SVGAParser.m 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. //
  2. // SVGAParser.m
  3. // SVGAPlayer
  4. //
  5. // Created by 崔明辉 on 16/6/17.
  6. // Copyright © 2016年 UED Center. All rights reserved.
  7. //
  8. #import "SVGAParser.h"
  9. #import "SVGAVideoEntity.h"
  10. #import "Svga.pbobjc.h"
  11. #import <zlib.h>
  12. #import <SSZipArchive/SSZipArchive.h>
  13. #import <CommonCrypto/CommonDigest.h>
  14. #define ZIP_MAGIC_NUMBER "PK"
  15. @interface SVGAParser ()
  16. @end
  17. @implementation SVGAParser
  18. static NSOperationQueue *parseQueue;
  19. static NSOperationQueue *unzipQueue;
  20. + (void)load {
  21. parseQueue = [NSOperationQueue new];
  22. parseQueue.maxConcurrentOperationCount = 8;
  23. unzipQueue = [NSOperationQueue new];
  24. unzipQueue.maxConcurrentOperationCount = 1;
  25. }
  26. - (void)parseWithURL:(nonnull NSURL *)URL
  27. completionBlock:(void ( ^ _Nonnull )(SVGAVideoEntity * _Nullable videoItem))completionBlock
  28. failureBlock:(void ( ^ _Nullable)(NSError * _Nullable error))failureBlock {
  29. [self parseWithURLRequest:[NSURLRequest requestWithURL:URL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:20.0]
  30. completionBlock:completionBlock
  31. failureBlock:failureBlock];
  32. }
  33. - (void)parseWithURLRequest:(NSURLRequest *)URLRequest completionBlock:(void (^)(SVGAVideoEntity * _Nullable))completionBlock failureBlock:(void (^)(NSError * _Nullable))failureBlock {
  34. if (URLRequest.URL == nil) {
  35. if (failureBlock) {
  36. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  37. failureBlock([NSError errorWithDomain:@"SVGAParser" code:411 userInfo:@{NSLocalizedDescriptionKey: @"URL cannot be nil."}]);
  38. }];
  39. }
  40. return;
  41. }
  42. NSString *cacheKeyMD5 = [self cacheKey:URLRequest.URL];
  43. if ([[NSFileManager defaultManager] fileExistsAtPath:[self cacheDirectory:cacheKeyMD5]]) {
  44. [self parseWithCacheKey:cacheKeyMD5 completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
  45. if (completionBlock) {
  46. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  47. completionBlock(videoItem);
  48. }];
  49. }
  50. } failureBlock:^(NSError * _Nonnull error) {
  51. [self clearCache:cacheKeyMD5];
  52. if (failureBlock) {
  53. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  54. failureBlock(error);
  55. }];
  56. }
  57. }];
  58. return;
  59. }
  60. if ([[NSFileManager defaultManager] fileExistsAtPath:[self SVGADataCacheFilePath:cacheKeyMD5]]) {
  61. [self parseLocalSVGADataWithCacheKey:cacheKeyMD5 completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
  62. if (completionBlock) {
  63. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  64. completionBlock(videoItem);
  65. }];
  66. }
  67. } failureBlock:^(NSError * _Nonnull error) {
  68. [self clearLocalSVGADataCache:cacheKeyMD5];
  69. if (failureBlock) {
  70. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  71. failureBlock(error);
  72. }];
  73. }
  74. }];
  75. return;
  76. }
  77. // 网络请求SVGAData
  78. __weak typeof(self) weakSelf = self;
  79. [[[NSURLSession sharedSession] dataTaskWithRequest:URLRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  80. if (error == nil && data != nil) {
  81. __strong typeof(weakSelf) strongSelf = weakSelf;
  82. [strongSelf parseWithSVGAData:data cacheKey:cacheKeyMD5 completionBlock:completionBlock failureBlock:failureBlock];
  83. [strongSelf saveToLocalWithSVGAData:data cacheKey:cacheKeyMD5];
  84. }
  85. else {
  86. if (failureBlock) {
  87. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  88. failureBlock(error);
  89. }];
  90. }
  91. }
  92. }] resume];
  93. }
  94. - (void)parseWithSVGAData:(NSData *)data cacheKey:(NSString *)cacheKey completionBlock:(void (^)(SVGAVideoEntity * _Nullable))completionBlock failureBlock:(void (^)(NSError * _Nullable))failureBlock {
  95. [self parseWithData:data cacheKey:cacheKey completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
  96. if (completionBlock) {
  97. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  98. completionBlock(videoItem);
  99. }];
  100. }
  101. } failureBlock:^(NSError * _Nonnull error) {
  102. [self clearCache:cacheKey];
  103. [self clearLocalSVGADataCache:cacheKey];
  104. if (failureBlock) {
  105. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  106. failureBlock(error);
  107. }];
  108. }
  109. }];
  110. }
  111. - (void)parseWithNamed:(NSString *)named
  112. inBundle:(NSBundle *)inBundle
  113. completionBlock:(void (^)(SVGAVideoEntity * _Nonnull))completionBlock
  114. failureBlock:(void (^)(NSError * _Nonnull))failureBlock {
  115. NSString *filePath = [(inBundle ?: [NSBundle mainBundle]) pathForResource:named ofType:@"svga"];
  116. if (filePath == nil) {
  117. if (failureBlock) {
  118. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  119. failureBlock([NSError errorWithDomain:@"SVGAParser" code:404 userInfo:@{NSLocalizedDescriptionKey: @"File not exist."}]);
  120. }];
  121. }
  122. return;
  123. }
  124. [self parseWithData:[NSData dataWithContentsOfFile:filePath]
  125. cacheKey:[self cacheKey:[NSURL fileURLWithPath:filePath]]
  126. completionBlock:completionBlock
  127. failureBlock:failureBlock];
  128. }
  129. - (void)parseWithCacheKey:(nonnull NSString *)cacheKey
  130. completionBlock:(void ( ^ _Nullable)(SVGAVideoEntity * _Nonnull videoItem))completionBlock
  131. failureBlock:(void ( ^ _Nullable)(NSError * _Nonnull error))failureBlock {
  132. [parseQueue addOperationWithBlock:^{
  133. SVGAVideoEntity *cacheItem = [SVGAVideoEntity readCache:cacheKey];
  134. if (cacheItem != nil) {
  135. if (completionBlock) {
  136. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  137. completionBlock(cacheItem);
  138. }];
  139. }
  140. return;
  141. }
  142. NSString *cacheDir = [self cacheDirectory:cacheKey];
  143. if ([[NSFileManager defaultManager] fileExistsAtPath:[cacheDir stringByAppendingString:@"/movie.binary"]]) {
  144. NSError *err;
  145. NSData *protoData = [NSData dataWithContentsOfFile:[cacheDir stringByAppendingString:@"/movie.binary"]];
  146. SVGAProtoMovieEntity *protoObject = [SVGAProtoMovieEntity parseFromData:protoData error:&err];
  147. if (!err && [protoObject isKindOfClass:[SVGAProtoMovieEntity class]]) {
  148. SVGAVideoEntity *videoItem = [[SVGAVideoEntity alloc] initWithProtoObject:protoObject cacheDir:cacheDir];
  149. [videoItem resetImagesWithProtoObject:protoObject];
  150. [videoItem resetSpritesWithProtoObject:protoObject];
  151. [videoItem resetAudiosWithProtoObject:protoObject];
  152. if (self.enabledMemoryCache) {
  153. [videoItem saveCache:cacheKey];
  154. } else {
  155. [videoItem saveWeakCache:cacheKey];
  156. }
  157. if (completionBlock) {
  158. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  159. completionBlock(videoItem);
  160. }];
  161. }
  162. }
  163. else {
  164. if (failureBlock) {
  165. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  166. failureBlock([NSError errorWithDomain:NSFilePathErrorKey code:-1 userInfo:nil]);
  167. }];
  168. }
  169. }
  170. }
  171. else {
  172. NSError *err;
  173. NSData *JSONData = [NSData dataWithContentsOfFile:[cacheDir stringByAppendingString:@"/movie.spec"]];
  174. if (JSONData != nil) {
  175. NSDictionary *JSONObject = [NSJSONSerialization JSONObjectWithData:JSONData options:kNilOptions error:&err];
  176. if ([JSONObject isKindOfClass:[NSDictionary class]]) {
  177. SVGAVideoEntity *videoItem = [[SVGAVideoEntity alloc] initWithJSONObject:JSONObject cacheDir:cacheDir];
  178. [videoItem resetImagesWithJSONObject:JSONObject];
  179. [videoItem resetSpritesWithJSONObject:JSONObject];
  180. if (self.enabledMemoryCache) {
  181. [videoItem saveCache:cacheKey];
  182. } else {
  183. [videoItem saveWeakCache:cacheKey];
  184. }
  185. if (completionBlock) {
  186. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  187. completionBlock(videoItem);
  188. }];
  189. }
  190. }
  191. }
  192. else {
  193. if (failureBlock) {
  194. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  195. failureBlock([NSError errorWithDomain:NSFilePathErrorKey code:-1 userInfo:nil]);
  196. }];
  197. }
  198. }
  199. }
  200. }];
  201. }
  202. - (void)clearCache:(nonnull NSString *)cacheKey {
  203. NSString *cacheDir = [self cacheDirectory:cacheKey];
  204. [[NSFileManager defaultManager] removeItemAtPath:cacheDir error:NULL];
  205. }
  206. + (BOOL)isZIPData:(NSData *)data {
  207. BOOL result = NO;
  208. if (!strncmp([data bytes], ZIP_MAGIC_NUMBER, strlen(ZIP_MAGIC_NUMBER))) {
  209. result = YES;
  210. }
  211. return result;
  212. }
  213. - (void)parseWithData:(nonnull NSData *)data
  214. cacheKey:(nonnull NSString *)cacheKey
  215. completionBlock:(void ( ^ _Nullable)(SVGAVideoEntity * _Nonnull videoItem))completionBlock
  216. failureBlock:(void ( ^ _Nullable)(NSError * _Nonnull error))failureBlock {
  217. SVGAVideoEntity *cacheItem = [SVGAVideoEntity readCache:cacheKey];
  218. if (cacheItem != nil) {
  219. if (completionBlock) {
  220. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  221. completionBlock(cacheItem);
  222. }];
  223. }
  224. return;
  225. }
  226. if (!data || data.length < 4) {
  227. return;
  228. }
  229. if (![SVGAParser isZIPData:data]) {
  230. // Maybe is SVGA 2.0.0
  231. [parseQueue addOperationWithBlock:^{
  232. NSData *inflateData = [self zlibInflate:data];
  233. NSError *err;
  234. SVGAProtoMovieEntity *protoObject = [SVGAProtoMovieEntity parseFromData:inflateData error:&err];
  235. if (!err && [protoObject isKindOfClass:[SVGAProtoMovieEntity class]]) {
  236. SVGAVideoEntity *videoItem = [[SVGAVideoEntity alloc] initWithProtoObject:protoObject cacheDir:@""];
  237. [videoItem resetImagesWithProtoObject:protoObject];
  238. [videoItem resetSpritesWithProtoObject:protoObject];
  239. [videoItem resetAudiosWithProtoObject:protoObject];
  240. if (self.enabledMemoryCache) {
  241. [videoItem saveCache:cacheKey];
  242. } else {
  243. [videoItem saveWeakCache:cacheKey];
  244. }
  245. if (completionBlock) {
  246. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  247. completionBlock(videoItem);
  248. }];
  249. }
  250. }
  251. }];
  252. return ;
  253. }
  254. [unzipQueue addOperationWithBlock:^{
  255. if ([[NSFileManager defaultManager] fileExistsAtPath:[self cacheDirectory:cacheKey]]) {
  256. [self parseWithCacheKey:cacheKey completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
  257. if (completionBlock) {
  258. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  259. completionBlock(videoItem);
  260. }];
  261. }
  262. } failureBlock:^(NSError * _Nonnull error) {
  263. [self clearCache:cacheKey];
  264. [self clearLocalSVGADataCache:cacheKey];
  265. if (failureBlock) {
  266. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  267. failureBlock(error);
  268. }];
  269. }
  270. }];
  271. return;
  272. }
  273. NSString *tmpPath = [NSTemporaryDirectory() stringByAppendingFormat:@"%u.svga", arc4random()];
  274. if (data != nil) {
  275. [data writeToFile:tmpPath atomically:YES];
  276. NSString *cacheDir = [self cacheDirectory:cacheKey];
  277. if ([cacheDir isKindOfClass:[NSString class]]) {
  278. [[NSFileManager defaultManager] createDirectoryAtPath:cacheDir withIntermediateDirectories:NO attributes:nil error:nil];
  279. [SSZipArchive unzipFileAtPath:tmpPath toDestination:[self cacheDirectory:cacheKey] progressHandler:^(NSString * _Nonnull entry, unz_file_info zipInfo, long entryNumber, long total) {
  280. } completionHandler:^(NSString *path, BOOL succeeded, NSError *error) {
  281. if (error != nil) {
  282. if (failureBlock) {
  283. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  284. failureBlock(error);
  285. }];
  286. }
  287. }
  288. else {
  289. if ([[NSFileManager defaultManager] fileExistsAtPath:[cacheDir stringByAppendingString:@"/movie.binary"]]) {
  290. NSError *err;
  291. NSData *protoData = [NSData dataWithContentsOfFile:[cacheDir stringByAppendingString:@"/movie.binary"]];
  292. SVGAProtoMovieEntity *protoObject = [SVGAProtoMovieEntity parseFromData:protoData error:&err];
  293. if (!err) {
  294. SVGAVideoEntity *videoItem = [[SVGAVideoEntity alloc] initWithProtoObject:protoObject cacheDir:cacheDir];
  295. [videoItem resetImagesWithProtoObject:protoObject];
  296. [videoItem resetSpritesWithProtoObject:protoObject];
  297. if (self.enabledMemoryCache) {
  298. [videoItem saveCache:cacheKey];
  299. } else {
  300. [videoItem saveWeakCache:cacheKey];
  301. }
  302. if (completionBlock) {
  303. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  304. completionBlock(videoItem);
  305. }];
  306. }
  307. }
  308. else {
  309. if (failureBlock) {
  310. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  311. failureBlock([NSError errorWithDomain:NSFilePathErrorKey code:-1 userInfo:nil]);
  312. }];
  313. }
  314. }
  315. }
  316. else {
  317. NSError *err;
  318. NSData *JSONData = [NSData dataWithContentsOfFile:[cacheDir stringByAppendingString:@"/movie.spec"]];
  319. if (JSONData != nil) {
  320. NSDictionary *JSONObject = [NSJSONSerialization JSONObjectWithData:JSONData options:kNilOptions error:&err];
  321. if ([JSONObject isKindOfClass:[NSDictionary class]]) {
  322. SVGAVideoEntity *videoItem = [[SVGAVideoEntity alloc] initWithJSONObject:JSONObject cacheDir:cacheDir];
  323. [videoItem resetImagesWithJSONObject:JSONObject];
  324. [videoItem resetSpritesWithJSONObject:JSONObject];
  325. if (self.enabledMemoryCache) {
  326. [videoItem saveCache:cacheKey];
  327. } else {
  328. [videoItem saveWeakCache:cacheKey];
  329. }
  330. if (completionBlock) {
  331. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  332. completionBlock(videoItem);
  333. }];
  334. }
  335. }
  336. }
  337. else {
  338. if (failureBlock) {
  339. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  340. failureBlock([NSError errorWithDomain:NSFilePathErrorKey code:-1 userInfo:nil]);
  341. }];
  342. }
  343. }
  344. }
  345. }
  346. }];
  347. }
  348. else {
  349. if (failureBlock) {
  350. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  351. failureBlock([NSError errorWithDomain:NSFilePathErrorKey code:-1 userInfo:nil]);
  352. }];
  353. }
  354. }
  355. }
  356. else {
  357. if (failureBlock) {
  358. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  359. failureBlock([NSError errorWithDomain:@"Data Error" code:-1 userInfo:nil]);
  360. }];
  361. }
  362. }
  363. }];
  364. }
  365. - (nonnull NSString *)cacheKey:(NSURL *)URL {
  366. return [self MD5String:URL.absoluteString];
  367. }
  368. - (nullable NSString *)cacheDirectory:(NSString *)cacheKey {
  369. NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
  370. return [cacheDir stringByAppendingFormat:@"/%@", cacheKey];
  371. }
  372. - (NSString *)MD5String:(NSString *)str {
  373. const char *cstr = [str UTF8String];
  374. unsigned char result[16];
  375. CC_MD5(cstr, (CC_LONG)strlen(cstr), result);
  376. return [NSString stringWithFormat:
  377. @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
  378. result[0], result[1], result[2], result[3],
  379. result[4], result[5], result[6], result[7],
  380. result[8], result[9], result[10], result[11],
  381. result[12], result[13], result[14], result[15]
  382. ];
  383. }
  384. - (NSData *)zlibInflate:(NSData *)data
  385. {
  386. if ([data length] == 0) return data;
  387. unsigned full_length = (unsigned)[data length];
  388. unsigned half_length = (unsigned)[data length] / 2;
  389. NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
  390. BOOL done = NO;
  391. int status;
  392. z_stream strm;
  393. strm.next_in = (Bytef *)[data bytes];
  394. strm.avail_in = (unsigned)[data length];
  395. strm.total_out = 0;
  396. strm.zalloc = Z_NULL;
  397. strm.zfree = Z_NULL;
  398. if (inflateInit (&strm) != Z_OK) return nil;
  399. while (!done)
  400. {
  401. // Make sure we have enough room and reset the lengths.
  402. if (strm.total_out >= [decompressed length])
  403. [decompressed increaseLengthBy: half_length];
  404. strm.next_out = [decompressed mutableBytes] + strm.total_out;
  405. strm.avail_out = (uInt)([decompressed length] - strm.total_out);
  406. // Inflate another chunk.
  407. status = inflate (&strm, Z_SYNC_FLUSH);
  408. if (status == Z_STREAM_END) done = YES;
  409. else if (status != Z_OK) break;
  410. }
  411. if (inflateEnd (&strm) != Z_OK) return nil;
  412. // Set real length.
  413. if (done)
  414. {
  415. [decompressed setLength: strm.total_out];
  416. return [NSData dataWithData: decompressed];
  417. }
  418. else return nil;
  419. }
  420. #pragma mark - Customer 方法
  421. - (void)parseLocalSVGADataWithCacheKey:(nonnull NSString *)cacheKey
  422. completionBlock:(void ( ^ _Nullable)(SVGAVideoEntity * _Nonnull videoItem))completionBlock
  423. failureBlock:(void ( ^ _Nullable)(NSError * _Nonnull error))failureBlock {
  424. SVGAVideoEntity *cacheItem = [SVGAVideoEntity readCache:cacheKey];
  425. if (cacheItem != nil) {
  426. if (completionBlock) {
  427. [[NSOperationQueue mainQueue] addOperationWithBlock:^{
  428. completionBlock(cacheItem);
  429. }];
  430. }
  431. return;
  432. }
  433. // 读取本地SVGAData缓存
  434. NSData *data = [self readLocalSVGADataWithCacheKey:cacheKey];
  435. if (data != nil) {
  436. [self parseWithSVGAData:data cacheKey:cacheKey completionBlock:completionBlock failureBlock:failureBlock];
  437. return;
  438. }
  439. }
  440. - (nullable NSString *)SVGADataCacheFilePath:(NSString *)cacheKey {
  441. NSString *SVGADataCacheDir = [self SVGADataCacheDirectory];
  442. if (![[NSFileManager defaultManager] fileExistsAtPath: SVGADataCacheDir]) {
  443. [[NSFileManager defaultManager] createDirectoryAtPath:SVGADataCacheDir withIntermediateDirectories:NO attributes:nil error:nil];
  444. }
  445. return [SVGADataCacheDir stringByAppendingFormat:@"/%@", cacheKey];
  446. }
  447. - (nullable NSString *)SVGADataCacheDirectory {
  448. return [[self diskCacheDirectory] stringByAppendingFormat:@"/SVGA_data_cache"];
  449. }
  450. - (nullable NSString *)diskCacheDirectory {
  451. return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];;
  452. }
  453. /** 保存二进制SVGAData到本地
  454. *
  455. */
  456. - (void)saveToLocalWithSVGAData:(NSData *)data cacheKey:(NSString *)cacheKey {
  457. if (![[NSFileManager defaultManager] fileExistsAtPath:[self SVGADataCacheFilePath:cacheKey]]) {
  458. [data writeToFile:[self SVGADataCacheFilePath:cacheKey] atomically:true];
  459. }
  460. }
  461. /** 读取本地二进制 SVGAData
  462. *
  463. */
  464. - (NSData *)readLocalSVGADataWithCacheKey:(NSString *)cacheKey{
  465. if ([[NSFileManager defaultManager] fileExistsAtPath:[self SVGADataCacheFilePath:cacheKey]]) {
  466. return [NSData dataWithContentsOfFile:[self SVGADataCacheFilePath:cacheKey]];
  467. }
  468. return nil;
  469. }
  470. - (void)clearLocalSVGADataCache:(nonnull NSString *)cacheKey {
  471. NSString *cacheDir = [self SVGADataCacheFilePath:cacheKey];
  472. [[NSFileManager defaultManager] removeItemAtPath:cacheDir error:NULL];
  473. }
  474. - (void)clearLocalSVGADataCacheWithURLString:(nonnull NSString *)URLString {
  475. NSString *cacheDir = [self SVGADataCacheFilePath:[self MD5String:URLString]];
  476. NSError *error = nil;
  477. [[NSFileManager defaultManager] removeItemAtPath:cacheDir error:&error];
  478. }
  479. /** 下载SVGAData
  480. *
  481. */
  482. - (void)downloadSVGADataWithURLString:(NSString *)URLString {
  483. [parseQueue addOperationWithBlock:^{
  484. NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:URLString]];
  485. NSString *cacheKeyMD5 = [self MD5String:URLString];
  486. // 读取本地SVGAData缓存
  487. NSData *data = [self readLocalSVGADataWithCacheKey:cacheKeyMD5];
  488. if (data == nil) {
  489. [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  490. if (error == nil && data != nil) {
  491. [self saveToLocalWithSVGAData:data cacheKey:cacheKeyMD5];
  492. }
  493. }] resume];
  494. }
  495. }];
  496. }
  497. @end