Commit eaf290ea cgx

优化白噪音(无缝播放、KTVHTTPCache)

1 个父辈 93cfbaff
...@@ -2003,9 +2003,9 @@ ...@@ -2003,9 +2003,9 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D0B5ECB627F2D9E0003EDFE3 /* main.m */, D0B5ECB627F2D9E0003EDFE3 /* main.m */,
D0B5ECAD27F2D9DE003EDFE3 /* Main.storyboard */,
D0B5ECA427F2D9DE003EDFE3 /* AppDelegate.h */, D0B5ECA427F2D9DE003EDFE3 /* AppDelegate.h */,
D0B5ECA527F2D9DE003EDFE3 /* AppDelegate.m */, D0B5ECA527F2D9DE003EDFE3 /* AppDelegate.m */,
D0B5ECAD27F2D9DE003EDFE3 /* Main.storyboard */,
D0930F102801124E006B497A /* BaseNaviController.h */, D0930F102801124E006B497A /* BaseNaviController.h */,
D0930F112801124E006B497A /* BaseNaviController.m */, D0930F112801124E006B497A /* BaseNaviController.m */,
D04B3DA927F6EEB40022F8DF /* DSTabBarController.h */, D04B3DA927F6EEB40022F8DF /* DSTabBarController.h */,
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
// //
#import "DsCacheUtils.h" #import "DsCacheUtils.h"
#import <KTVHTTPCache/KTVHTTPCache.h>
@implementation DsCacheUtils @implementation DsCacheUtils
...@@ -26,11 +27,16 @@ ...@@ -26,11 +27,16 @@
// size = size + [[SDImageCache sharedImageCache] totalDiskSize]; // size = size + [[SDImageCache sharedImageCache] totalDiskSize];
} }
// YYImage缓存
YYImageCache *cache = [YYWebImageManager sharedManager].cache; YYImageCache *cache = [YYWebImageManager sharedManager].cache;
NSInteger discCache = cache.diskCache.totalCost; NSInteger discCache = cache.diskCache.totalCost;
NSInteger memoryCache = cache.memoryCache.totalCost; NSInteger memoryCache = cache.memoryCache.totalCost;
size = size + (discCache + memoryCache); size = size + (discCache + memoryCache);
// 音频缓存
NSInteger audioCacheSize = [KTVHTTPCache cacheTotalCacheLength];
size += audioCacheSize;
if (size < 0) { return @"0.0M"; } if (size < 0) { return @"0.0M"; }
double returnSize = size / 1024.0 / 1024.0; double returnSize = size / 1024.0 / 1024.0;
return [NSString stringWithFormat:@"%.1fM", returnSize]; return [NSString stringWithFormat:@"%.1fM", returnSize];
...@@ -69,6 +75,9 @@ ...@@ -69,6 +75,9 @@
// } // }
// }]; // }];
} }
// 清除音频缓存
[KTVHTTPCache cacheDeleteAllCaches];
} }
@end @end
...@@ -6,61 +6,36 @@ ...@@ -6,61 +6,36 @@
// //
#import "NoisePlayItem.h" #import "NoisePlayItem.h"
#import <AVFoundation/AVFoundation.h>
#import "NoisePlayerManager.h" #import "NoisePlayerManager.h"
#import <AVFoundation/AVFoundation.h>
/*
播放器当前播放时刻距离完成时刻的时间间隔
即:需要开启循环播放器的时刻
*/
#define NEED_LOOP_PLAY_TIME 1.0
/*
播放器当前播放时刻距离完成时刻的时间间隔
即:需要停止播放器的时刻
*/
#define NEED_STOP_PLAY_TIME .5
@interface NoisePlayItem () @interface NoisePlayItem ()
/// 系统播放器 /// 系统播放器
@property (nonatomic, strong) AVPlayer *player; @property (nonatomic, strong) AVPlayer *player;
/// 无缝循环播放辅助播放器 /// 无缝循环播放辅助播放器
@property (nonatomic, strong) AVPlayer *loopPlayer; @property (nonatomic, strong) AVPlayer *loopPlayer;
/// 当前保存的音频播放器
@property (nonatomic, strong) NSMutableArray *allPlayers;
@end @end
@implementation NoisePlayItem { @implementation NoisePlayItem
id _timeObserve;
id _timeLoopObserve;
}
- (instancetype)initWithUrl:(NSString *)url volume:(float)volume {
if (self = [super init]) {
self.url = url;
self.volume = volume;
}
return self;
}
- (NSArray *)allPlayers {
if (!_allPlayers) {
_allPlayers = [NSMutableArray array];
}
return _allPlayers;
}
- (void)setVolume:(float)volume {
_volume = volume;
self.player.volume = volume;
}
#pragma mark - pubilc
- (void)play { - (void)play {
if (self.isSeamlessLoopPlayback) { if (self.isSeamlessLoopPlayback) {
if (self.allPlayers.count == 0) {
if (self.player.timeControlStatus != AVPlayerTimeControlStatusPlaying) { if (self.player.timeControlStatus != AVPlayerTimeControlStatusPlaying) {
[self.player play]; if (self.player.currentItem.error) {
} [self initPlayer];
return;
} }
for (AVPlayer *player in self.allPlayers) {
if (player.timeControlStatus != AVPlayerTimeControlStatusPlaying) {
[player play];
}
}
}
if (self.isLoopPlayback) {
if (self.player.timeControlStatus != AVPlayerTimeControlStatusPlaying) {
[self.player play]; [self.player play];
} }
} }
...@@ -68,49 +43,43 @@ ...@@ -68,49 +43,43 @@
- (void)pause { - (void)pause {
if (self.isSeamlessLoopPlayback) { if (self.isSeamlessLoopPlayback) {
for (AVPlayer *player in self.allPlayers) {
if (player.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[player pause];
}
}
}
if (self.isLoopPlayback) {
if (self.player.timeControlStatus == AVPlayerTimeControlStatusPlaying) { if (self.player.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[self.player pause]; [self.player pause];
} }
if (self.loopPlayer.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[self.loopPlayer pause];
}
} }
} }
- (void)stop { - (void)stop {
if (self.isSeamlessLoopPlayback) { if (self.isSeamlessLoopPlayback) {
for (__strong AVPlayer *player in self.allPlayers) {
if (player.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[player pause];
[player seekToTime:CMTimeMake(0, 1)];
if (player == _player) {
[player removeTimeObserver:_timeObserve];
_timeObserve = nil;
_player = nil;
} else if (player == _loopPlayer) {
[_loopPlayer removeTimeObserver:_timeLoopObserve];
_timeLoopObserve = nil;
_loopPlayer = nil;
}
}
}
[self.allPlayers removeAllObjects];
}
if (self.isLoopPlayback) {
if (self.player.timeControlStatus == AVPlayerTimeControlStatusPlaying) { if (self.player.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[self.player pause]; [self.player pause];
[self.player seekToTime:CMTimeMake(0, 1)]; [self.player seekToTime:CMTimeMake(0, 1)];
[_player.currentItem removeObserver:self forKeyPath:@"status" context:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
_player = nil;
}
if (self.loopPlayer.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[self.loopPlayer pause];
[self.loopPlayer seekToTime:CMTimeMake(0, 1)];
[_loopPlayer.currentItem removeObserver:self forKeyPath:@"status" context:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:_loopPlayer.currentItem];
_loopPlayer = nil;
} }
} }
} }
- (void)setVolume:(float)volume {
_volume = volume;
self.player.volume = volume;
self.loopPlayer.volume = volume;
}
#pragma mark - observe
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
AVPlayerItem *item = object;
if ([keyPath isEqualToString:@"status"]) { if ([keyPath isEqualToString:@"status"]) {
AVPlayerStatus status = [[change objectForKey:@"new"] intValue]; AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
if (status == AVPlayerStatusReadyToPlay) { if (status == AVPlayerStatusReadyToPlay) {
...@@ -118,125 +87,89 @@ ...@@ -118,125 +87,89 @@
[NoisePlayerManager sharedNoisePlayerManager].isPlaying = self.isPlaying; [NoisePlayerManager sharedNoisePlayerManager].isPlaying = self.isPlaying;
} else if (status == AVPlayerStatusFailed) { } else if (status == AVPlayerStatusFailed) {
self.isPlaying = NO; self.isPlaying = NO;
DSLog(@"AVPlayerStatusFailed"); NSError *error = item.error;
if (error) {
DSLog(@"AVPlayerStatusFailed:%@", item.error);
[DSProgressHUD showToast:error.localizedDescription];
}
} else { } else {
self.isPlaying = NO; self.isPlaying = NO;
DSLog(@"AVPlayerStatusUnknown"); DSLog(@"AVPlayerStatusUnknown");
} }
} else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
DSLog(@"loadedTimeRanges:%@", change);
} }
} }
- (void)playbackFinished:(NSNotification *)notification { - (void)playbackFinished:(NSNotification *)notification {
DSLog(@"音频播放完成通知:%@", notification.object); DSLog(@"白噪音播放完成:%@", notification.object);
AVPlayerItem *playerItem = [notification object];
if (self.isSeamlessLoopPlayback) {
if (playerItem == _player.currentItem) {
if ([self.allPlayers containsObject:_player]) {
[self.allPlayers removeObject:_player];
}
[_player removeTimeObserver:_timeObserve];
_timeObserve = nil;
_player = nil;
} else if (playerItem == _loopPlayer.currentItem) {
if ([self.allPlayers containsObject:_loopPlayer]) {
[self.allPlayers removeObject:_loopPlayer];
}
[_loopPlayer removeTimeObserver:_timeLoopObserve];
_timeLoopObserve = nil;
_loopPlayer = nil;
}
}
if (self.isLoopPlayback) {
if (self.isLoopPlayback) {
[playerItem seekToTime:kCMTimeZero completionHandler:nil];
[self.player play];
}
}
} }
- (void)dealloc { #pragma mark - 初始化
if (_player) { - (instancetype)initWithUrl:(NSString *)url volume:(float)volume {
[_player.currentItem removeObserver:self forKeyPath:@"status" context:nil]; if (self = [super init]) {
[_player.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges" context:nil]; self.url = url;
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem]; self.volume = volume;
} [self initPlayer];
if (_loopPlayer) { [self initLoopPlayer];
[_loopPlayer.currentItem removeObserver:self forKeyPath:@"status" context:nil];
[_loopPlayer.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges" context:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:_loopPlayer.currentItem];
} }
return self;
} }
#pragma mark - lazy - (void)initPlayer {
- (AVPlayer *)player { self.player = [self getPlayer];
if (!_player) {
_player = [[AVPlayer alloc] initWithURL:[NSURL URLWithString:self.url]];
_player.volume = self.volume;
if (![self.allPlayers containsObject:_player]) {
[self.allPlayers addObject:_player];
}
[_player.currentItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
[_player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:(NSKeyValueObservingOptionNew) context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
WS(weakSelf); WS(weakSelf);
_timeObserve = [_player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) { [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float current = CMTimeGetSeconds(time); float current = CMTimeGetSeconds(time);
float total = CMTimeGetSeconds(weakSelf.player.currentItem.duration); float duration = CMTimeGetSeconds(weakSelf.player.currentItem.duration);
// 即将播放完成后,继续播放该音乐
if (current >= total - .5) { if (current >= duration - NEED_LOOP_PLAY_TIME) {
[weakSelf.loopPlayer play]; if (weakSelf.loopPlayer) { [weakSelf.loopPlayer play]; }
}
if (current >= duration - NEED_STOP_PLAY_TIME) {
[weakSelf.player seekToTime:kCMTimeZero completionHandler:^(BOOL finished) {
if (finished) {
[weakSelf.player pause];
[weakSelf.player seekToTime:kCMTimeZero];
} }
}]; }];
} }
return _player; }];
} }
- (AVPlayer *)loopPlayer { - (void)initLoopPlayer {
if (!_loopPlayer) { self.loopPlayer = [self getPlayer];
_loopPlayer = [[AVPlayer alloc] initWithURL:[NSURL URLWithString:self.url]];
_loopPlayer.volume = self.volume;
if (![self.allPlayers containsObject:_loopPlayer]) {
[self.allPlayers addObject:_loopPlayer];
}
[_loopPlayer.currentItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
[_loopPlayer.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:(NSKeyValueObservingOptionNew) context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:_loopPlayer.currentItem];
WS(weakSelf); WS(weakSelf);
_timeLoopObserve = [_loopPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) { [self.loopPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float current = CMTimeGetSeconds(time); float current = CMTimeGetSeconds(time);
float total = CMTimeGetSeconds(weakSelf.loopPlayer.currentItem.duration); float duration = CMTimeGetSeconds(weakSelf.loopPlayer.currentItem.duration);
// 即将播放完成后,继续播放该音乐
if (current >= total - .5) { if (current >= duration - NEED_LOOP_PLAY_TIME) {
[weakSelf.player play]; if (weakSelf.player) { [weakSelf.player play]; }
if (![weakSelf.allPlayers containsObject:weakSelf.player]) {
[weakSelf.allPlayers addObject:weakSelf.player];
} }
if (current >= duration - NEED_STOP_PLAY_TIME) {
[weakSelf.loopPlayer seekToTime:kCMTimeZero completionHandler:^(BOOL finished) {
if (finished) {
[weakSelf.loopPlayer pause];
[weakSelf.loopPlayer seekToTime:kCMTimeZero];
} }
}]; }];
} }
return _loopPlayer; }];
} }
#pragma mark - others - (AVPlayer *)getPlayer {
- (void)resetMusicPlayer { NSString *remoteStr = [self.url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
if (self.player) { NSURL *localURL = [KTVHTTPCache proxyURLWithOriginalURL:[NSURL URLWithString:remoteStr]];
[self.player removeTimeObserver:_timeObserve];
_timeObserve = nil;
}
self.player = nil;
}
- (void)resetMusicLoopPlayer { AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:localURL];
if (self.loopPlayer) { [playerItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
[self.loopPlayer removeTimeObserver:_timeLoopObserve]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
_timeLoopObserve = nil;
} AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
self.loopPlayer = nil; player.volume = self.volume;
return player;
} }
@end @end
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "NoisePlayItem.h" #import "NoisePlayItem.h"
#import <KTVHTTPCache/KTVHTTPCache.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
......
...@@ -15,6 +15,32 @@ ...@@ -15,6 +15,32 @@
@implementation NoisePlayerManager @implementation NoisePlayerManager
SingletonM(NoisePlayerManager) SingletonM(NoisePlayerManager)
- (instancetype)init {
if (self = [super init]) {
[self setupHTTPCache];
}
return self;
}
- (void)setupHTTPCache {
[KTVHTTPCache logSetConsoleLogEnable:NO];
NSError *error = nil;
[KTVHTTPCache proxyStart:&error];
if (error) {
DSLog(@"Proxy Start Failure, %@", error);
} else {
DSLog(@"Proxy Start Success");
}
[KTVHTTPCache encodeSetURLConverter:^NSURL *(NSURL *URL) {
DSLog(@"URL Filter reviced URL : %@", URL);
return URL;
}];
[KTVHTTPCache downloadSetUnacceptableContentTypeDisposer:^BOOL(NSURL *URL, NSString *contentType) {
DSLog(@"Unsupport Content-Type Filter reviced URL : %@, %@", URL, contentType);
return NO;
}];
}
#pragma mark - setter/getter #pragma mark - setter/getter
- (void)setIsPlaying:(BOOL)isPlaying { - (void)setIsPlaying:(BOOL)isPlaying {
_isPlaying = isPlaying; _isPlaying = isPlaying;
...@@ -71,7 +97,9 @@ SingletonM(NoisePlayerManager) ...@@ -71,7 +97,9 @@ SingletonM(NoisePlayerManager)
BOOL isPlaying = NO; BOOL isPlaying = NO;
for (NoisePlayItem *item in self.playItemList) { for (NoisePlayItem *item in self.playItemList) {
// 该状态存在不及时 // 该状态存在不及时
isPlaying = item.isPlaying; if (item.isPlaying) {
isPlaying = YES;
}
[item play]; [item play];
} }
self.isPlaying = isPlaying; self.isPlaying = isPlaying;
......
...@@ -14,6 +14,7 @@ target 'DreamSleep' do ...@@ -14,6 +14,7 @@ target 'DreamSleep' do
pod 'YYModel', '~> 1.0.4' pod 'YYModel', '~> 1.0.4'
pod 'FreeStreamer', '~> 4.0.0' pod 'FreeStreamer', '~> 4.0.0'
pod 'IQKeyboardManager', '~> 6.5.10' pod 'IQKeyboardManager', '~> 6.5.10'
pod 'KTVHTTPCache', '~> 2.0.1'
end end
# AFNetworking (4.0.1) # AFNetworking (4.0.1)
...@@ -31,3 +32,4 @@ end ...@@ -31,3 +32,4 @@ end
# FreeStreamer(4.0.0) # FreeStreamer(4.0.0)
# IQKeyboardManager(6.5.10) # IQKeyboardManager(6.5.10)
# JJException(0.2.12) # JJException(0.2.12)
# KTVHTTPCache(2.0.1)
...@@ -14,6 +14,7 @@ PODS: ...@@ -14,6 +14,7 @@ PODS:
- AFNetworking/Serialization (4.0.1) - AFNetworking/Serialization (4.0.1)
- AFNetworking/UIKit (4.0.1): - AFNetworking/UIKit (4.0.1):
- AFNetworking/NSURLSession - AFNetworking/NSURLSession
- CocoaAsyncSocket (7.6.5)
- DKNightVersion (2.4.3): - DKNightVersion (2.4.3):
- DKNightVersion/Core (= 2.4.3) - DKNightVersion/Core (= 2.4.3)
- DKNightVersion/CoreAnimation (= 2.4.3) - DKNightVersion/CoreAnimation (= 2.4.3)
...@@ -31,6 +32,10 @@ PODS: ...@@ -31,6 +32,10 @@ PODS:
- FreeStreamer (4.0.0): - FreeStreamer (4.0.0):
- Reachability (~> 3.0) - Reachability (~> 3.0)
- IQKeyboardManager (6.5.10) - IQKeyboardManager (6.5.10)
- KTVCocoaHTTPServer (1.0.0):
- CocoaAsyncSocket
- KTVHTTPCache (2.0.1):
- KTVCocoaHTTPServer
- lottie-ios (2.5.3) - lottie-ios (2.5.3)
- Masonry (1.1.0) - Masonry (1.1.0)
- MBProgressHUD (1.2.0) - MBProgressHUD (1.2.0)
...@@ -53,6 +58,7 @@ DEPENDENCIES: ...@@ -53,6 +58,7 @@ DEPENDENCIES:
- DOUAudioStreamer (~> 0.2.16) - DOUAudioStreamer (~> 0.2.16)
- FreeStreamer (~> 4.0.0) - FreeStreamer (~> 4.0.0)
- IQKeyboardManager (~> 6.5.10) - IQKeyboardManager (~> 6.5.10)
- KTVHTTPCache (~> 2.0.1)
- lottie-ios (~> 2.5.3) - lottie-ios (~> 2.5.3)
- Masonry (~> 1.1.0) - Masonry (~> 1.1.0)
- MBProgressHUD (~> 1.2.0) - MBProgressHUD (~> 1.2.0)
...@@ -64,10 +70,13 @@ DEPENDENCIES: ...@@ -64,10 +70,13 @@ DEPENDENCIES:
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- AFNetworking - AFNetworking
- CocoaAsyncSocket
- DKNightVersion - DKNightVersion
- DOUAudioStreamer - DOUAudioStreamer
- FreeStreamer - FreeStreamer
- IQKeyboardManager - IQKeyboardManager
- KTVCocoaHTTPServer
- KTVHTTPCache
- lottie-ios - lottie-ios
- Masonry - Masonry
- MBProgressHUD - MBProgressHUD
...@@ -80,10 +89,13 @@ SPEC REPOS: ...@@ -80,10 +89,13 @@ SPEC REPOS:
SPEC CHECKSUMS: SPEC CHECKSUMS:
AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DKNightVersion: eaa80cc4014b4bae7d4b535fd87ecc6a3c2767b3 DKNightVersion: eaa80cc4014b4bae7d4b535fd87ecc6a3c2767b3
DOUAudioStreamer: c503ba2ecb9a54ff7bda0eff66963ad224f3c7dc DOUAudioStreamer: c503ba2ecb9a54ff7bda0eff66963ad224f3c7dc
FreeStreamer: 7e9c976045701ac2f7e9c14c17245203c37bf2ea FreeStreamer: 7e9c976045701ac2f7e9c14c17245203c37bf2ea
IQKeyboardManager: 45a1fa55c1a5b02c61ac0fd7fd5b62bb4ad20d97 IQKeyboardManager: 45a1fa55c1a5b02c61ac0fd7fd5b62bb4ad20d97
KTVCocoaHTTPServer: df8d7b861e603ff8037e9b2138aca2563a6b768d
KTVHTTPCache: 588c3eb16f6bd1e6fde1e230dabfb7bd4e490a4d
lottie-ios: a50d5c0160425cd4b01b852bb9578963e6d92d31 lottie-ios: a50d5c0160425cd4b01b852bb9578963e6d92d31
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201 Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
MBProgressHUD: 3ee5efcc380f6a79a7cc9b363dd669c5e1ae7406 MBProgressHUD: 3ee5efcc380f6a79a7cc9b363dd669c5e1ae7406
...@@ -94,6 +106,6 @@ SPEC CHECKSUMS: ...@@ -94,6 +106,6 @@ SPEC CHECKSUMS:
YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30 YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
YYWebImage: 5f7f36aee2ae293f016d418c7d6ba05c4863e928 YYWebImage: 5f7f36aee2ae293f016d418c7d6ba05c4863e928
PODFILE CHECKSUM: e4359ec13a52ba4e49c7d0c1466b596eceaf7b77 PODFILE CHECKSUM: b808024d124d43764129a7c9916691de21d3b921
COCOAPODS: 1.11.3 COCOAPODS: 1.11.3
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!