Files
ASHReactNative/Sources/Impl/ASHRNBundleManagerImpl.m
2017-04-10 17:56:27 +08:00

171 lines
6.1 KiB
Objective-C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// ASHRNBundleManagerImpl.m
// ASHReactNative
//
// Created by xmfish on 17/4/7.
// Copyright © 2017年 ash. All rights reserved.
//
#import "ASHRNBundleManagerImpl.h"
#import <ZipArchive.h>
#import <AFNetworking.h>
#import "ASHDownFileUtil.h"
@interface ASHRNBundleManagerImpl()
@property (nonatomic, copy) NSString *dirPath;
@property (nonatomic, strong) NSMutableDictionary *callbackMaps;
@end
@implementation ASHRNBundleManagerImpl
- (instancetype)init
{
self = [super init];
if (self) {
self.callbackMaps = [NSMutableDictionary dictionary];
}
return self;
}
- (NSString *)dirPath
{
if (!_dirPath) {
_dirPath = [self createRNBundleDirectory];
}
return _dirPath;
}
- (NSString *)createRNBundleDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *dirPath = [paths.firstObject stringByAppendingPathComponent:@"RNView"];
BOOL isDir = NO;
BOOL isCreated = [[NSFileManager defaultManager] fileExistsAtPath:dirPath isDirectory:&isDir];
if (!isCreated || !isDir) {
NSError *error = nil;
BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:&error];
if (!success)
{
NSAssert(NO, @"create dir error: %@", error.localizedDescription);
return nil;
}
}
return dirPath;
}
- (NSString *)bundlePathWithURLString:(NSString *)urlString
{
if (!urlString.length) {
return nil;
}
NSString *lastPathComponent = [urlString componentsSeparatedByString:@"?"].firstObject.lastPathComponent.stringByDeletingPathExtension;
NSString* zipPath = [urlString componentsSeparatedByString:@"?"].firstObject;
NSString *fileName = [NSString stringWithFormat:@"%ld_%@",zipPath.hash,lastPathComponent];
NSString *bundlePath = [self.dirPath stringByAppendingPathComponent:fileName];
return bundlePath;
}
- (BOOL)containBundleURL:(NSURL *)bundleURL
{
NSString *bundlePath = [self bundlePathWithURLString:bundleURL.absoluteString];
if (bundlePath) {
BOOL isDir = NO;
BOOL hasExists = [[NSFileManager defaultManager] fileExistsAtPath:bundlePath isDirectory:&isDir];
return (hasExists && isDir);
}
else {
return NO;
}
}
- (void)downloadWithBundleURL:(NSURL *)bundleURL completedBlock:(nullable void (^)(NSString *, NSString *, NSError * _Nullable))completedBlock
{
NSString *urlString = bundleURL.absoluteString;
if (!urlString.length) {
NSError* error = [NSError errorWithDomain:@"bundle包地址不能为空" code:0 userInfo:nil];
if (completedBlock) {
completedBlock(nil, nil, error);
}
// NSAssert(NO, @"bundleURL is nil!!!");
return;
}
//文件夹地址
NSString *bundlePath = [self bundlePathWithURLString:urlString];
//index文件地址
NSString *indexPath = [bundlePath stringByAppendingPathComponent:@"index.ios.bundle"];
BOOL isDir = NO;
BOOL hasExists = [[NSFileManager defaultManager] fileExistsAtPath:bundlePath isDirectory:&isDir];
BOOL hasIndexFile = [[NSFileManager defaultManager] fileExistsAtPath:indexPath];
if (hasExists && isDir && hasIndexFile) {
if (completedBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
completedBlock(indexPath, bundlePath, nil);
});
}
}
else {
@synchronized (self) {
NSMutableArray *callbackBlocks = self.callbackMaps[urlString];
if (!callbackBlocks) {
callbackBlocks = [NSMutableArray array];
self.callbackMaps[urlString] = callbackBlocks;
}
if (completedBlock) {
[callbackBlocks addObject:[completedBlock copy]];
}
}
NSString *zipPath = [bundlePath stringByAppendingPathExtension:@"zip"];
[ASHDownFileUtil downLoadWithUrl:urlString filePath:zipPath completedBlock:^(NSString * _Nonnull url, NSString * _Nonnull filePath) {
NSError *error = nil;
do{
BOOL isUnzip = [self unzipFilePath:zipPath];
if (!isUnzip) {
error = [NSError errorWithDomain:[NSString stringWithFormat:@"文件解压 %@ 失败!", zipPath] code:0 userInfo:nil];
break;
}
BOOL hasIndexFile = [[NSFileManager defaultManager] fileExistsAtPath:indexPath];
if (!hasIndexFile) {
error = [NSError errorWithDomain:[NSString stringWithFormat:@"未找到 index.ios.bundle 文件,%@ ", indexPath] code:0 userInfo:nil];
break;
}
}while (0);
[self callbackWithBundleURLString:urlString indexPath:indexPath bundlePath:bundlePath error:error];
} failBlock:^(NSString * _Nonnull url, NSError * _Nonnull error) {
[self callbackWithBundleURLString:urlString indexPath:indexPath bundlePath:bundlePath error:error];
}];
}
}
- (void)callbackWithBundleURLString:(NSString *)urlString indexPath:(NSString *)indexPath bundlePath:(NSString *)bundlePath error:(NSError *)error
{
NSMutableArray *callbackBlocks = nil;
@synchronized (self) {
callbackBlocks = self.callbackMaps[urlString];
}
dispatch_async(dispatch_get_main_queue(), ^{
void (^completedBlock)(NSString *indexPath, NSString *bundlePath, NSError *error) = nil;
for (completedBlock in callbackBlocks) {
completedBlock(indexPath, bundlePath, error);
}
});
}
- (BOOL)unzipFilePath:(NSString *)zipPath
{
NSString *dirPath = [zipPath stringByDeletingPathExtension];
ZipArchive* unzipArchive = [[ZipArchive alloc] initWithFileManager:[NSFileManager defaultManager]];
[unzipArchive UnzipOpenFile:zipPath];
BOOL isOK = [unzipArchive UnzipFileTo:dirPath overWrite:YES];
[unzipArchive UnzipCloseFile];
if (isOK) {
[[NSFileManager defaultManager] removeItemAtPath:zipPath error:nil];
}
return isOK;
}
@end