├── .gitignore ├── CCCandyWebCache.podspec ├── CCDemo ├── CCDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── CCDemo.xcworkspace │ └── contents.xcworkspacedata ├── CCDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── have-css-have-js.imageset │ │ │ ├── Contents.json │ │ │ └── have-css-have-js.png │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── CheckAndUpdate.h │ ├── CheckAndUpdate.m │ ├── CheckAndUpdateController.h │ ├── CheckAndUpdateController.m │ ├── Info.plist │ ├── PerformanceController.h │ ├── PerformanceController.m │ ├── ViewController.h │ ├── ViewController.m │ ├── WebAppCleanController.h │ ├── WebAppCleanController.m │ ├── WebViewProtocolController.h │ ├── WebViewProtocolController.m │ └── main.m ├── CCDemoTests │ ├── CCCacheManagerDBTests.m │ ├── CCCacheManagerTest.m │ ├── CCDemoTests.m │ ├── CCMD5EncryptTest.m │ ├── CCThreadSafeDictionaryTest.m │ ├── CCVersionCheckerTests.m │ ├── CCWebViewWarmuperTests.m │ └── Info.plist ├── Podfile └── Pods │ ├── Headers │ ├── Private │ │ ├── CCCandyWebCache │ │ │ ├── CCBackgroundQueue.h │ │ │ ├── CCCacheManager+DB.h │ │ │ ├── CCCacheManager+Download.h │ │ │ ├── CCCacheManager.h │ │ │ ├── CCCandyWebCache.h │ │ │ ├── CCLogger.h │ │ │ ├── CCResourceIndexInfo.h │ │ │ ├── CCThreadSafeMutableDictionary.h │ │ │ ├── CCValidationChecker.h │ │ │ ├── CCWebAppInfo.h │ │ │ ├── CCWebViewProtocol.h │ │ │ ├── HTDBManager.h │ │ │ ├── HTFDLogger.h │ │ │ ├── HTFDThreadSafeMutableDictionary.h │ │ │ ├── HTFileDownloadTask.h │ │ │ ├── HTFileDownloader+MD5.h │ │ │ ├── HTFileDownloader+Private.h │ │ │ ├── HTFileDownloader.h │ │ │ ├── HTFileTransferConst.h │ │ │ ├── HTFileTransferItem.h │ │ │ ├── HTResourceVersionChecker.h │ │ │ ├── HTResourceVersionInfo.h │ │ │ ├── HTThreadSafeMutableDictionary.h │ │ │ ├── NSDate+NSDateRFC1123.h │ │ │ ├── NSString+Encrypt.h │ │ │ ├── NSString+MD5Encrypt.h │ │ │ ├── NSString+Path.h │ │ │ ├── bsdiff.h │ │ │ ├── bspatch.h │ │ │ ├── bzlib.h │ │ │ ├── bzlib_private.h │ │ │ └── config.h │ │ └── ZipArchive │ │ │ ├── ZipArchive.h │ │ │ ├── crypt.h │ │ │ ├── ioapi.h │ │ │ ├── mztools.h │ │ │ ├── unzip.h │ │ │ └── zip.h │ └── Public │ │ ├── CCCandyWebCache │ │ ├── CCBackgroundQueue.h │ │ ├── CCCacheManager+DB.h │ │ ├── CCCacheManager+Download.h │ │ ├── CCCacheManager.h │ │ ├── CCCandyWebCache.h │ │ ├── CCLogger.h │ │ ├── CCResourceIndexInfo.h │ │ ├── CCThreadSafeMutableDictionary.h │ │ ├── CCValidationChecker.h │ │ ├── CCWebAppInfo.h │ │ ├── CCWebViewProtocol.h │ │ ├── HTDBManager.h │ │ ├── HTFDLogger.h │ │ ├── HTFDThreadSafeMutableDictionary.h │ │ ├── HTFileDownloadTask.h │ │ ├── HTFileDownloader+MD5.h │ │ ├── HTFileDownloader+Private.h │ │ ├── HTFileDownloader.h │ │ ├── HTFileTransferConst.h │ │ ├── HTFileTransferItem.h │ │ ├── HTResourceVersionChecker.h │ │ ├── HTResourceVersionInfo.h │ │ ├── HTThreadSafeMutableDictionary.h │ │ ├── NSDate+NSDateRFC1123.h │ │ ├── NSString+Encrypt.h │ │ ├── NSString+MD5Encrypt.h │ │ ├── NSString+Path.h │ │ ├── bsdiff.h │ │ ├── bspatch.h │ │ ├── bzlib.h │ │ ├── bzlib_private.h │ │ └── config.h │ │ └── ZipArchive │ │ └── ZipArchive.h │ ├── Local Podspecs │ └── CCCandyWebCache.podspec.json │ ├── Pods.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── CCCandyWebCache.xcscheme │ ├── Target Support Files │ ├── CCCandyWebCache │ │ ├── CCCandyWebCache-Private.xcconfig │ │ ├── CCCandyWebCache-dummy.m │ │ ├── CCCandyWebCache-prefix.pch │ │ └── CCCandyWebCache.xcconfig │ ├── Pods-CCDemo │ │ ├── Pods-CCDemo-acknowledgements.markdown │ │ ├── Pods-CCDemo-acknowledgements.plist │ │ ├── Pods-CCDemo-dummy.m │ │ ├── Pods-CCDemo-resources.sh │ │ ├── Pods-CCDemo.debug.xcconfig │ │ └── Pods-CCDemo.release.xcconfig │ └── ZipArchive │ │ ├── ZipArchive-Private.xcconfig │ │ ├── ZipArchive-dummy.m │ │ ├── ZipArchive-prefix.pch │ │ └── ZipArchive.xcconfig │ └── ZipArchive │ ├── LICENSE │ ├── README.md │ ├── ZipArchive.h │ ├── ZipArchive.m │ └── minizip │ ├── crypt.h │ ├── ioapi.c │ ├── ioapi.h │ ├── mztools.c │ ├── mztools.h │ ├── unzip.c │ ├── unzip.h │ ├── zip.c │ └── zip.h ├── CC_build_script.py ├── LICENSE.txt ├── readme.md └── src ├── CCCandyWebCache ├── CCCandyWebCache.h ├── CCCandyWebCache.m ├── CC_build_script_sample.py ├── CacheManager │ ├── CCCacheManager+DB.h │ ├── CCCacheManager+DB.m │ ├── CCCacheManager+Download.h │ ├── CCCacheManager+Download.m │ ├── CCCacheManager.h │ ├── CCCacheManager.m │ ├── CCResourceIndexInfo.h │ ├── CCResourceIndexInfo.m │ ├── CCValidationChecker.h │ ├── CCValidationChecker.m │ ├── CCWebAppInfo.h │ └── CCWebAppInfo.m ├── Utils │ ├── CCBackgroundQueue.h │ ├── CCBackgroundQueue.m │ ├── CCLogger.h │ ├── CCLogger.m │ ├── CCThreadSafeMutableDictionary.h │ ├── CCThreadSafeMutableDictionary.m │ ├── NSDate+NSDateRFC1123.h │ ├── NSDate+NSDateRFC1123.m │ ├── NSString+Encrypt.h │ ├── NSString+Encrypt.m │ ├── NSString+MD5Encrypt.h │ ├── NSString+MD5Encrypt.m │ ├── NSString+Path.h │ └── NSString+Path.m └── WebViewProtocol │ ├── CCWebViewProtocol.h │ └── CCWebViewProtocol.m ├── HTFileDownloader ├── HTDBManager.h ├── HTDBManager.m ├── HTFDLogger.h ├── HTFDLogger.m ├── HTFDThreadSafeMutableDictionary.h ├── HTFDThreadSafeMutableDictionary.m ├── HTFileDownloadTask.h ├── HTFileDownloadTask.m ├── HTFileDownloader+MD5.h ├── HTFileDownloader+MD5.m ├── HTFileDownloader+Private.h ├── HTFileDownloader.h ├── HTFileDownloader.m ├── HTFileTransferConst.h ├── HTFileTransferItem.h └── HTFileTransferItem.m ├── VersionChecker ├── HTResourceVersionChecker.h ├── HTResourceVersionChecker.m ├── HTResourceVersionInfo.h ├── HTResourceVersionInfo.m ├── HTThreadSafeMutableDictionary.h └── HTThreadSafeMutableDictionary.m └── bsdiff ├── bsdiff ├── bsdiff.c ├── bsdiff.h ├── bspatch.c ├── bspatch.h └── config.h └── bzip2 ├── blocksort.c ├── bzlib.c ├── bzlib.h ├── bzlib_private.h ├── compress.c ├── crctable.c ├── decompress.c ├── huffman.c └── randtable.c /CCCandyWebCache.podspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # 3 | # Be sure to run `pod spec lint HTUI.podspec' to ensure this is a 4 | # valid spec and to remove all comments including this before submitting the spec. 5 | # 6 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 7 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 8 | # 9 | 10 | Pod::Spec.new do |s| 11 | 12 | 13 | s.name = "CCCandyWebCache" 14 | s.version = "0.0.1" 15 | s.summary = "iOS资源缓存解决方案" 16 | 17 | s.description = <<-DESC 18 | iOS资源缓存解决方案. 19 | DESC 20 | 21 | s.homepage = "https://g.hz.netease.com/web-cache/CCCandyWebCache-ios" 22 | 23 | s.license = "MIT" 24 | 25 | s.source = { :git => 'https://g.hz.netease.com/web-cache/CCCandyWebCache-ios.git' } 26 | 27 | s.platform = :ios, "7.0" 28 | 29 | s.ios.deployment_target = "7.0" 30 | 31 | s.library = 'sqlite3' 32 | 33 | s.source_files = "src/CCCandyWebCache/*.{h,m}","src/CCCandyWebCache/CacheManager/*.{h,m}","src/CCCandyWebCache/WebViewProtocol/*.{h,m}","src/CCCandyWebCache/Utils/*.{h,m}","src/CCCandyWebCache/CC_build_script_sample.py","src/bsdiff/bsdiff/*.{h,c}","src/bsdiff/bzip2/*.{h,c}","src/bsdiff/bzip2/*.{h,c}","src/HTFileDownloader/*.{h,m}","src/VersionChecker/*.{h,m}" 34 | 35 | s.requires_arc = true 36 | end 37 | -------------------------------------------------------------------------------- /CCDemo/CCDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CCDemo/CCDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // CCDemo 4 | // 5 | // Created by jw on 6/3/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | @property (strong, nonatomic) UIWindow *window; 13 | 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // CCDemo 4 | // 5 | // Created by jw on 6/3/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | // Override point for customization after application launch. 21 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 22 | ViewController * viewController = [[ViewController alloc] init]; 23 | UINavigationController *naviController = [[UINavigationController alloc] initWithRootViewController: 24 | viewController]; 25 | [naviController.navigationBar.topItem setTitle:@"CandyWebCache Test"]; 26 | self.window.rootViewController = naviController; 27 | [self.window makeKeyAndVisible]; 28 | return YES; 29 | } 30 | 31 | - (void)applicationWillResignActive:(UIApplication *)application { 32 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 33 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 34 | } 35 | 36 | - (void)applicationDidEnterBackground:(UIApplication *)application { 37 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 38 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 39 | } 40 | 41 | - (void)applicationWillEnterForeground:(UIApplication *)application { 42 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 43 | } 44 | 45 | - (void)applicationDidBecomeActive:(UIApplication *)application { 46 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 47 | } 48 | 49 | - (void)applicationWillTerminate:(UIApplication *)application { 50 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /CCDemo/CCDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /CCDemo/CCDemo/Assets.xcassets/have-css-have-js.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "have-css-have-js.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CCDemo/CCDemo/Assets.xcassets/have-css-have-js.imageset/have-css-have-js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-ios/145c5eee88a9363674246f80160f61d1485e69ef/CCDemo/CCDemo/Assets.xcassets/have-css-have-js.imageset/have-css-have-js.png -------------------------------------------------------------------------------- /CCDemo/CCDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/CheckAndUpdate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CheckAndUpdate.h 3 | // CCDemo 4 | // 5 | // Created by jw on 6/22/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CheckAndUpdate : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/CheckAndUpdate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CheckAndUpdate.m 3 | // CCDemo 4 | // 5 | // Created by jw on 6/22/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import "CheckAndUpdate.h" 10 | 11 | @implementation CheckAndUpdate 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/CheckAndUpdateController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CheckAndUpdateController.h 3 | // CCDemo 4 | // 5 | // Created by jw on 6/22/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CheckAndUpdateController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/CheckAndUpdateController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CheckAndUpdateController.m 3 | // CCDemo 4 | // 5 | // Created by jw on 6/22/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import "CheckAndUpdateController.h" 10 | #import "CCCandyWebCache.h" 11 | 12 | @interface CheckAndUpdateController () 13 | @property (nonatomic, strong) UIButton* button; 14 | @end 15 | 16 | @implementation CheckAndUpdateController 17 | 18 | 19 | - (void)viewDidLoad 20 | { 21 | [super viewDidLoad]; 22 | self.view.backgroundColor = [UIColor whiteColor]; 23 | _button = [[UIButton alloc]init]; 24 | [self.view addSubview:_button]; 25 | [_button setTitle:@"检测更新" forState:UIControlStateNormal]; 26 | _button.backgroundColor = [UIColor blueColor]; 27 | [_button addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside]; 28 | } 29 | 30 | - (void)viewWillLayoutSubviews 31 | { 32 | [super viewWillLayoutSubviews]; 33 | _button.frame = CGRectMake(100, 120, 200, 40); 34 | } 35 | 36 | - (void)buttonClick 37 | { 38 | [[CCCandyWebCache defaultWebCache]checkAndUpdateResource]; 39 | 40 | } 41 | 42 | 43 | - (void)viewDidAppear:(BOOL)animated 44 | { 45 | [super viewDidAppear:animated]; 46 | [[CCCandyWebCache defaultWebCache] addObserver:self]; 47 | } 48 | 49 | - (void)viewDidDisappear:(BOOL)animated 50 | { 51 | [super viewDidDisappear:animated]; 52 | [[CCCandyWebCache defaultWebCache] removeObserver:self]; 53 | } 54 | 55 | #pragma mark -- CCWebAppUpdateDelegate 56 | - (BOOL)CCCacheManager:(CCCacheManager*)manager shouldUpdateWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info 57 | { 58 | return YES; 59 | } 60 | 61 | - (void)CCCacheManager:(CCCacheManager*)manager willStartDownloadWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info 62 | { 63 | NSLog(@"CCCandyWebCache:开始更新资源,更新之前信息如下:"); 64 | NSLog(@"%@",[CCCandyWebCache defaultWebCache]); 65 | } 66 | 67 | - (void)CCCacheManager:(CCCacheManager*)manager didStartDownloadWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info 68 | { 69 | 70 | } 71 | 72 | - (void)CCCacheManager:(CCCacheManager*)manager updatingWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info 73 | { 74 | 75 | } 76 | 77 | - (void)CCCacheManager:(CCCacheManager*)manager didFinishDownloadWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info 78 | { 79 | 80 | } 81 | 82 | - (void)CCCacheManager:(CCCacheManager*)manager didUpdateWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info 83 | { 84 | NSLog(@"CCCandyWebCache:完成更新资源,更新之后信息如下:"); 85 | NSLog(@"%@",[CCCandyWebCache defaultWebCache]); 86 | } 87 | 88 | - (void)CCCacheManager:(CCCacheManager*)manager failedUpdateWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info error:(CCWebAppUpdateError)error 89 | { 90 | switch (error) { 91 | case CCWebAppUpdateErrorDownload: 92 | NSLog(@"CCCandyWebCache:下载失败"); 93 | break; 94 | case CCWebAppUpdateErrorDiffMerge: 95 | NSLog(@"CCCandyWebCache:增量包merge失败"); 96 | break; 97 | case CCWebAppUpdateErrorNotValid: 98 | NSLog(@"CCCandyWebCache:下载资源md5校验"); 99 | break; 100 | case CCWebAppUpdateErrorUnzip: 101 | NSLog(@"CCCandyWebCache:下载文件解压失败"); 102 | break; 103 | case CCWebAppUpdateErrorLocalAppNotExist: 104 | NSLog(@"CCCandyWebCache:本地资源不存在"); 105 | break; 106 | 107 | default: 108 | NSLog(@"CCCandyWebCache:反正失败了"); 109 | break; 110 | } 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppTransportSecurity 6 | 7 | NSExceptionDomains 8 | 9 | NSAllowsArbitraryLoads 10 | 11 | 12 | LSApplicationCategoryType 13 | 14 | CFBundleDevelopmentRegion 15 | en 16 | CFBundleExecutable 17 | $(EXECUTABLE_NAME) 18 | CFBundleIdentifier 19 | $(PRODUCT_BUNDLE_IDENTIFIER) 20 | CFBundleInfoDictionaryVersion 21 | 6.0 22 | CFBundleName 23 | $(PRODUCT_NAME) 24 | CFBundlePackageType 25 | APPL 26 | CFBundleShortVersionString 27 | 1.0 28 | CFBundleSignature 29 | ???? 30 | CFBundleVersion 31 | 1 32 | LSRequiresIPhoneOS 33 | 34 | UILaunchStoryboardName 35 | LaunchScreen 36 | UIMainStoryboardFile 37 | Main 38 | UIRequiredDeviceCapabilities 39 | 40 | armv7 41 | 42 | UISupportedInterfaceOrientations 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/PerformanceController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PerformanceController.h 3 | // CCDemo 4 | // 5 | // Created by jw on 7/5/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PerformanceController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/PerformanceController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PerformanceController.m 3 | // CCDemo 4 | // 5 | // Created by jw on 7/5/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import "PerformanceController.h" 10 | #import "CCCandyWebCache.h" 11 | 12 | @interface PerformanceController () 13 | @property (nonatomic,strong) UIButton* urlMatchTestButton; 14 | @property (nonatomic,strong) UIButton* threadSafeTestButton; 15 | @end 16 | 17 | @implementation PerformanceController 18 | 19 | - (void)viewDidLoad 20 | { 21 | [super viewDidLoad]; 22 | self.view.backgroundColor = [UIColor whiteColor]; 23 | _urlMatchTestButton = [[UIButton alloc]init]; 24 | [self.view addSubview:_urlMatchTestButton]; 25 | [_urlMatchTestButton setTitle:@"url匹配性能测试" forState:UIControlStateNormal]; 26 | _urlMatchTestButton.backgroundColor = [UIColor blueColor]; 27 | [_urlMatchTestButton addTarget:self action:@selector(urlMatchTest) forControlEvents:UIControlEventTouchUpInside]; 28 | 29 | 30 | 31 | _threadSafeTestButton = [[UIButton alloc]init]; 32 | [self.view addSubview:_threadSafeTestButton]; 33 | [_threadSafeTestButton setTitle:@"url匹配线程安全测试" forState:UIControlStateNormal]; 34 | _threadSafeTestButton.backgroundColor = [UIColor blueColor]; 35 | [_threadSafeTestButton addTarget:self action:@selector(threadSafeTest) forControlEvents:UIControlEventTouchUpInside]; 36 | 37 | } 38 | 39 | - (void)viewWillLayoutSubviews 40 | { 41 | [super viewWillLayoutSubviews]; 42 | _urlMatchTestButton.frame = CGRectMake(100, 120, 200, 40); 43 | 44 | _threadSafeTestButton.frame = CGRectMake(100, 200, 200, 40); 45 | } 46 | 47 | 48 | - (void)urlMatchTest 49 | { 50 | CCCacheManager* manager = [CCCandyWebCache defaultWebCache].cacheManager; 51 | NSInteger testCount = 1000; 52 | NSUInteger startMilSec = [[NSDate date] timeIntervalSince1970] * 1000 * 1000; 53 | for (int i =0; i < testCount; i++) { 54 | // [manager dataForURL:[NSString stringWithFormat:@"http://www.kaola.com/r/javascript/core-v%d.0.js",i]]; 55 | [manager dataForURL:[NSString stringWithFormat:@"http://m.kaola.com/r/core_c2e5aa4f2d71d82b7cb95d5aaed3cc6c.js"]]; 56 | } 57 | NSUInteger costMilSec = [[NSDate date] timeIntervalSince1970] * 1000 * 1000 - startMilSec; 58 | NSUInteger averageMilSec = costMilSec/testCount; 59 | NSLog(@"平均每次url匹配耗时:%@微秒",@(averageMilSec)); 60 | } 61 | 62 | - (void)threadSafeTest 63 | { 64 | NSInteger testCount = 1000; 65 | 66 | dispatch_queue_t q1 = dispatch_queue_create(@"threadSafeTest1".UTF8String, DISPATCH_QUEUE_SERIAL); 67 | dispatch_queue_t q2 = dispatch_queue_create(@"threadSafeTest2".UTF8String, DISPATCH_QUEUE_SERIAL); 68 | dispatch_queue_t q3 = dispatch_queue_create(@"threadSafeTest3".UTF8String, DISPATCH_QUEUE_SERIAL); 69 | CCCacheManager* manager = [CCCandyWebCache defaultWebCache].cacheManager; 70 | for (int i =0; i< testCount; i++) { 71 | dispatch_async(q1, ^{ 72 | [manager dataForURL:[NSString stringWithFormat:@"http://www.kaola.com/webapp/pub/app.html"]]; 73 | }); 74 | dispatch_async(q2, ^{ 75 | [manager dataForURL:[NSString stringWithFormat:@"http://www.kaola.com/webapp/pub/app.html"]]; 76 | }); 77 | dispatch_async(q3, ^{ 78 | [manager dataForURL:[NSString stringWithFormat:@"http://www.kaola.com/webapp/pub/app.html"]]; 79 | }); 80 | } 81 | 82 | 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // CCDemo 4 | // 5 | // Created by jw on 6/3/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | @property (weak, nonatomic) IBOutlet UIWebView *webView; 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // CCDemo 4 | // 5 | // Created by jw on 6/3/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "CCCacheManager.h" 11 | #import "CCWebViewProtocol.h" 12 | #import "HTFileDownloader+MD5.h" 13 | #import "CCCandyWebCache.h" 14 | #import "CheckAndUpdateController.h" 15 | #import "WebViewProtocolController.h" 16 | #import "WebAppCleanController.h" 17 | #import "PerformanceController.h" 18 | 19 | @interface ViewController () 20 | @property (nonatomic,strong) CCCacheManager* ccm; 21 | @property (nonatomic,strong) CCCandyWebCache* webcache; 22 | @property (nonatomic,strong) UITableView* tableView; 23 | @property (nonatomic,copy) NSArray* testVCs; 24 | @property (nonatomic,copy) NSArray* testNames; 25 | @end 26 | 27 | @implementation ViewController 28 | 29 | -(id)createWebView{ 30 | return [[UIWebView alloc]initWithFrame:CGRectMake(0,0,320,560)]; 31 | } 32 | 33 | - (void)viewDidLoad { 34 | [super viewDidLoad]; 35 | _tableView = [UITableView new]; 36 | [self.view addSubview:_tableView]; 37 | _tableView.delegate = self; 38 | _tableView.dataSource = self; 39 | 40 | _testNames = @[@"检测更新", 41 | @"资源拦截", 42 | @"资源清理", 43 | @"性能测试"]; 44 | _testVCs = @[CheckAndUpdateController.class, 45 | WebViewProtocolController.class, 46 | WebAppCleanController.class, 47 | PerformanceController.class 48 | ]; 49 | 50 | CCCandyWebCacheConfig* config = [CCCandyWebCacheConfig new]; 51 | 52 | // config.serverAddress = @"10.242.27.37:9001"; 53 | // config.appName = @"KaoLa"; 54 | config.serverAddress = @"127.0.0.1:8080"; 55 | config.appName = @"kaola"; 56 | config.appVersion = @"1.0.1"; 57 | config.blackListResourceTypes = @[@"html"]; 58 | [CCCandyWebCache setDefaultConfiguration:config]; 59 | 60 | [CCCandyWebCache setLogEnable:YES]; 61 | [CCCandyWebCache setLogLevel:CCLoggerLevelVerbose]; 62 | 63 | [CCCandyWebCache defaultWebCache].enable = YES; 64 | [CCCandyWebCache defaultWebCache].diffEnable = YES; 65 | [[CCCandyWebCache defaultWebCache] checkAndUpdateResource]; 66 | 67 | } 68 | 69 | - (void)didReceiveMemoryWarning { 70 | [super didReceiveMemoryWarning]; 71 | // Dispose of any resources that can be recreated. 72 | 73 | } 74 | 75 | - (void)viewWillLayoutSubviews 76 | { 77 | [super viewWillLayoutSubviews]; 78 | _tableView.frame = self.view.bounds; 79 | } 80 | 81 | #pragma mark -- UITableViewDelegate 82 | #pragma mark -- UITableViewDataSource 83 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 84 | { 85 | return _testVCs.count; 86 | } 87 | 88 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 89 | { 90 | return 1; 91 | } 92 | 93 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 94 | { 95 | UIViewController* vc = [[_testVCs objectAtIndex:indexPath.row] new]; 96 | vc.title = _testNames[indexPath.row]; 97 | [self.navigationController pushViewController:vc animated:YES]; 98 | } 99 | 100 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 101 | { 102 | UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"]; 103 | if (!cell) { 104 | cell = [UITableViewCell new]; 105 | // RGB 106 | UIColor *randomRGBColor = [[UIColor alloc] initWithRed:arc4random()%256/256.0 107 | green:arc4random()%256/256.0 108 | blue:arc4random()%256/256.0 109 | alpha:0.3]; 110 | cell.backgroundColor = randomRGBColor; 111 | } 112 | cell.textLabel.text = _testNames[indexPath.row]; 113 | return cell; 114 | 115 | } 116 | 117 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 118 | { 119 | return 80; 120 | } 121 | //#pragma mark - webViewProtocol 测试 122 | //-(void) testWebViewProtocol{ 123 | // 124 | // NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]; 125 | // 126 | // [self.webView loadRequest:request]; 127 | // self.webView.delegate = self; 128 | // 129 | // self.webView.scalesPageToFit = YES; 130 | // 131 | //} 132 | // 133 | //- (NSString *)filePathWithUrlString:(NSString *)urlString { 134 | // 135 | // NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 136 | // NSString *fileName = [urlString MD5]; 137 | // return [cachesPath stringByAppendingPathComponent:fileName]; 138 | //} 139 | // 140 | //-(NSData *)CCWebViewProtocol:(CCWebViewProtocol *)protocol dataForURL:(NSURL *)requestURL{ 141 | // 142 | // NSData * data = [NSData dataWithContentsOfFile:[self filePathWithUrlString:requestURL.absoluteString]]; 143 | // 144 | // return data; 145 | //} 146 | // 147 | //#pragma mark - webViewWarmup 测试 148 | //-(void) webViewDidStartLoad:(UIWebView *)webView{ 149 | // 150 | // NSLog(@"Webview did started, %ld", (long)[[NSDate date] timeIntervalSince1970]); 151 | //} 152 | // 153 | //-(void) webViewDidFinishLoad:(UIWebView *)webView{ 154 | // NSLog(@"Webview did finished, %ld", (long)[[NSDate date] timeIntervalSince1970]); 155 | //} 156 | 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/WebAppCleanController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WebAppCleanController.h 3 | // CCDemo 4 | // 5 | // Created by jw on 6/29/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WebAppCleanController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/WebAppCleanController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WebAppCleanController.m 3 | // CCDemo 4 | // 5 | // Created by jw on 6/29/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import "WebAppCleanController.h" 10 | #import "CCCandyWebCache.h" 11 | 12 | @interface WebAppCleanController () 13 | @property (nonatomic,strong) UITableView* tableView; 14 | @property (nonatomic,copy) NSMutableArray* webappInfos; 15 | @end 16 | @implementation WebAppCleanController 17 | 18 | - (void)viewDidLoad 19 | { 20 | [super viewDidLoad]; 21 | self.view.backgroundColor = [UIColor whiteColor]; 22 | _tableView = [[UITableView alloc]init]; 23 | [self.view addSubview:_tableView]; 24 | _tableView.delegate = self; 25 | _tableView.dataSource = self; 26 | _webappInfos = [[CCCandyWebCache defaultWebCache].cacheManager allWebAppInfos].mutableCopy; 27 | 28 | } 29 | 30 | - (void)viewWillLayoutSubviews 31 | { 32 | _tableView.frame = self.view.bounds; 33 | } 34 | 35 | 36 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 37 | { 38 | return 1; 39 | } 40 | 41 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 42 | { 43 | return _webappInfos.count + 1; 44 | } 45 | 46 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 47 | { 48 | UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"tableviewcell"]; 49 | if (!cell) { 50 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"tableviewcell"]; 51 | UIColor *randomRGBColor = [[UIColor alloc] initWithRed:arc4random()%256/256.0 52 | green:arc4random()%256/256.0 53 | blue:arc4random()%256/256.0 54 | alpha:0.3]; 55 | cell.backgroundColor = randomRGBColor; 56 | } 57 | if (indexPath.row == 0) { 58 | cell.textLabel.text = @"清除所有webapp"; 59 | cell.detailTextLabel.text = [NSString stringWithFormat:@"%@字节",@([[CCCandyWebCache defaultWebCache].cacheManager diskSizeOfWebApps])]; 60 | }else{ 61 | cell.textLabel.text = [NSString stringWithFormat:@"webapp:%@",_webappInfos[indexPath.row - 1].name]; 62 | cell.detailTextLabel.text = [NSString stringWithFormat:@"%@字节",@(_webappInfos[indexPath.row - 1].diskSize)]; 63 | } 64 | return cell; 65 | } 66 | 67 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 68 | { 69 | if (indexPath.row == 0) { 70 | [[CCCandyWebCache defaultWebCache].cacheManager clearCacheOfWebApps]; 71 | _webappInfos = @[].mutableCopy; 72 | }else{ 73 | [[CCCandyWebCache defaultWebCache].cacheManager clearCacheOfWebAppWithName:_webappInfos[indexPath.row - 1].name]; 74 | [_webappInfos removeObjectAtIndex:indexPath.row - 1]; 75 | } 76 | [_tableView reloadData]; 77 | } 78 | 79 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 80 | { 81 | return 80; 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/WebViewProtocolController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewProtocolController.h 3 | // CCDemo 4 | // 5 | // Created by jw on 6/22/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WebViewProtocolController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/WebViewProtocolController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewProtocolController.m 3 | // CCDemo 4 | // 5 | // Created by jw on 6/22/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import "WebViewProtocolController.h" 10 | #import "CCCandyWebCache.h" 11 | 12 | @interface WebViewProtocolController () 13 | @property (nonatomic,strong) UITextField* urlInput; 14 | @property (nonatomic,strong) UIButton* loadURLButton; 15 | @property (nonatomic,strong) UIButton* logButton; 16 | @property (nonatomic,strong) UIWebView* webview; 17 | @end 18 | 19 | @implementation WebViewProtocolController 20 | 21 | - (void)viewDidLoad 22 | { 23 | [super viewDidLoad]; 24 | self.view.backgroundColor = [UIColor whiteColor]; 25 | _urlInput = [UITextField new]; 26 | [self.view addSubview:_urlInput]; 27 | _urlInput.backgroundColor = [UIColor grayColor]; 28 | // _urlInput.text = @"http://www.kaola.com/webapp/pub/app.html"; 29 | _urlInput.text = @"http://www.kaola.com/webapp/res/image/loading.gif"; 30 | 31 | _loadURLButton = [[UIButton alloc]init]; 32 | [self.view addSubview:_loadURLButton]; 33 | [_loadURLButton setTitle:@"加载url" forState:UIControlStateNormal]; 34 | [_loadURLButton addTarget:self action:@selector(loadURLButtonClick) forControlEvents:UIControlEventTouchUpInside]; 35 | _loadURLButton.backgroundColor = [UIColor blueColor]; 36 | 37 | _logButton = [[UIButton alloc]init]; 38 | [self.view addSubview:_logButton]; 39 | [_logButton setTitle:@"打印缓存信息" forState:UIControlStateNormal]; 40 | [_logButton addTarget:self action:@selector(logButtonClick) forControlEvents:UIControlEventTouchUpInside]; 41 | _logButton.backgroundColor = [UIColor blueColor]; 42 | 43 | 44 | _webview = [UIWebView new]; 45 | [self.view addSubview:_webview]; 46 | _webview.delegate = self; 47 | _webview.backgroundColor = [UIColor grayColor]; 48 | 49 | 50 | } 51 | 52 | - (void)viewWillLayoutSubviews 53 | { 54 | _urlInput.frame = CGRectMake(0, 100, self.view.bounds.size.width, 30); 55 | 56 | _loadURLButton.frame = CGRectMake(20, 140, 100, 30); 57 | _logButton.frame = CGRectMake(150, 140, 150, 30); 58 | 59 | _webview.frame = CGRectMake(0, CGRectGetMaxY(_logButton.frame)+10, self.view.bounds.size.width, self.view.bounds.size.height - (CGRectGetMaxY(_logButton.frame)+10)); 60 | } 61 | 62 | - (void)loadURLButtonClick 63 | { 64 | NSString* url = _urlInput.text; 65 | NSURLRequest* request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:url]]; 66 | [_webview loadRequest:request]; 67 | } 68 | 69 | - (void)logButtonClick 70 | { 71 | NSLog(@"%@",[CCCandyWebCache defaultWebCache]); 72 | } 73 | 74 | #pragma mark -- UIWebViewDelegate 75 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 76 | { 77 | return YES; 78 | } 79 | - (void)webViewDidStartLoad:(UIWebView *)webView 80 | { 81 | NSLog(@"Webview did start, %ld", (long)[[NSDate date] timeIntervalSince1970]); 82 | } 83 | - (void)webViewDidFinishLoad:(UIWebView *)webView 84 | { 85 | NSLog(@"Webview did end, %ld", (long)[[NSDate date] timeIntervalSince1970]); 86 | } 87 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error 88 | { 89 | 90 | } 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /CCDemo/CCDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CCDemo 4 | // 5 | // Created by jw on 6/3/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /CCDemo/CCDemoTests/CCCacheManagerDBTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCCacheManagerDBTests.m 3 | // CCDemo 4 | // 5 | // Created by jw on 6/14/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CCWebAppInfo.h" 11 | #import "CCResourceIndexInfo.h" 12 | #import "CCCacheManager.h" 13 | #import "CCCacheManager+DB.h" 14 | 15 | @interface CCCacheManagerDBTests : XCTestCase 16 | 17 | @end 18 | 19 | @implementation CCCacheManagerDBTests 20 | 21 | - (void)setUp { 22 | [super setUp]; 23 | // Put setup code here. This method is called before the invocation of each test method in the class. 24 | } 25 | 26 | - (void)tearDown { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | [super tearDown]; 29 | } 30 | 31 | - (void)testExample { 32 | // This is an example of a functional test case. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | - (void)testPerformanceExample { 37 | // This is an example of a performance test case. 38 | [self measureBlock:^{ 39 | // Put the code you want to measure the time of here. 40 | }]; 41 | } 42 | 43 | //for test 44 | - (void)testDatabase 45 | { 46 | NSMutableDictionary* webappInfos; 47 | NSMutableDictionary* resourceIndexInfos; 48 | webappInfos = [[NSMutableDictionary alloc]init]; 49 | resourceIndexInfos = [[NSMutableDictionary alloc]init]; 50 | for (int i = 0; i < 10; i++) { 51 | CCWebAppInfo* info = [CCWebAppInfo new]; 52 | info.name = [NSString stringWithFormat:@"webapp%@",@(i)]; 53 | info.domains = @[@"www.126.com",@"www.163.com",@"mm.blog.net/public"]; 54 | info.version = @"1.0.0"; 55 | 56 | info.fullPackageMD5 = @"221312213213"; 57 | info.fullDownloadURL = @"www.126.com"; 58 | info.localRelativePath = @"aaa/bbb/webapp1"; 59 | info.status = 1; 60 | info.updatePercent = 0.85; 61 | info.diskSize = 2048; 62 | 63 | [webappInfos setObject:info forKey:info.name]; 64 | } 65 | 66 | 67 | for (int i = 0; i < 10; i++) { 68 | CCResourceIndexInfo* info = [CCResourceIndexInfo new]; 69 | info.url = [NSString stringWithFormat:@"www.126.com/%@.html",@(i)]; 70 | info.localRelativePath = @"aaa/bbb/webapp1"; 71 | info.md5 = @"221312213213"; 72 | // info.webappName = [NSString stringWithFormat:@"webapp%@",@(i)]; 73 | 74 | [resourceIndexInfos setObject:info forKey:info.url]; 75 | } 76 | 77 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 78 | NSString *rootPath = [paths objectAtIndex:0]; 79 | 80 | 81 | CCCacheManager* cacheManager = [[CCCacheManager alloc]initWithRootPath:rootPath]; 82 | XCTAssertNotNil(cacheManager,@"创建CCCacheManager失败"); 83 | 84 | XCTAssertTrue([cacheManager DB_writeWebAppInfos:webappInfos.allValues],@"写入webappinfo失败"); 85 | 86 | NSArray* arr = [cacheManager DB_readWebAppInfos]; 87 | XCTAssertTrue(arr.count == 10,@"读取webappinfo失败"); 88 | 89 | CCWebAppInfo* info = [CCWebAppInfo new]; 90 | info.name = [NSString stringWithFormat:@"webapp11"]; 91 | info.domains = @[@"www.126.com",@"www.163.com",@"mm.blog.net/public"]; 92 | info.version = @"1.0.0"; 93 | 94 | info.fullPackageMD5 = @"221312213213"; 95 | info.fullDownloadURL = @"www.126.com"; 96 | info.localRelativePath = @"aaa/bbb/webapp1"; 97 | info.status = 1; 98 | info.updatePercent = 0.85; 99 | info.diskSize = 2048; 100 | 101 | XCTAssertTrue([cacheManager DB_insertWebAppInfo:info],@"webappinfo失败"); 102 | arr = [cacheManager DB_readWebAppInfos]; 103 | XCTAssertTrue(arr.count == 11,@"读取webappinfo失败"); 104 | 105 | 106 | XCTAssertTrue([cacheManager DB_writeResourceIndexInfos:resourceIndexInfos.allValues],@"写入resource index info失败"); 107 | arr = [cacheManager DB_readResourceIndexInfos]; 108 | 109 | XCTAssertTrue(arr.count == 10,@"读取resource index info失败"); 110 | 111 | NSMutableArray* resIndexInfos = [NSMutableArray new]; 112 | for (int i = 0; i < 3; i++) { 113 | CCResourceIndexInfo* info = [CCResourceIndexInfo new]; 114 | info.url = [NSString stringWithFormat:@"www.126.com/%@.html",@(i+20)]; 115 | info.localRelativePath = @"aaa/bbb/webapp1"; 116 | info.md5 = @"221312213213"; 117 | // info.webappName = [NSString stringWithFormat:@"webapp%@",@(i)]; 118 | 119 | [resIndexInfos addObject:info]; 120 | } 121 | 122 | XCTAssertTrue([cacheManager DB_insertResourceIndexInfos:resIndexInfos],@"插入resource index info失败"); 123 | arr = [cacheManager DB_readResourceIndexInfos]; 124 | XCTAssertTrue(arr.count == 13,@"读取resource index info失败"); 125 | 126 | NSMutableArray* urls = [NSMutableArray new]; 127 | for (CCResourceIndexInfo* info in resIndexInfos) { 128 | [urls addObject:info.url]; 129 | } 130 | 131 | // XCTAssertTrue([cacheManager DB_deleteResourceIndexInfoWithURLs:urls],@"删除resource index info失败"); 132 | // arr = [cacheManager DB_readResourceIndexInfos]; 133 | // XCTAssertTrue(arr.count == 10,@"读取resource index info失败"); 134 | // 135 | // XCTAssertTrue([cacheManager DB_deleteWebAppInfoWithNames:@[@"webapp3"]],@"删除webapp信息失败"); 136 | // XCTAssertTrue([cacheManager DB_deleteResourceIndexInfoWithURLs:@[@"www.126.com/3.html"]],@"删除resouce index信息失败"); 137 | } 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /CCDemo/CCDemoTests/CCCacheManagerTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCCacheManagerTest.m 3 | // CCDemo 4 | // 5 | // Created by jw on 6/21/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CCCacheManager.h" 11 | 12 | @interface CCCacheManagerTest : XCTestCase 13 | 14 | @end 15 | 16 | @implementation CCCacheManagerTest 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | // Use XCTAssert and related functions to verify your tests produce the correct results. 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | 41 | - (void)testFirstInstall 42 | { 43 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 44 | NSString *rootPath = [paths objectAtIndex:0]; 45 | CCCacheManager* manager = [[CCCacheManager alloc]initWithRootPath:rootPath]; 46 | [manager firstInitWithCheckPackagePath:rootPath completeBlock:^{ 47 | 48 | }]; 49 | 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /CCDemo/CCDemoTests/CCDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCDemoTests.m 3 | // CCDemoTests 4 | // 5 | // Created by 小丸子 on 13/6/2016. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CCDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation CCDemoTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /CCDemo/CCDemoTests/CCMD5EncryptTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCMD5EncryptTest.m 3 | // CCDemo 4 | // 5 | // Created by jw on 6/24/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NSString+MD5Encrypt.h" 11 | 12 | @interface CCMD5EncryptTest : XCTestCase 13 | 14 | @end 15 | 16 | @implementation CCMD5EncryptTest 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | // Use XCTAssert and related functions to verify your tests produce the correct results. 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | 41 | //for unit test 42 | - (void) testValidationChecker 43 | { 44 | NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 45 | NSString *rootPath = [paths objectAtIndex:0]; 46 | NSString *filePath = [rootPath stringByAppendingPathComponent:@"language.txt"]; 47 | NSArray *array = @[@"C语言", @"JAVA",@"Objective-C", @"Swift", @"PHP", @"C++", @"C#"]; 48 | // 数组写入文件执行的方法 49 | [array writeToFile:filePath atomically:YES]; 50 | NSString* text = @"aaaaaaaabbbbbbbbccccccccdddddddd"; 51 | NSLog(@"%@",[text encryptedMD5]); 52 | NSLog(@"%@",[[text encryptedMD5] decryptedMD5]); 53 | 54 | XCTAssertTrue([[[text encryptedMD5]decryptedMD5] isEqualToString:text],"not symetric"); 55 | 56 | NSArray* arr = DESKeyEncrypt(@"12344321"); 57 | NSMutableString* str = [[NSMutableString alloc]init]; 58 | for (NSNumber* num in arr) { 59 | [str appendFormat:@"%0x,",num.intValue]; 60 | } 61 | NSLog(@"%@",str); 62 | 63 | XCTAssertTrue([DESKeyDecrypt(DESKeyEncrypt(@"12344321")) isEqualToString:@"12344321"],"key encrypt error"); 64 | 65 | } 66 | @end 67 | -------------------------------------------------------------------------------- /CCDemo/CCDemoTests/CCThreadSafeDictionaryTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCThreadSafeDictionaryTest.m 3 | // CCDemo 4 | // 5 | // Created by jw on 7/6/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CCThreadSafeMutableDictionary.h" 11 | 12 | @interface CCThreadSafeDictionaryTest : XCTestCase 13 | 14 | @end 15 | 16 | @implementation CCThreadSafeDictionaryTest 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | CCThreadSafeMutableDictionary* dic = [CCThreadSafeMutableDictionary new]; 30 | NSInteger testCount = 10; 31 | 32 | dispatch_queue_t q1 = dispatch_queue_create(@"threadSafeTest1".UTF8String, DISPATCH_QUEUE_SERIAL); 33 | dispatch_queue_t q2 = dispatch_queue_create(@"threadSafeTest2".UTF8String, DISPATCH_QUEUE_SERIAL); 34 | dispatch_queue_t q3 = dispatch_queue_create(@"threadSafeTest3".UTF8String, DISPATCH_QUEUE_SERIAL); 35 | 36 | __block int i1 = 0; 37 | __block int i2 = 0; 38 | for (int i =0; i< testCount; i++) { 39 | 40 | for (int i = 0; i < 100; i++) { 41 | dispatch_async(q1, ^{ 42 | for (NSString* str in dic) { 43 | i1++; 44 | NSLog(@"1 = %@ %@",@(i1),str); 45 | } 46 | }); 47 | } 48 | 49 | for (int i = 0; i < 100; i++) { 50 | dispatch_async(q2, ^{ 51 | for (NSString* str in dic) { 52 | i2++; 53 | NSLog(@"2 = %@ %@",@(i2),str); 54 | } 55 | }); 56 | } 57 | 58 | 59 | for (int i = 0; i < 100; i++) { 60 | dispatch_async(q3, ^{ 61 | [dic setObject:@"3 = aa" forKey:[NSString stringWithFormat:@"%@",@(i)]]; 62 | NSLog(@"write"); 63 | }); 64 | 65 | } 66 | } 67 | } 68 | 69 | - (void)testPerformanceExample { 70 | // This is an example of a performance test case. 71 | [self measureBlock:^{ 72 | // Put the code you want to measure the time of here. 73 | }]; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /CCDemo/CCDemoTests/CCVersionCheckerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCVersionCheckerTests.m 3 | // CCDemo 4 | // 5 | // Created by 小丸子 on 13/6/2016. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CCVersionChecker.h" 11 | 12 | @interface CCVersionCheckerTests : XCTestCase 13 | 14 | @property (nonatomic, strong) CCVersionChecker * versionChecker; 15 | 16 | @end 17 | 18 | @implementation CCVersionCheckerTests 19 | 20 | - (void)setUp { 21 | [super setUp]; 22 | // Put setup code here. This method is called before the invocation of each test method in the class. 23 | self.versionChecker = [[CCVersionChecker alloc]initWithDelegate:nil withHost:@"10.242.27.37:9001"]; 24 | 25 | } 26 | 27 | - (void)tearDown { 28 | // Put teardown code here. This method is called after the invocation of each test method in the class. 29 | [super tearDown]; 30 | } 31 | 32 | - (void)testExample { 33 | // This is an example of a functional test case. 34 | // Use XCTAssert and related functions to verify your tests produce the correct results. 35 | } 36 | 37 | - (void)testPerformanceExample { 38 | // This is an example of a performance test case. 39 | [self measureBlock:^{ 40 | // Put the code you want to measure the time of here. 41 | }]; 42 | } 43 | 44 | // check 返回error, versionInfo为空 45 | - (void)testCheckVersionWithErrorParam{ 46 | 47 | } 48 | 49 | -(void)testCheckVersionOnlyWithNativeappInfo{ 50 | 51 | XCTestExpectation * expectation = [self expectationWithDescription:@"CheckVersion with native app info"]; 52 | 53 | NSString * nativeApp = @"KaoLa"; 54 | NSString * nativeVersion = @"20160612"; 55 | 56 | [self.versionChecker checkVersionWithApp:nativeApp nativeVersion:nativeVersion webAppInfos:nil checkCompletionHandler:^(NSArray * _Nullable versionInfoArray, NSError * _Nullable error) { 57 | 58 | if (error == nil){ 59 | 60 | if (versionInfoArray.count != 0) { 61 | 62 | [expectation fulfill]; 63 | } 64 | } 65 | }]; 66 | 67 | [self waitForExpectationsWithTimeout:100.0 handler:^(NSError * _Nullable error) { 68 | if (error) { 69 | XCTFail(@"Expectation error: %@", error); 70 | } 71 | }]; 72 | 73 | } 74 | 75 | // check 返回error, versionInfo 为空 76 | - (void)testCheckVersionWithErrorNotExistedApp{ 77 | 78 | XCTestExpectation * expectation = [self expectationWithDescription:@"CheckVersion With app not existed"]; 79 | 80 | NSString * nativeApp = @"KaoLa1"; 81 | NSString * nativeVersion = @"20160612"; 82 | NSMutableArray * webAppInfoArray = [NSMutableArray array]; 83 | for (int i = 0; i <3; i++) { 84 | CCWebAppInfo * webApp = [[CCWebAppInfo alloc]init]; 85 | webApp.name = @"Login"; 86 | webApp.version = @"20160612"; 87 | [webAppInfoArray addObject:webApp]; 88 | } 89 | 90 | [self.versionChecker checkVersionWithApp:nativeApp nativeVersion:nativeVersion webAppInfos:webAppInfoArray checkCompletionHandler:^(NSArray * _Nullable versionInfoArray, NSError * _Nullable error) { 91 | 92 | if (error != nil && versionInfoArray.count == 0) { 93 | if (error.code == CCVersionCheckerErrorNotExisted) { 94 | 95 | [expectation fulfill]; 96 | } 97 | } 98 | }]; 99 | 100 | [self waitForExpectationsWithTimeout:100.0 handler:^(NSError * _Nullable error) { 101 | if (error) { 102 | XCTFail(@"Expectation error: %@", error); 103 | } 104 | }]; 105 | } 106 | 107 | // 期望:返回所有传入的webApp, 但是checkerState为Latest 108 | - (void)testCheckVersionForAppInfoWithLatestVersion{ 109 | 110 | XCTestExpectation * expectation = [self expectationWithDescription:@"CheckVersion With Latest Version"]; 111 | 112 | NSString * nativeApp = @"KaoLa"; 113 | NSString * nativeVersion = @"20160612"; 114 | NSMutableArray * webAppInfoArray = [NSMutableArray array]; 115 | for (int i = 0; i <3; i++) { 116 | CCWebAppInfo * webApp = [[CCWebAppInfo alloc]init]; 117 | webApp.name = @"Login"; 118 | webApp.version = @"20160612"; 119 | [webAppInfoArray addObject:webApp]; 120 | } 121 | 122 | [self.versionChecker checkVersionWithApp:nativeApp nativeVersion:nativeVersion webAppInfos:webAppInfoArray checkCompletionHandler:^(NSArray * _Nullable versionInfoArray, NSError * _Nullable error) { 123 | 124 | if(error == nil){ 125 | BOOL isSatisfied = YES; 126 | for (CCVersionInfo * versionInfo in versionInfoArray){ 127 | if (versionInfo.statusCode != CCVersionCheckerStateLatest) { 128 | isSatisfied = NO; 129 | } 130 | } 131 | if (isSatisfied) { 132 | [expectation fulfill]; 133 | } 134 | } 135 | }]; 136 | 137 | [self waitForExpectationsWithTimeout:100.0 handler:^(NSError * _Nullable error) { 138 | if (error) { 139 | XCTFail(@"Expectation error: %@", error); 140 | } 141 | }]; 142 | } 143 | 144 | @end 145 | -------------------------------------------------------------------------------- /CCDemo/CCDemoTests/CCWebViewWarmuperTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCWebViewWarmuperTests.m 3 | // CCDemo 4 | // 5 | // Created by 小丸子 on 17/6/2016. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CCWebViewWarmuper.h" 11 | 12 | @interface CCWebViewWarmuperTests : XCTestCase 13 | 14 | @end 15 | 16 | @interface CustomizeWebView : UIWebView 17 | 18 | 19 | @end 20 | 21 | @implementation CustomizeWebView 22 | 23 | 24 | @end 25 | 26 | @implementation CCWebViewWarmuperTests 27 | 28 | - (void)setUp { 29 | [super setUp]; 30 | // Put setup code here. This method is called before the invocation of each test method in the class. 31 | } 32 | 33 | - (void)tearDown { 34 | // Put teardown code here. This method is called after the invocation of each test method in the class. 35 | [super tearDown]; 36 | } 37 | 38 | - (void)testExample { 39 | // This is an example of a functional test case. 40 | // Use XCTAssert and related functions to verify your tests produce the correct results. 41 | } 42 | 43 | - (void)testPerformanceExample { 44 | // This is an example of a performance test case. 45 | [self measureBlock:^{ 46 | // Put the code you want to measure the time of here. 47 | }]; 48 | } 49 | 50 | # pragma mark - internal method 51 | -(id)customizeWebview{ 52 | 53 | CustomizeWebView * webView = [[CustomizeWebView alloc]initWithFrame:CGRectMake(0, 0, 200, 200)]; 54 | return webView; 55 | } 56 | 57 | -(BOOL)isSizeEqual:(CGSize)sizeA withAnother:(CGSize)sizeB{ 58 | 59 | if ((sizeA.height == sizeB.height) && (sizeA.width == sizeB.width)) { 60 | return YES; 61 | } 62 | else{ 63 | return NO; 64 | } 65 | } 66 | 67 | -(void)testWarmuperSupportUserdefineWebviewClass{ 68 | 69 | CCWebViewWarmuper * warmuper = [[CCWebViewWarmuper alloc]initWithWebviewClass:[CustomizeWebView class]]; 70 | 71 | [warmuper initWebviewPool]; 72 | 73 | XCTAssertTrue([[warmuper webviewInstance] class] == [CustomizeWebView class]); 74 | } 75 | 76 | -(void)testWarmuperSupportUserdefineWebviewFactory{ 77 | 78 | CCWebViewWarmuper * warmuper = [[CCWebViewWarmuper alloc]initWithWebviewFactory:^(){ 79 | return [[CustomizeWebView alloc]initWithFrame:CGRectMake(0,0,320,560)]; 80 | }]; 81 | 82 | [warmuper initWebviewPool]; 83 | 84 | XCTAssertTrue(([[warmuper webviewInstance] class] == [CustomizeWebView class]) 85 | && ([self isSizeEqual:[[warmuper webviewInstance] frame].size withAnother:CGRectMake(0, 0, 320, 560).size])); 86 | } 87 | 88 | -(void)testWebviewInstanceFromWarmuperPool{ 89 | 90 | CCWebViewWarmuper * warmuper = [[CCWebViewWarmuper alloc]initWithWebviewClass:[UIWebView class]]; 91 | 92 | warmuper.warmupWebViewCount = 5; 93 | [warmuper initWebviewPool]; 94 | 95 | // use warmuper 96 | UIWebView * webView = [warmuper webviewInstance]; 97 | 98 | XCTAssertNotNil(webView, @"Webview 获取失败"); 99 | 100 | } 101 | 102 | -(void)testWebviewInstanceFromEmptyWarmuperPool{ 103 | 104 | CCWebViewWarmuper * warmuper = [[CCWebViewWarmuper alloc]initWithWebviewClass:[UIWebView class]]; 105 | 106 | warmuper.warmupWebViewCount = 0; 107 | [warmuper initWebviewPool]; 108 | 109 | UIWebView * webView = [warmuper webviewInstance]; 110 | 111 | XCTAssertNotNil(webView, @"Webview 获取失败"); 112 | } 113 | 114 | -(void)testWebviewInstanceFromConsumedWarmuperPool{ 115 | 116 | CCWebViewWarmuper * warmuper = [[CCWebViewWarmuper alloc]initWithWebviewClass:[UIWebView class]]; 117 | 118 | warmuper.warmupWebViewCount = 2; 119 | [warmuper initWebviewPool]; 120 | 121 | for (int i = 0; i < 2; i++) { 122 | UIWebView * webView = [warmuper webviewInstance]; 123 | } 124 | 125 | UIWebView * webViewNew = [warmuper webviewInstance]; 126 | XCTAssertNotNil(webViewNew, @"webview 获取失败"); 127 | } 128 | 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /CCDemo/CCDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /CCDemo/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '7.0' 2 | 3 | target :'CCDemo' do 4 | pod 'CCCandyWebCache', :path => '../',:inhibit_warnings => true 5 | pod 'ZipArchive', '~>1.3.0' 6 | end 7 | -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/CCBackgroundQueue.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/CCBackgroundQueue.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/CCCacheManager+DB.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCCacheManager+DB.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/CCCacheManager+Download.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCCacheManager+Download.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/CCCacheManager.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCCacheManager.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/CCCandyWebCache.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CCCandyWebCache.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/CCLogger.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/CCLogger.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/CCResourceIndexInfo.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCResourceIndexInfo.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/CCThreadSafeMutableDictionary.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/CCThreadSafeMutableDictionary.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/CCValidationChecker.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCValidationChecker.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/CCWebAppInfo.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCWebAppInfo.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/CCWebViewProtocol.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/WebViewProtocol/CCWebViewProtocol.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTDBManager.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTDBManager.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTFDLogger.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFDLogger.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTFDThreadSafeMutableDictionary.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFDThreadSafeMutableDictionary.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTFileDownloadTask.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileDownloadTask.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTFileDownloader+MD5.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileDownloader+MD5.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTFileDownloader+Private.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileDownloader+Private.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTFileDownloader.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileDownloader.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTFileTransferConst.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileTransferConst.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTFileTransferItem.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileTransferItem.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTResourceVersionChecker.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/VersionChecker/HTResourceVersionChecker.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTResourceVersionInfo.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/VersionChecker/HTResourceVersionInfo.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/HTThreadSafeMutableDictionary.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/VersionChecker/HTThreadSafeMutableDictionary.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/NSDate+NSDateRFC1123.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/NSDate+NSDateRFC1123.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/NSString+Encrypt.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/NSString+Encrypt.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/NSString+MD5Encrypt.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/NSString+MD5Encrypt.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/NSString+Path.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/NSString+Path.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/bsdiff.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/bsdiff/bsdiff/bsdiff.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/bspatch.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/bsdiff/bsdiff/bspatch.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/bzlib.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/bsdiff/bzip2/bzlib.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/bzlib_private.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/bsdiff/bzip2/bzlib_private.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/CCCandyWebCache/config.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/bsdiff/bsdiff/config.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/ZipArchive/ZipArchive.h: -------------------------------------------------------------------------------- 1 | ../../../ZipArchive/ZipArchive.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/ZipArchive/crypt.h: -------------------------------------------------------------------------------- 1 | ../../../ZipArchive/minizip/crypt.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/ZipArchive/ioapi.h: -------------------------------------------------------------------------------- 1 | ../../../ZipArchive/minizip/ioapi.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/ZipArchive/mztools.h: -------------------------------------------------------------------------------- 1 | ../../../ZipArchive/minizip/mztools.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/ZipArchive/unzip.h: -------------------------------------------------------------------------------- 1 | ../../../ZipArchive/minizip/unzip.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Private/ZipArchive/zip.h: -------------------------------------------------------------------------------- 1 | ../../../ZipArchive/minizip/zip.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/CCBackgroundQueue.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/CCBackgroundQueue.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/CCCacheManager+DB.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCCacheManager+DB.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/CCCacheManager+Download.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCCacheManager+Download.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/CCCacheManager.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCCacheManager.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/CCCandyWebCache.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CCCandyWebCache.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/CCLogger.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/CCLogger.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/CCResourceIndexInfo.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCResourceIndexInfo.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/CCThreadSafeMutableDictionary.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/CCThreadSafeMutableDictionary.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/CCValidationChecker.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCValidationChecker.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/CCWebAppInfo.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/CacheManager/CCWebAppInfo.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/CCWebViewProtocol.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/WebViewProtocol/CCWebViewProtocol.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTDBManager.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTDBManager.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTFDLogger.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFDLogger.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTFDThreadSafeMutableDictionary.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFDThreadSafeMutableDictionary.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTFileDownloadTask.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileDownloadTask.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTFileDownloader+MD5.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileDownloader+MD5.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTFileDownloader+Private.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileDownloader+Private.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTFileDownloader.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileDownloader.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTFileTransferConst.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileTransferConst.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTFileTransferItem.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/HTFileDownloader/HTFileTransferItem.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTResourceVersionChecker.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/VersionChecker/HTResourceVersionChecker.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTResourceVersionInfo.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/VersionChecker/HTResourceVersionInfo.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/HTThreadSafeMutableDictionary.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/VersionChecker/HTThreadSafeMutableDictionary.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/NSDate+NSDateRFC1123.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/NSDate+NSDateRFC1123.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/NSString+Encrypt.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/NSString+Encrypt.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/NSString+MD5Encrypt.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/NSString+MD5Encrypt.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/NSString+Path.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/CCCandyWebCache/Utils/NSString+Path.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/bsdiff.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/bsdiff/bsdiff/bsdiff.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/bspatch.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/bsdiff/bsdiff/bspatch.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/bzlib.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/bsdiff/bzip2/bzlib.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/bzlib_private.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/bsdiff/bzip2/bzlib_private.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/CCCandyWebCache/config.h: -------------------------------------------------------------------------------- 1 | ../../../../../src/bsdiff/bsdiff/config.h -------------------------------------------------------------------------------- /CCDemo/Pods/Headers/Public/ZipArchive/ZipArchive.h: -------------------------------------------------------------------------------- 1 | ../../../ZipArchive/ZipArchive.h -------------------------------------------------------------------------------- /CCDemo/Pods/Local Podspecs/CCCandyWebCache.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CCCandyWebCache", 3 | "version": "0.0.1", 4 | "summary": "iOS资源缓存解决方案", 5 | "description": "iOS资源缓存解决方案.", 6 | "homepage": "https://g.hz.netease.com/web-cache/CCCandyWebCache-ios", 7 | "license": "MIT", 8 | "source": { 9 | "git": "https://g.hz.netease.com/web-cache/CCCandyWebCache-ios.git" 10 | }, 11 | "platforms": { 12 | "ios": "7.0" 13 | }, 14 | "libraries": "sqlite3", 15 | "source_files": [ 16 | "src/CCCandyWebCache/*.{h,m}", 17 | "src/CCCandyWebCache/CacheManager/*.{h,m}", 18 | "src/CCCandyWebCache/WebViewProtocol/*.{h,m}", 19 | "src/CCCandyWebCache/Utils/*.{h,m}", 20 | "src/CCCandyWebCache/CC_build_script_sample.py", 21 | "src/bsdiff/bsdiff/*.{h,c}", 22 | "src/bsdiff/bzip2/*.{h,c}", 23 | "src/bsdiff/bzip2/*.{h,c}", 24 | "src/HTFileDownloader/*.{h,m}", 25 | "src/VersionChecker/*.{h,m}" 26 | ], 27 | "requires_arc": true 28 | } 29 | -------------------------------------------------------------------------------- /CCDemo/Pods/Pods.xcodeproj/xcshareddata/xcschemes/CCCandyWebCache.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 47 | 48 | 54 | 55 | 57 | 58 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/CCCandyWebCache/CCCandyWebCache-Private.xcconfig: -------------------------------------------------------------------------------- 1 | #include "CCCandyWebCache.xcconfig" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/CCCandyWebCache" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/CCCandyWebCache" "${PODS_ROOT}/Headers/Public/ZipArchive" 4 | OTHER_LDFLAGS = ${CCCANDYWEBCACHE_OTHER_LDFLAGS} 5 | PODS_ROOT = ${SRCROOT} 6 | SKIP_INSTALL = YES -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/CCCandyWebCache/CCCandyWebCache-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_CCCandyWebCache : NSObject 3 | @end 4 | @implementation PodsDummy_CCCandyWebCache 5 | @end 6 | -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/CCCandyWebCache/CCCandyWebCache-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/CCCandyWebCache/CCCandyWebCache.xcconfig: -------------------------------------------------------------------------------- 1 | CCCANDYWEBCACHE_OTHER_LDFLAGS = -l"sqlite3" -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/Pods-CCDemo/Pods-CCDemo-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## ZipArchive 5 | 6 | 7 | Copyright (C) 2010-2012 Matt Connolly, Edward Patel, et al 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | 16 | Generated by CocoaPods - http://cocoapods.org 17 | -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/Pods-CCDemo/Pods-CCDemo-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | 18 | Copyright (C) 2010-2012 Matt Connolly, Edward Patel, et al 19 | 20 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | 27 | Title 28 | ZipArchive 29 | Type 30 | PSGroupSpecifier 31 | 32 | 33 | FooterText 34 | Generated by CocoaPods - http://cocoapods.org 35 | Title 36 | 37 | Type 38 | PSGroupSpecifier 39 | 40 | 41 | StringsTable 42 | Acknowledgements 43 | Title 44 | Acknowledgements 45 | 46 | 47 | -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/Pods-CCDemo/Pods-CCDemo-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_CCDemo : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_CCDemo 5 | @end 6 | -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/Pods-CCDemo/Pods-CCDemo-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | realpath() { 12 | DIRECTORY="$(cd "${1%/*}" && pwd)" 13 | FILENAME="${1##*/}" 14 | echo "$DIRECTORY/$FILENAME" 15 | } 16 | 17 | install_resource() 18 | { 19 | case $1 in 20 | *.storyboard) 21 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 22 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 23 | ;; 24 | *.xib) 25 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 26 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 27 | ;; 28 | *.framework) 29 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 30 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 31 | echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 32 | rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 33 | ;; 34 | *.xcdatamodel) 35 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" 36 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" 37 | ;; 38 | *.xcdatamodeld) 39 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" 40 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" 41 | ;; 42 | *.xcmappingmodel) 43 | echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" 44 | xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" 45 | ;; 46 | *.xcassets) 47 | ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1") 48 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 49 | ;; 50 | /*) 51 | echo "$1" 52 | echo "$1" >> "$RESOURCES_TO_COPY" 53 | ;; 54 | *) 55 | echo "${PODS_ROOT}/$1" 56 | echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" 57 | ;; 58 | esac 59 | } 60 | 61 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 62 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 63 | if [[ "${ACTION}" == "install" ]]; then 64 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 65 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 66 | fi 67 | rm -f "$RESOURCES_TO_COPY" 68 | 69 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 70 | then 71 | case "${TARGETED_DEVICE_FAMILY}" in 72 | 1,2) 73 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 74 | ;; 75 | 1) 76 | TARGET_DEVICE_ARGS="--target-device iphone" 77 | ;; 78 | 2) 79 | TARGET_DEVICE_ARGS="--target-device ipad" 80 | ;; 81 | *) 82 | TARGET_DEVICE_ARGS="--target-device mac" 83 | ;; 84 | esac 85 | 86 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 87 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 88 | while read line; do 89 | if [[ $line != "`realpath $PODS_ROOT`*" ]]; then 90 | XCASSET_FILES+=("$line") 91 | fi 92 | done <<<"$OTHER_XCASSETS" 93 | 94 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 95 | fi 96 | -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/Pods-CCDemo/Pods-CCDemo.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/CCCandyWebCache" "${PODS_ROOT}/Headers/Public/ZipArchive" 3 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/CCCandyWebCache" -isystem "${PODS_ROOT}/Headers/Public/ZipArchive" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"CCCandyWebCache" -l"ZipArchive" -l"sqlite3" -l"z" 5 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/Pods-CCDemo/Pods-CCDemo.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/CCCandyWebCache" "${PODS_ROOT}/Headers/Public/ZipArchive" 3 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/CCCandyWebCache" -isystem "${PODS_ROOT}/Headers/Public/ZipArchive" 4 | OTHER_LDFLAGS = $(inherited) -ObjC -l"CCCandyWebCache" -l"ZipArchive" -l"sqlite3" -l"z" 5 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/ZipArchive/ZipArchive-Private.xcconfig: -------------------------------------------------------------------------------- 1 | #include "ZipArchive.xcconfig" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/ZipArchive" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/CCCandyWebCache" "${PODS_ROOT}/Headers/Public/ZipArchive" 4 | OTHER_LDFLAGS = ${ZIPARCHIVE_OTHER_LDFLAGS} 5 | PODS_ROOT = ${SRCROOT} 6 | SKIP_INSTALL = YES -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/ZipArchive/ZipArchive-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_ZipArchive : NSObject 3 | @end 4 | @implementation PodsDummy_ZipArchive 5 | @end 6 | -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/ZipArchive/ZipArchive-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /CCDemo/Pods/Target Support Files/ZipArchive/ZipArchive.xcconfig: -------------------------------------------------------------------------------- 1 | ZIPARCHIVE_OTHER_LDFLAGS = -l"z" -------------------------------------------------------------------------------- /CCDemo/Pods/ZipArchive/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (C) 2010-2012 Matt Connolly, Edward Patel, et al 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | 10 | -------------------------------------------------------------------------------- /CCDemo/Pods/ZipArchive/README.md: -------------------------------------------------------------------------------- 1 | ZipArchive 2 | ========== 3 | 4 | ZipArchive lets Mac OS X / iOS apps read and write to ZIP archive files. 5 | 6 | 7 | Contributors 8 | ------------ 9 | 10 | Thanks to the following contributors to the Objective-C ZipArchive library: 11 | 12 | * acsolu 13 | * Matt Connolly (@mattconnolly) 14 | * Edward Patel (@epatel) 15 | * kajinka13 16 | * David Keegan (@kgn) 17 | * Yuri (@Wert1go) 18 | * Hyunwoo Nam (@namenu) 19 | 20 | Special Thanks to the minizip authors: 21 | 22 | * Gilles Vollant - Original MiniZip author 23 | * Even Rouault - ZIP64 unzip Support 24 | * Daniel Borca - BZip Compression method support in unzip 25 | * Mathias Svensson - ZIP64 zip support 26 | * Mathias Svensson - BZip Compression method support in zip 27 | 28 | License 29 | ------- 30 | 31 | Portions of ZipArchive are licensed under the original minizip license. See the minizip headers for details. All other parts of this project are licensed under the MIT license, see LICENSE. 32 | -------------------------------------------------------------------------------- /CCDemo/Pods/ZipArchive/ZipArchive.h: -------------------------------------------------------------------------------- 1 | /** 2 | // @header ZipArchive.h 3 | // 4 | // An objective C wrapper for minizip and libz for creating and exanding ZIP files. 5 | // 6 | // @author Created by aish on 08-9-11. 7 | // acsolu@gmail.com 8 | // @copyright Copyright 2008 Inc. All rights reserved. 9 | // 10 | */ 11 | 12 | 13 | 14 | 15 | /** 16 | a block that is called from UnzipFileTo:overwrite:withProgressBlock: where the percentage of 17 | files processed (as an integer from 0 to 100), the number of files processed so far and the 18 | total number of files in the archive is called after each file is processed. 19 | */ 20 | typedef void(^ZipArchiveProgressUpdateBlock)(int percentage, int filesProcessed, unsigned long numFiles); 21 | 22 | /** 23 | @protocol 24 | @discussion methods for a delegate to receive error notifications and control overwriting of files 25 | */ 26 | 27 | @protocol ZipArchiveDelegate 28 | @optional 29 | 30 | /** 31 | @brief Delegate method to be notified of errors 32 | 33 | ZipArchive calls this selector on the delegate when errors are encountered. 34 | 35 | @param msg a string describing the error. 36 | @result void 37 | */ 38 | 39 | -(void) ErrorMessage:(NSString*) msg; 40 | 41 | /** 42 | @brief Delegate method to determine if a file should be replaced 43 | 44 | When an zip file is being expanded and a file is about to be replaced, this selector 45 | is called on the delegate to notify that file is about to be replaced. The delegate method 46 | should return YES to overwrite the file, or NO to skip it. 47 | 48 | @param file - path to the file to be overwritten. 49 | @result a BOOL - YES to replace, NO to skip 50 | */ 51 | 52 | -(BOOL) OverWriteOperation:(NSString*) file; 53 | 54 | @end 55 | 56 | /** 57 | @class 58 | @brief An object that can create zip files and expand existing ones. 59 | This class provides methods to create a zip file (optionally with a password) and 60 | add files to that zip archive. 61 | 62 | It also provides methods to expand an existing archive file (optionally with a password), 63 | and extract the files. 64 | */ 65 | 66 | @interface ZipArchive : NSObject { 67 | @private 68 | void* _zipFile; 69 | void* _unzFile; 70 | 71 | unsigned long _numFiles; 72 | NSString* _password; 73 | id _delegate; 74 | ZipArchiveProgressUpdateBlock _progressBlock; 75 | 76 | NSArray* _unzippedFiles; 77 | 78 | NSFileManager* _fileManager; 79 | NSStringEncoding _stringEncoding; 80 | } 81 | 82 | /** a delegate object conforming to ZipArchiveDelegate protocol */ 83 | @property (nonatomic, retain) id delegate; 84 | @property (nonatomic, readonly) unsigned long numFiles; 85 | @property (nonatomic, copy) ZipArchiveProgressUpdateBlock progressBlock; 86 | 87 | /** 88 | @brief String encoding to be used when interpreting file names in the zip file. 89 | */ 90 | @property (nonatomic, assign) NSStringEncoding stringEncoding; 91 | 92 | /** an array of files that were successfully expanded. Available after calling UnzipFileTo:overWrite: */ 93 | @property (nonatomic, readonly) NSArray* unzippedFiles; 94 | 95 | -(id) initWithFileManager:(NSFileManager*) fileManager; 96 | 97 | -(BOOL) CreateZipFile2:(NSString*) zipFile; 98 | -(BOOL) CreateZipFile2:(NSString*) zipFile Password:(NSString*) password; 99 | -(BOOL) addFileToZip:(NSString*) file newname:(NSString*) newname; 100 | -(BOOL) CloseZipFile2; 101 | 102 | -(BOOL) UnzipOpenFile:(NSString*) zipFile; 103 | -(BOOL) UnzipOpenFile:(NSString*) zipFile Password:(NSString*) password; 104 | -(BOOL) UnzipFileTo:(NSString*) path overWrite:(BOOL) overwrite; 105 | -(BOOL) UnzipCloseFile; 106 | -(NSArray*) getZipFileContents; // list the contents of the zip archive. must be called after UnzipOpenFile 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /CCDemo/Pods/ZipArchive/minizip/crypt.h: -------------------------------------------------------------------------------- 1 | /* crypt.h -- base code for crypt/uncrypt ZIPfile 2 | 3 | 4 | Version 1.01e, February 12th, 2005 5 | 6 | Copyright (C) 1998-2005 Gilles Vollant 7 | 8 | This code is a modified version of crypting code in Infozip distribution 9 | 10 | The encryption/decryption parts of this source code (as opposed to the 11 | non-echoing password parts) were originally written in Europe. The 12 | whole source package can be freely distributed, including from the USA. 13 | (Prior to January 2000, re-export from the US was a violation of US law.) 14 | 15 | This encryption code is a direct transcription of the algorithm from 16 | Roger Schlafly, described by Phil Katz in the file appnote.txt. This 17 | file (appnote.txt) is distributed with the PKZIP program (even in the 18 | version without encryption capabilities). 19 | 20 | If you don't need crypting in your application, just define symbols 21 | NOCRYPT and NOUNCRYPT. 22 | 23 | This code support the "Traditional PKWARE Encryption". 24 | 25 | The new AES encryption added on Zip format by Winzip (see the page 26 | http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong 27 | Encryption is not supported. 28 | */ 29 | 30 | #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) 31 | 32 | /*********************************************************************** 33 | * Return the next byte in the pseudo-random sequence 34 | */ 35 | static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) 36 | { 37 | unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an 38 | * unpredictable manner on 16-bit systems; not a problem 39 | * with any known compiler so far, though */ 40 | 41 | temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; 42 | return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); 43 | } 44 | 45 | /*********************************************************************** 46 | * Update the encryption keys with the next byte of plain text 47 | */ 48 | static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) 49 | { 50 | (*(pkeys+0)) = CRC32((*(pkeys+0)), c); 51 | (*(pkeys+1)) += (*(pkeys+0)) & 0xff; 52 | (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; 53 | { 54 | register int keyshift = (int)((*(pkeys+1)) >> 24); 55 | (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); 56 | } 57 | return c; 58 | } 59 | 60 | 61 | /*********************************************************************** 62 | * Initialize the encryption keys and the random header according to 63 | * the given password. 64 | */ 65 | static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) 66 | { 67 | *(pkeys+0) = 305419896L; 68 | *(pkeys+1) = 591751049L; 69 | *(pkeys+2) = 878082192L; 70 | while (*passwd != '\0') { 71 | update_keys(pkeys,pcrc_32_tab,(int)*passwd); 72 | passwd++; 73 | } 74 | } 75 | 76 | #define zdecode(pkeys,pcrc_32_tab,c) \ 77 | (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) 78 | 79 | #define zencode(pkeys,pcrc_32_tab,c,t) \ 80 | (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) 81 | 82 | #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED 83 | 84 | #define RAND_HEAD_LEN 12 85 | /* "last resort" source for second part of crypt seed pattern */ 86 | # ifndef ZCR_SEED2 87 | # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ 88 | # endif 89 | 90 | static int crypthead(const char* passwd, /* password string */ 91 | unsigned char* buf, /* where to write header */ 92 | int bufSize, 93 | unsigned long* pkeys, 94 | const unsigned long* pcrc_32_tab, 95 | unsigned long crcForCrypting) 96 | { 97 | int n; /* index in random header */ 98 | int t; /* temporary */ 99 | int c; /* random byte */ 100 | unsigned char header[RAND_HEAD_LEN-2]; /* random header */ 101 | static unsigned calls = 0; /* ensure different random header each time */ 102 | 103 | if (bufSize> 7) & 0xff; 118 | header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); 119 | } 120 | /* Encrypt random header (last two bytes is high word of crc) */ 121 | init_keys(passwd, pkeys, pcrc_32_tab); 122 | for (n = 0; n < RAND_HEAD_LEN-2; n++) 123 | { 124 | buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); 125 | } 126 | buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); 127 | buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); 128 | return n; 129 | } 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /CCDemo/Pods/ZipArchive/minizip/mztools.h: -------------------------------------------------------------------------------- 1 | /* 2 | Additional tools for Minizip 3 | Code: Xavier Roche '2004 4 | License: Same as ZLIB (www.gzip.org) 5 | */ 6 | 7 | #ifndef _zip_tools_H 8 | #define _zip_tools_H 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #ifndef _ZLIB_H 15 | #include "zlib.h" 16 | #endif 17 | 18 | #include "unzip.h" 19 | 20 | /* Repair a ZIP file (missing central directory) 21 | file: file to recover 22 | fileOut: output file after recovery 23 | fileOutTmp: temporary file name used for recovery 24 | */ 25 | extern int ZEXPORT unzRepair(const char* file, 26 | const char* fileOut, 27 | const char* fileOutTmp, 28 | uLong* nRecovered, 29 | uLong* bytesRecovered); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /CC_build_script.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import urllib2 3 | import json 4 | import sys 5 | import getopt 6 | import os 7 | 8 | # connection info 9 | WEBCACHE_SERVER = "10.165.124.46" 10 | PORT = 8080 11 | 12 | # appInfo 13 | NATIVE_APP = "kaola" 14 | NATIVE_VERSION = "1.0.0" 15 | PLATFORM = "ios" 16 | WEBAPPINFO_FOLDER = "/CandyWebCache" 17 | WEBAPPINFO_CONFIG = "/WebappInfo.json" 18 | 19 | SUCCESS = 200 20 | ERR_PROTOCOL = 401 21 | ERR_APPID = 402 22 | ERR_SERVER = 501 23 | ERR_UNKNOWN = 601 24 | 25 | class CandyWebcacheBuilder: 26 | webcache_server = "" 27 | port = 0 28 | download_path = "" 29 | 30 | def __init__(self, webcache_server, port, path): 31 | self.webcache_server = webcache_server 32 | self.port = port 33 | if len(path) == 0: 34 | self.download_path = '%s%s' % (sys.path[0], WEBAPPINFO_FOLDER) 35 | else: 36 | self.download_path = '%s%s' % (path, WEBAPPINFO_FOLDER) 37 | if not os.path.exists(self.download_path): 38 | os.mkdir(self.download_path) 39 | print self.download_path + 'create successfully' 40 | print self.download_path 41 | 42 | """ 43 | @return (err_msg, url) 44 | """ 45 | @property 46 | def getWebappInfo(self): 47 | webapp_downloadInfo = [] 48 | request_body = { 49 | "version": "0.1", 50 | "appID": NATIVE_APP, 51 | "appVersion": NATIVE_VERSION, 52 | "platform": PLATFORM, 53 | "isDiff": False, 54 | "autoFill": True 55 | } 56 | req = urllib2.Request('http://%s:%s/api/version_check/webapp' % (self.webcache_server, str(self.port))) 57 | req.add_header('Content-Type', 'application/json') 58 | webapp_fullurls = [] 59 | try: 60 | # adopt default timeout 61 | response_data = urllib2.urlopen(req, json.dumps(request_body)).read() 62 | except urllib2.HTTPError, e: 63 | print "Builder error : %s" % str(e.reason) 64 | sys.exit(1) 65 | except urllib2.URLError, e: 66 | print "Builder error : %s" % str(e.reason) 67 | sys.exit(1) 68 | else: 69 | json_data = json.loads(response_data) 70 | result_code = json_data["code"] 71 | if result_code == SUCCESS: 72 | # if success, then write appinfo into config file 73 | appversion_infos = json_data["data"]["resInfos"] 74 | json_file = open('%s%s' % (self.download_path, WEBAPPINFO_CONFIG), 'wb') 75 | json_file.write(json.dumps(json_data["data"])) 76 | try: 77 | for appversion_info in appversion_infos: 78 | full_url = appversion_info["fullUrl"] 79 | app_id = appversion_info["resID"] 80 | file_name = '%s%s' % (app_id, ".zip") 81 | if len(full_url) and full_url is not None: 82 | webapp_downloadInfo.append([full_url, file_name]) 83 | if len(webapp_downloadInfo) == 0: 84 | sys.exit(0) 85 | else: 86 | return webapp_downloadInfo 87 | except Exception, e: 88 | print "Builder error(json parse error) : %s" % str(e) 89 | sys.exit(1) 90 | elif result_code == ERR_APPID: 91 | err_msg = "Invalid appID" 92 | print "Builder error : %s" % err_msg 93 | sys.exit(1) 94 | elif result_code == ERR_PROTOCOL: 95 | err_msg = "not supported protocol" 96 | print "Builder error : %s" % err_msg 97 | sys.exit(1) 98 | elif result_code == ERR_SERVER: 99 | err_msg = "Server error" 100 | print "Builder error : %s" % err_msg 101 | sys.exit(1) 102 | else: 103 | err_msg = "Unknown error" 104 | print "Builder error : %s" % err_msg 105 | sys.exit(1) 106 | 107 | ''' 108 | @param url downloadurl 109 | @return (BOOL, err_msg) (download success/failed, err_msg) 110 | ''' 111 | def getFile(self, url, file_name): 112 | try: 113 | u = urllib2.urlopen(url) 114 | except urllib2.HTTPError, e: 115 | print "Builder error : %s" % e.reason 116 | sys.exit(1) 117 | except urllib2.URLError, e: 118 | print "Builder error : %s" % e.reason 119 | sys.exit(1) 120 | else: 121 | f = open('%s/%s' % (self.download_path, file_name), 'wb') 122 | # comment progress part 123 | # meta = u.info() 124 | # file_size = int(meta.getheaders("Content-Length")[0]) 125 | # print "Downloading: %s Bytes: %s" % (file_name, file_size) 126 | 127 | file_size_dl = 0 128 | block_sz = 8192 129 | while True: 130 | buffer = u.read(block_sz) 131 | if not buffer: 132 | break 133 | 134 | file_size_dl += len(buffer) 135 | f.write(buffer) 136 | # status = r" %10d [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size) 137 | # status = status + chr(8)*(len(status)+1) 138 | # print status, 139 | 140 | f.close() 141 | print "Builder Success" 142 | 143 | 144 | ''' 145 | The API exposed to outside. 146 | @return (BOOL, err_msg), (Build success or failed, err_msg) 147 | ''' 148 | 149 | 150 | def candyWebcacheBuilder(host, port, path): 151 | webcache_builder = CandyWebcacheBuilder(host, port, path) 152 | webapp_downloadInfos = webcache_builder.getWebappInfo 153 | print webapp_downloadInfos 154 | for [url, file_name] in webapp_downloadInfos: 155 | webcache_builder.getFile(url, file_name) 156 | 157 | 158 | def get_path_from_commandline_args(): 159 | try: 160 | optlist, args = getopt.getopt(sys.argv[1:], "b: p:") 161 | if len(optlist) != 2: 162 | print "invalid parameters: script -b build_products_dir -p product_name" 163 | sys.exit(1) 164 | 165 | for opt, value in optlist: 166 | if opt == '-b': 167 | build_products_dir = value 168 | elif opt == '-p': 169 | product_name = value 170 | 171 | path = '%s/%s' % (build_products_dir, product_name) 172 | print path 173 | return path 174 | except getopt.GetoptError as err: 175 | print "error: %s" % (str(err)) 176 | sys.exit(1) 177 | 178 | 179 | if __name__ == "__main__": 180 | path = get_path_from_commandline_args() 181 | candyWebcacheBuilder(WEBCACHE_SERVER, PORT, path) 182 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Netease Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # CandyWebCache 2 | 3 | CandyWebCache是移动端web资源的本地缓存的解决方案,能够拦截webview的请求,并优先使用本地缓存静态资源进行响应,以此来对webview加载页面性能进行优化。 4 | 5 | 特点: 6 | 7 | * 协议层拦截请求,透明替换响应 8 | * 静态资源版本控制及更新策略 9 | * 资源防篡改策略 10 | * 静态资源自动打包到应用,及首次安装解压处理 11 | 12 | 13 | ## 客户端集成CandyWebCache 14 | 15 | ### 一、使用CocoaPods安装CandyWebCache及依赖库 16 | 17 | (1) 修改Podfile。 18 | 19 | ``` 20 | pod 'CCCandyWebCache', :git => 'https://github.com/NEYouFan/ht-candywebcache-ios.git',:inhibit_warnings => true 21 | pod 'ZipArchive', '~>1.3.0' 22 | ``` 23 | 24 | (2) 执行`pod install`或 `pod update` 25 | 26 | 27 | ### 二、修改和集成自动打包脚本 28 | 29 | * 要求本地安装python 30 | 31 | (1)从CCCandyWebCache源文件中找到`CC_build_script.py`文件,并拷贝到与应用工程文件同级目录。 32 | 33 | (2)修改`CC_build_script.py`脚本文件相关配置信息 34 | 35 | ``` 36 | # connection info 37 | WEBCACHE_SERVER = "127.0.0.1" 38 | PORT = 8080 39 | 40 | # appInfo 41 | NATIVE_APP = "kaola" 42 | NATIVE_VERSION = "1.0.0" 43 | ``` 44 | 45 | (3)添加打包脚本到工程 46 | 47 | * Xcode打包 48 | * 在Xcode中选中工程文件 -> Build Phases 49 | * 菜单栏Editor -> Add Build Phase -> Add Run Script Build Phase,在Build Phases可以看到新添加的Run Script,双击重命名为CandyWebCache Script 50 | * 在Shell栏输入:` /usr/bin/python CC_build_script.py -b ${BUILT_PRODUCTS_DIR} -p ${FULL_PRODUCT_NAME}`,其中BUILT_PRODUCTS_DIR是build app所在路径,FULL_PRODUCT_NAME是app全名 51 | * 如果日常debug想关闭每次build执行脚本,可以将`Run script only when installing`设置为勾选状态,等到真正进行product archive时,才会执行脚本 52 | 53 | * 脚本打包 54 | * 在打包脚本中添加`CC_build_script.py`的执行,注意传入正确的参数 55 | 56 | 脚本执行后,会向服务器请求线上最新资源,根据服务器返回结果,将线上最新的资源包下载并打包到app安装包中。 57 | 58 | 59 | ### 三、CandyWebCache配置 60 | 61 | (1)导入头文件 62 | 63 | ``` 64 | #import "CCCandyWebCache.h" 65 | ``` 66 | 67 | (2)配置CandyWebCache 68 | 69 | 可以在AppDelegate.m的application:didFinishLaunchingWithOptions:方法中配置,也可以在其他合适的地方进行配置。 70 | 71 | **注意:设置配置信息接口[CCCandyWebCache setDefaultConfiguration:config]必须在首次调用[CCCandyWebCache defaultWebCache]之前进行调用,否则将忽略用户设置的配置信息而采用默认配置信息。** 72 | 73 | ``` 74 | CCCandyWebCacheConfig* config = [CCCandyWebCacheConfig new]; 75 | config.serverAddress = @"127.0.0.1:8080"; 76 | config.appName = @"kaoLa"; 77 | config.appVersion = @"1.0.1"; 78 | config.blackListResourceTypes = @[@"html"]; 79 | [CCCandyWebCache setDefaultConfiguration:config]; 80 | 81 | ``` 82 | 83 | (3)配置CCCacheManager[可选] 84 | 85 | ``` 86 | CCCandyWebCache* cacheManager = [CCCandyWebCache defaultWebCache].cacheManager; 87 | cacheManager.concurrentDownloadCount = 3; 88 | cacheManager.memCacheSize = 10 * 1024 * 1024; 89 | 90 | ``` 91 | 92 | ### 四、CandyWebCache的使用 93 | 94 | (1)可以根据需求在合适的时间,如应用启动、前后台切换等,调用接口进行版本检测和更新。 95 | 96 | ``` 97 | [[CCCandyWebCache defaultWebCache] checkAndUpdateResource]; 98 | ``` 99 | 100 | (2)也可以在配置信息CCCandyWebCacheConfig中设置pullInterval进行定时周期性资源检测和更新。 101 | 102 | ``` 103 | config.pullInterval = 10 * 60; //十分钟 104 | 105 | ``` 106 | 107 | (3)可以添加对象作为资源更新的监听器,监听器会收到资源更新的相关事件通知,但要在合适的时间,移除监听器,防止内存泄露。 108 | 109 | ``` 110 | - (void)viewDidAppear:(BOOL)animated 111 | { 112 | [super viewDidAppear:animated]; 113 | [[CCCandyWebCache defaultWebCache] addObserver:self]; 114 | ... 115 | } 116 | 117 | - (void)viewDidDisappear:(BOOL)animated 118 | { 119 | [super viewDidDisappear:animated]; 120 | [[CCCandyWebCache defaultWebCache] removeObserver:self]; 121 | ... 122 | } 123 | 124 | ``` 125 | 126 | ### 五、全局开关 127 | 128 | * 缓存功能开关,关闭将禁用CandyWebCache 129 | 130 | ``` 131 | [CCCandyWebCache defaultWebCache].enable = NO; 132 | ``` 133 | 134 | * 增量更新功能开关,关闭将只做全量更新 135 | 136 | ``` 137 | [CCCandyWebCache defaultWebCache].diffEnable = YES; 138 | ``` 139 | 140 | ## 调试 141 | 142 | (1)启用CandyWebCache日志 143 | 144 | ``` 145 | [CCCandyWebCache setLogEnable:YES]; 146 | ``` 147 | 148 | (2)设置日志级别 149 | 150 | ``` 151 | [CCCandyWebCache setLogLevel:CCLoggerLevelDebug]; 152 | ``` 153 | 154 | ## 测试 155 | 156 | 为了方便测试,我们提供了demo服务器来配合集成CandyWebCache之后,进行测试。 157 | [demo服务器](https://github.com/NEYouFan/ht-candywebcache-demo-server) 158 | 159 | ## CandyWebCache客户端SDK对服务器的要求 160 | 161 | 提供给客户端SDK的接口: 162 | 163 | * 版本检测接口,返回信息包括 164 | * 请求的webapp对应的增量包和全量包信息:版本号、下载地址、md5、url、domains 165 | * 请求中不包含的webapp则返回全量包信息:版本号、下载地址、md5、url、domains 166 | 167 | 提供给应用服务器的接口: 168 | 169 | * 更新全量包 170 | * 根据全量包和历史N(N可配置)个版本的包进行diff包计算 171 | * 计算各个资源包的md5,并加密md5值 172 | * 上传增量包和全量包到文件服务,并记录各个包的md5、资源url、版本号信息、domains 173 | 174 | 服务端功能要求: 175 | 176 | * 计算资源包diff包(使用bsdiff) 177 | * 上传资源到文件服务器 178 | * 资源md5计算与加密(加密算法:DES + base64,客户端对称加密秘钥目前是埋在客户端代码中) 179 | * webapp domains的配置 180 | 181 | ## CandyWebCache客户端SDK对打包方式的要求 182 | 183 | * 打包资源包目录路径要跟url能够对应,如 `http://m.kaola.com/public/r/js/core_57384232.js` ,资源的存放路径需要是 `public/r/js/core_57384232.js` 或者 `r/js/core_57384232.js`。 184 | * 资源缓存不支持带“?”的url,如果有版本号信息需要打到文件名中。对于为了解决缓存问题所采用的后缀形式url,如 `http://m.kaola.com/public/r/js/core.js?v=57384232` ,需要调整打包方式,采用文件名来区分版本号 185 | 186 | ## 系统要求 187 | 188 | 该项目最低支持`iOS 7.0`和`Xcode 7.0` 189 | 190 | ## 许可证 191 | 192 | CandyWebCache使用MIT许可证,详情见[LICENSE](./LICENSE.txt)文件。 193 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/CCCandyWebCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCCandyWebCache.h 3 | // CandyWebCache 4 | // 5 | // Created by jw on 5/27/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | #import "CCCacheManager.h" 12 | #import "HTResourceVersionChecker.h" 13 | #import "CCLogger.h" 14 | 15 | 16 | @class CCCandyWebCache; 17 | 18 | @interface CCCandyWebCacheConfig : NSObject 19 | 20 | /** 21 | * app名称 22 | */ 23 | @property (nonatomic, copy) NSString* appName; 24 | 25 | /** 26 | * app版本号,默认为工程app version 27 | */ 28 | @property (nonatomic, copy) NSString* appVersion; 29 | 30 | /** 31 | * 资源更新检测时间间隔。单位秒,默认是0,表示不做定期资源更新检测。 32 | */ 33 | @property (nonatomic,assign) NSInteger pullInterval; 34 | 35 | /** 36 | * 资源类型黑名单,名单中的文件将不使用缓存资源。 37 | */ 38 | @property (nonatomic, copy) NSArray* blackListResourceTypes; 39 | 40 | /** 41 | * 资源缓存本地根路径 42 | */ 43 | @property (nonatomic, copy) NSString* cacheRootPath; 44 | 45 | /** 46 | * CandyWebCache服务器地址 47 | */ 48 | @property (nonatomic, copy) NSString* serverAddress; 49 | 50 | @end 51 | 52 | 53 | @interface CCCandyWebCache : NSObject 54 | 55 | /** 56 | * 设置默认单例的配置信息,只允许设置一次。如要设置config,需要在第一次使用defaultWebCache之前调用该方法。 57 | * 58 | * @param config 配置信息。如果传nil,则使用默认配置信息。 59 | */ 60 | + (void)setDefaultConfiguration:(CCCandyWebCacheConfig*)config; 61 | 62 | 63 | /** 64 | * 默认单例。获取实例之前,要求已经调用initDefaultConfiguration接口。 65 | * 66 | * @return 实例 67 | */ 68 | + (instancetype)defaultWebCache; 69 | 70 | /** 71 | * 打印log信息控制 72 | * 73 | * @param enable YES:打印log,NO:关闭log 74 | */ 75 | + (void)setLogEnable:(BOOL)enable; 76 | 77 | /** 78 | * 日志级别,只有大于等于设定日志级别的日志会被打印 79 | * 80 | * @param level 日志级别 81 | */ 82 | + (void)setLogLevel:(CCLoggerLevel)level; 83 | 84 | /** 85 | * 资源管理器,可以直接对该对象进行配置。 86 | */ 87 | @property (nonatomic, strong, readonly) CCCacheManager* cacheManager; 88 | 89 | /** 90 | * CandyWebCache全局开关。默认打开 91 | */ 92 | @property (nonatomic, assign) BOOL enable; 93 | 94 | /** 95 | * CandyWebCache增量更新开关。默认打开 96 | */ 97 | @property (nonatomic, assign) BOOL diffEnable; 98 | 99 | 100 | /** 101 | * 检查并更新资源信息。(非可靠,可能根据内部状态拒绝) 102 | */ 103 | - (void)checkAndUpdateResource; 104 | 105 | /** 106 | * 收到推送更新消息,更新资源信息。 107 | * 108 | * @param pushInfo 更新消息 109 | */ 110 | //- (void)updateWithPushInfo:(NSDictionary*)pushInfo; 111 | 112 | /** 113 | * 根据webapp信息,更新一组webapp资源信息。 114 | * 115 | * @param webappsInfos webapp信息 116 | */ 117 | - (void)updateWithWebAppsInfos:(NSArray*)webappsInfos;//暂时不做 118 | 119 | /** 120 | * 添加资源更新监听器(强引用)。需要在合适的时机调用removeObserver防止内存泄露。 121 | * 注意:如果observer实现了CCCacheManager:shouldUpdateWebAppOfURL:withInfo:方法,则只要有一个observer返回了NO,webapp都不会更新。 122 | */ 123 | - (void)addObserver:(id)observer; 124 | 125 | /** 126 | * 添加资源更新监听器(弱引用)。 127 | */ 128 | //- (void)addWeakObserver:(id)weakObserver;//暂时不做 129 | 130 | /** 131 | * 删除资源更新监听器。 132 | */ 133 | - (void)removeObserver:(id)observer; 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/CC_build_script_sample.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import urllib2 3 | import json 4 | import sys 5 | import getopt 6 | import os 7 | 8 | # connection info 9 | WEBCACHE_SERVER = "10.165.124.46" 10 | PORT = 8080 11 | 12 | # appInfo 13 | NATIVE_APP = "kaola" 14 | NATIVE_VERSION = "1.0.0" 15 | PLATFORM = "ios" 16 | WEBAPPINFO_FOLDER = "/CandyWebCache" 17 | WEBAPPINFO_CONFIG = "/WebappInfo.json" 18 | 19 | SUCCESS = 200 20 | ERR_PROTOCOL = 401 21 | ERR_APPID = 402 22 | ERR_SERVER = 501 23 | ERR_UNKNOWN = 601 24 | 25 | class CandyWebcacheBuilder: 26 | webcache_server = "" 27 | port = 0 28 | download_path = "" 29 | 30 | def __init__(self, webcache_server, port, path): 31 | self.webcache_server = webcache_server 32 | self.port = port 33 | if len(path) == 0: 34 | self.download_path = '%s%s' % (sys.path[0], WEBAPPINFO_FOLDER) 35 | else: 36 | self.download_path = '%s%s' % (path, WEBAPPINFO_FOLDER) 37 | if not os.path.exists(self.download_path): 38 | os.mkdir(self.download_path) 39 | print self.download_path + 'create successfully' 40 | print self.download_path 41 | 42 | """ 43 | @return (err_msg, url) 44 | """ 45 | @property 46 | def getWebappInfo(self): 47 | webapp_downloadInfo = [] 48 | request_body = { 49 | "version": "0.1", 50 | "appID": NATIVE_APP, 51 | "appVersion": NATIVE_VERSION, 52 | "platform": PLATFORM, 53 | "isDiff": False, 54 | "autoFill": True 55 | } 56 | req = urllib2.Request('http://%s:%s/api/version_check/webapp' % (self.webcache_server, str(self.port))) 57 | req.add_header('Content-Type', 'application/json') 58 | webapp_fullurls = [] 59 | try: 60 | # adopt default timeout 61 | response_data = urllib2.urlopen(req, json.dumps(request_body)).read() 62 | except urllib2.HTTPError, e: 63 | print "Builder error : %s" % str(e.reason) 64 | sys.exit(1) 65 | except urllib2.URLError, e: 66 | print "Builder error : %s" % str(e.reason) 67 | sys.exit(1) 68 | else: 69 | json_data = json.loads(response_data) 70 | result_code = json_data["code"] 71 | if result_code == SUCCESS: 72 | # if success, then write appinfo into config file 73 | appversion_infos = json_data["data"]["resInfos"] 74 | json_file = open('%s%s' % (self.download_path, WEBAPPINFO_CONFIG), 'wb') 75 | json_file.write(json.dumps(json_data["data"])) 76 | try: 77 | for appversion_info in appversion_infos: 78 | full_url = appversion_info["fullUrl"] 79 | app_id = appversion_info["resID"] 80 | file_name = '%s%s' % (app_id, ".zip") 81 | if len(full_url) and full_url is not None: 82 | webapp_downloadInfo.append([full_url, file_name]) 83 | if len(webapp_downloadInfo) == 0: 84 | sys.exit(0) 85 | else: 86 | return webapp_downloadInfo 87 | except Exception, e: 88 | print "Builder error(json parse error) : %s" % str(e) 89 | sys.exit(1) 90 | elif result_code == ERR_APPID: 91 | err_msg = "Invalid appID" 92 | print "Builder error : %s" % err_msg 93 | sys.exit(1) 94 | elif result_code == ERR_PROTOCOL: 95 | err_msg = "not supported protocol" 96 | print "Builder error : %s" % err_msg 97 | sys.exit(1) 98 | elif result_code == ERR_SERVER: 99 | err_msg = "Server error" 100 | print "Builder error : %s" % err_msg 101 | sys.exit(1) 102 | else: 103 | err_msg = "Unknown error" 104 | print "Builder error : %s" % err_msg 105 | sys.exit(1) 106 | 107 | ''' 108 | @param url downloadurl 109 | @return (BOOL, err_msg) (download success/failed, err_msg) 110 | ''' 111 | def getFile(self, url, file_name): 112 | try: 113 | u = urllib2.urlopen(url) 114 | except urllib2.HTTPError, e: 115 | print "Builder error : %s" % e.reason 116 | sys.exit(1) 117 | except urllib2.URLError, e: 118 | print "Builder error : %s" % e.reason 119 | sys.exit(1) 120 | else: 121 | f = open('%s/%s' % (self.download_path, file_name), 'wb') 122 | # comment progress part 123 | # meta = u.info() 124 | # file_size = int(meta.getheaders("Content-Length")[0]) 125 | # print "Downloading: %s Bytes: %s" % (file_name, file_size) 126 | 127 | file_size_dl = 0 128 | block_sz = 8192 129 | while True: 130 | buffer = u.read(block_sz) 131 | if not buffer: 132 | break 133 | 134 | file_size_dl += len(buffer) 135 | f.write(buffer) 136 | # status = r" %10d [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size) 137 | # status = status + chr(8)*(len(status)+1) 138 | # print status, 139 | 140 | f.close() 141 | print "Builder Success" 142 | 143 | 144 | ''' 145 | The API exposed to outside. 146 | @return (BOOL, err_msg), (Build success or failed, err_msg) 147 | ''' 148 | 149 | 150 | def candyWebcacheBuilder(host, port, path): 151 | webcache_builder = CandyWebcacheBuilder(host, port, path) 152 | webapp_downloadInfos = webcache_builder.getWebappInfo 153 | print webapp_downloadInfos 154 | for [url, file_name] in webapp_downloadInfos: 155 | webcache_builder.getFile(url, file_name) 156 | 157 | 158 | def get_path_from_commandline_args(): 159 | try: 160 | optlist, args = getopt.getopt(sys.argv[1:], "b: p:") 161 | if len(optlist) != 2: 162 | print "invalid parameters: script -b build_products_dir -p product_name" 163 | sys.exit(1) 164 | 165 | for opt, value in optlist: 166 | if opt == '-b': 167 | build_products_dir = value 168 | elif opt == '-p': 169 | product_name = value 170 | 171 | path = '%s/%s' % (build_products_dir, product_name) 172 | print path 173 | return path 174 | except getopt.GetoptError as err: 175 | print "error: %s" % (str(err)) 176 | sys.exit(1) 177 | 178 | 179 | if __name__ == "__main__": 180 | path = get_path_from_commandline_args() 181 | candyWebcacheBuilder(WEBCACHE_SERVER, PORT, path) 182 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/CacheManager/CCCacheManager+DB.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCCacheManager+DB.h 3 | // Pods 4 | // 5 | // Created by jw on 6/8/16. 6 | // 7 | // 8 | 9 | #import "CCCacheManager.h" 10 | #import "CCWebAppInfo.h" 11 | #import "CCResourceIndexInfo.h" 12 | 13 | @interface CCCacheManager (DB) 14 | 15 | /** 16 | * 创建数据库,包含两张表:WEBAPPINFOS和PATHINDEX 17 | * 18 | * @param path 数据库保存路径 19 | * 20 | */ 21 | - (BOOL)DB_createDatabaseAtPath:(NSString*)path; 22 | 23 | /** 24 | * 从数据库读取webapp信息 25 | * 26 | * @return webapp信息数据 27 | */ 28 | - (NSArray*)DB_readWebAppInfos; 29 | 30 | /** 31 | * 写入webapp信息到数据库,写入之前会清空之前数据 32 | * 33 | * @param webAppInfos webapp信息 34 | * 35 | * @return YES:成功,NO:失败 36 | */ 37 | - (BOOL)DB_writeWebAppInfos:(NSArray*)webAppInfos; 38 | 39 | /** 40 | * 插入单个webapp信息到数据库 41 | * 42 | * @param webAppInfo webapp信息 43 | * 44 | * @return YES:成功,NO:失败 45 | */ 46 | - (BOOL)DB_insertWebAppInfo:(CCWebAppInfo*)webAppInfo; 47 | 48 | /** 49 | * 删除单个webapp信息到数据库 50 | * 51 | * @param webAppInfo webapp信息 52 | * 53 | * @return YES:成功,NO:失败 54 | */ 55 | - (BOOL)DB_deleteWebAppInfo:(CCWebAppInfo*)webAppInfo; 56 | 57 | /** 58 | * 更新单个webapp信息到数据库 59 | * 60 | * @param webAppInfo webapp信息 61 | * 62 | * @return YES:成功,NO:失败 63 | */ 64 | - (BOOL)DB_updateWebAppInfo:(CCWebAppInfo*)webAppInfo; 65 | 66 | /** 67 | * 删除多个指定名称的webapp信息 68 | * 69 | * @param webappNames 需要删除的webapp名称 70 | * 71 | * @return YES:成功,NO:失败 72 | */ 73 | - (BOOL)DB_deleteWebAppInfoWithNames:(NSArray*)webappNames; 74 | 75 | /** 76 | * 从数据库读取资源索引信息 77 | * 78 | * @return 资源索引信息 79 | */ 80 | - (NSArray*)DB_readResourceIndexInfos; 81 | 82 | /** 83 | * 写入资源索引信息到数据库,写入之前会清空之前数据 84 | * 85 | * @param resourceIndexInfos 资源索引信息 86 | * 87 | * @return YES:成功,NO:失败 88 | */ 89 | - (BOOL)DB_writeResourceIndexInfos:(NSArray*)resourceIndexInfos; 90 | 91 | /** 92 | * 插入单个资源索引信息到数据库 93 | * 94 | * @param resourceIndexInfo 资源索引信息 95 | * 96 | * @return YES:成功,NO:失败 97 | */ 98 | - (BOOL)DB_insertResourceIndexInfos:(NSArray*)resourceIndexInfos; 99 | 100 | /** 101 | * 删除单个资源索引信息到数据库 102 | * 103 | * @param resourceIndexInfo 资源索引信息 104 | * 105 | * @return YES:成功,NO:失败 106 | */ 107 | //- (BOOL)DB_deleteResourceIndexInfos:(NSArray*)resourceIndexInfos; 108 | 109 | /** 110 | * 删除多个指定url的资源索引信息 111 | * 112 | * @param webappNames 需要删除的资源url 113 | * 114 | * @return YES:成功,NO:失败 115 | */ 116 | //- (BOOL)DB_deleteResourceIndexInfoWithURLs:(NSArray*)urls; 117 | 118 | 119 | - (BOOL)DB_deleteResourceIndexInfoWithWebappNames:(NSArray*)webappNames; 120 | 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/CacheManager/CCCacheManager+Download.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCCacheManager+Download.h 3 | // Pods 4 | // 5 | // Created by jw on 6/15/16. 6 | // 7 | // 8 | 9 | #import "CCCandyWebCache.h" 10 | #import "HTFileDownloader.h" 11 | #import "CCWebAppInfo.h" 12 | #import "CCResourceIndexInfo.h" 13 | #import "CCThreadSafeMutableDictionary.h" 14 | 15 | @interface CCCacheManager () 16 | @property (nonatomic, strong) HTFileDownloader* fileDownloader; 17 | //key:appname 18 | @property (nonatomic, copy) CCThreadSafeMutableDictionary* webappInfos; 19 | 20 | //key:domain 21 | @property (nonatomic, copy) CCThreadSafeMutableDictionary* domainWebappInfos; 22 | 23 | //key:webapp名称+资源相对路径 24 | @property (nonatomic, copy) CCThreadSafeMutableDictionary* resourceIndexInfos; 25 | 26 | @end 27 | 28 | 29 | @interface CCCacheManager (Download) 30 | 31 | - (void)innerUpdateResourceOfWebAppInfo:(CCWebAppInfo*)webappInfo; 32 | 33 | - (void)unzipInfosWithZipFile:(NSString*)zipFile toWebAppInfo:(CCWebAppInfo*)webappInfo; 34 | 35 | -(void)appDidEnterBackground:(NSNotification *)notification; 36 | 37 | -(void)appDidEnterForeground:(NSNotification *)notification; 38 | 39 | - (BOOL)replaceOrAddWebAppInfo:(CCWebAppInfo*)webappInfo; 40 | 41 | - (BOOL)removeWebAppInfo:(CCWebAppInfo*)webappInfo; 42 | @end 43 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/CacheManager/CCCacheManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCCacheManager.h 3 | // CandyWebCache 4 | // 5 | // Created by jw on 6/2/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CCWebAppInfo.h" 11 | 12 | 13 | @class CCCacheManager; 14 | 15 | typedef NS_ENUM(NSInteger,CCCacheManagerState) 16 | { 17 | CCCacheManagerStateUninitialed = 0, 18 | CCCacheManagerStateAvailable 19 | }; 20 | 21 | typedef NS_ENUM(NSInteger,CCWebAppUpdateError) 22 | { 23 | CCWebAppUpdateErrorDownload = 1, 24 | CCWebAppUpdateErrorDiffMerge, 25 | CCWebAppUpdateErrorNotValid, 26 | CCWebAppUpdateErrorUnzip, 27 | CCWebAppUpdateErrorLocalAppNotExist 28 | }; 29 | 30 | @protocol CCWebAppUpdateProtocol 31 | 32 | @optional 33 | /** 34 | * 实现CCWebAppUpdateProtocol的对象可以判定是否更新webapp 35 | * 36 | * @return YES:更新,NO:不更新 37 | */ 38 | - (BOOL)CCCacheManager:(CCCacheManager*)manager shouldUpdateWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info; 39 | 40 | - (void)CCCacheManager:(CCCacheManager*)manager willStartDownloadWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info; 41 | 42 | - (void)CCCacheManager:(CCCacheManager*)manager didStartDownloadWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info; 43 | 44 | - (void)CCCacheManager:(CCCacheManager*)manager updatingWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info; 45 | 46 | - (void)CCCacheManager:(CCCacheManager*)manager didFinishDownloadWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info; 47 | 48 | - (void)CCCacheManager:(CCCacheManager*)manager didUpdateWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info; 49 | 50 | - (void)CCCacheManager:(CCCacheManager*)manager failedUpdateWebAppOfURL:(NSString*)url withInfo:(CCWebAppInfo*)info error:(CCWebAppUpdateError)error; 51 | 52 | @end 53 | 54 | 55 | @interface CCCacheManager : NSObject 56 | 57 | /** 58 | * CCCacheManager当前状态 59 | */ 60 | @property (nonatomic, assign, readonly) CCCacheManagerState state; 61 | 62 | /** 63 | * 资源缓存本地根路径 64 | */ 65 | @property (nonatomic, copy, readonly) NSString* rootPath; 66 | 67 | /** 68 | * 资源下载并发数,默认5 69 | */ 70 | @property (nonatomic, assign) NSUInteger concurrentDownloadCount; 71 | 72 | /** 73 | * 资源内存缓存最大开销(非严格)。默认5 *1024 * 1024 (5M)字节。 74 | */ 75 | @property (nonatomic, assign) NSUInteger memCacheSize; 76 | 77 | /** 78 | * 代理对象 79 | */ 80 | @property (nonatomic, weak) id delegate; 81 | 82 | /** 83 | * 构造函数 84 | * 85 | * @param rootPath 资源缓存根路径 86 | * 87 | * @return 实例 88 | */ 89 | - (instancetype)initWithRootPath:(NSString*)rootPath; 90 | 91 | /** 92 | * 创建数据库及相关目录、从数据库异步加载数据. 93 | * 注意:需要调用该接口完成初始化。 94 | * 95 | * @param completeBlock 96 | */ 97 | - (void)initializeWithCompleteBlock:(void (^)(void))completeBlock; 98 | 99 | /** 100 | * 更新资源。非可靠,可能忽略更新,如当前正在更新资源、代理不允许更新等 101 | * 102 | * @param webappInfo webapp信息 103 | * 104 | */ 105 | - (void)updateResourceOfWebAppInfo:(CCWebAppInfo*)webappInfo; 106 | 107 | /** 108 | * 获取url对应的资源数据 109 | * 110 | * @param url url 111 | * 112 | * @return url对应资源数据 113 | */ 114 | - (NSData*)dataForURL:(NSString*)url; 115 | 116 | /** 117 | * 根据webapp名称,获取其app信息 118 | * 119 | * @param webappName webapp名称 120 | * 121 | * @return webapp信息 122 | */ 123 | - (CCWebAppInfo*)webAppInfoWithName:(NSString*)webappName; 124 | 125 | /** 126 | * 获取url对应本地资源路径 127 | * 128 | * @param url url 129 | * 130 | * @return url对应本地资源路径,如果不存在,返回nil 131 | */ 132 | - (NSString*)localResourcePathOfURL:(NSString*)url; 133 | 134 | /** 135 | * 获取所有webapp名称 136 | * 137 | * @return webapp名称数组 138 | */ 139 | - (NSArray*)webAppInfos; 140 | 141 | /** 142 | * 获取webapp本地资源所占磁盘空间总大小 143 | * 144 | * @return webapp本地资源总大小 145 | */ 146 | - (NSUInteger)diskSizeOfWebApps; 147 | 148 | /** 149 | * 清除webapp本地资源缓存(内存+磁盘) 150 | * 151 | * @param webappName webapp名称 152 | * 153 | */ 154 | - (void)clearCacheOfWebAppWithName:(NSString*)webappName; 155 | 156 | /** 157 | * 清除webapp本地资源内存缓存 158 | * 159 | * @param webappName webapp名称 160 | * 161 | */ 162 | - (void)clearMemCacheOfWebAppWithName:(NSString*)webappName; 163 | 164 | /** 165 | * 清除所有webapp本地资源缓存(内存+磁盘) 166 | * 167 | */ 168 | - (void)clearCacheOfWebApps; 169 | 170 | /** 171 | * 清除内存缓存 172 | * 173 | */ 174 | - (void)clearMemCache; 175 | 176 | /** 177 | * 获取所有webapp信息 178 | * 179 | * @return webapp信息们 180 | */ 181 | - (NSArray*)allWebAppInfos; 182 | 183 | /** 184 | * 首次安装初始化,要求全量包命名规则是:webappName_webappVersion.zip。 185 | * domain信息保存在packagePath所在目录下的domains.config文件中 186 | * 187 | * @param packagePath 全量包所在路径 188 | */ 189 | - (void)firstInitWithCheckPackagePath:(NSString*)packagePath completeBlock:(void (^)(void))block; 190 | 191 | @end 192 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/CacheManager/CCResourceIndexInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCResourceIndexInfo.h 3 | // Pods 4 | // 5 | // Created by jw on 6/8/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * 资源检索信息 13 | */ 14 | @interface CCResourceIndexInfo : NSObject 15 | 16 | /** 17 | * 资源相对URL。如kaola/js/core.js 18 | */ 19 | @property (nonatomic, copy) NSString* url; 20 | 21 | /** 22 | * 资源本地路径 23 | */ 24 | //@property (nonatomic, copy) NSString* localPath; 25 | /** 26 | * 资源本地相对路径,相对于Document目录 27 | */ 28 | @property (nonatomic, copy) NSString* localRelativePath; 29 | 30 | /** 31 | * 资源本地全路径 32 | */ 33 | @property (nonatomic, copy, readonly) NSString* localFullPath; 34 | 35 | /** 36 | * 资源md5值 37 | */ 38 | @property (nonatomic, copy) NSString* md5; 39 | 40 | /** 41 | * 资源所属webapp名称 42 | */ 43 | @property (nonatomic, copy) NSString* webappName; 44 | 45 | 46 | /** 47 | * 唯一key 48 | * 49 | * @return webappName/url 50 | */ 51 | - (NSString*)uniqueKey; 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/CacheManager/CCResourceIndexInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCResourceIndexInfo.m 3 | // Pods 4 | // 5 | // Created by jw on 6/8/16. 6 | // 7 | // 8 | 9 | #import "CCResourceIndexInfo.h" 10 | #import "NSString+Path.h" 11 | 12 | @implementation CCResourceIndexInfo 13 | 14 | - (instancetype)init 15 | { 16 | self = [super init]; 17 | if (self) { 18 | _url = @""; 19 | _localRelativePath = @""; 20 | _localFullPath = @""; 21 | _md5 = @""; 22 | _webappName = @""; 23 | } 24 | return self; 25 | } 26 | 27 | - (NSString*)uniqueKey 28 | { 29 | return [NSString stringWithFormat:@"%@/%@",_webappName,_url]; 30 | } 31 | 32 | - (NSString *)description 33 | { 34 | NSMutableString* des = [NSMutableString new]; 35 | [des appendFormat:@"===CCResourceIndexInfo:%@===\n",[self uniqueKey]]; 36 | [des appendFormat:@"url:%@,\n",_url]; 37 | [des appendFormat:@"localPath:%@,\n",_localFullPath]; 38 | [des appendFormat:@"md5:%@,\n",_md5]; 39 | [des appendFormat:@"webappName:%@,\n",_webappName]; 40 | [des appendString:@"======\n"]; 41 | return des; 42 | } 43 | 44 | - (void)setLocalRelativePath:(NSString *)localRelativePath 45 | { 46 | _localRelativePath = localRelativePath; 47 | _localFullPath = [NSString stringWithFormat:@"%@/%@",[NSString documentPath],localRelativePath]; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/CacheManager/CCValidationChecker.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCValidationChecker.h 3 | // CandyWebCache 4 | // 5 | // Created by jw on 6/3/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CCValidationChecker : NSObject 12 | 13 | 14 | + (BOOL)data:(NSData*)data md5Maching:(NSString*)md5String; 15 | 16 | + (BOOL)file:(NSString*)filePath md5Maching:(NSString*)md5String; 17 | 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/CacheManager/CCValidationChecker.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCValidationChecker.m 3 | // CandyWebCache 4 | // 5 | // Created by jw on 6/3/16. 6 | // Copyright © 2016 jw. All rights reserved. 7 | // 8 | 9 | #import "CCValidationChecker.h" 10 | #import "HTFileDownloader+MD5.h" 11 | 12 | @implementation CCValidationChecker 13 | 14 | + (BOOL)data:(NSData*)data md5Maching:(NSString*)md5String 15 | { 16 | if (!md5String || [md5String isEqualToString:@""]) { 17 | return NO; 18 | } 19 | return [[data MD5] isEqualToString:md5String]; 20 | } 21 | 22 | + (BOOL)file:(NSString*)filePath md5Maching:(NSString*)md5String 23 | { 24 | if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) { 25 | return NO; 26 | } 27 | return [CCValidationChecker data:[[NSFileManager defaultManager] contentsAtPath:filePath] md5Maching:md5String]; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/CacheManager/CCWebAppInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCWebAppInfo.h 3 | // Pods 4 | // 5 | // Created by jw on 6/7/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | 12 | typedef NS_ENUM(NSInteger,CCWebAppStatus) 13 | { 14 | CCWebAppStatusNone = 0, 15 | CCWebAppStatusAvailable = 1, 16 | CCWebAppStatusUpdating, 17 | // CCWebAppStatusExpired, 18 | CCWebAppStatusError 19 | }; 20 | 21 | /** 22 | * webapp信息 23 | */ 24 | @interface CCWebAppInfo : NSObject 25 | 26 | /** 27 | * webapp名称,全局唯一。 28 | */ 29 | @property (nonatomic, copy) NSString* name; 30 | 31 | /** 32 | * webapp所属域名 33 | */ 34 | @property (nonatomic, copy) NSArray* domains; 35 | 36 | /** 37 | * webapp本地版本号 38 | */ 39 | @property (nonatomic, copy) NSString* version; 40 | 41 | /** 42 | * webapp增量包md5值 43 | */ 44 | @property (nonatomic, copy) NSString* diffPackageMD5; 45 | 46 | /** 47 | * webapp增量包下载路径 48 | */ 49 | @property (nonatomic, copy) NSString* diffDownloadURL; 50 | 51 | /** 52 | * webapp全量包md5值 53 | */ 54 | @property (nonatomic, copy) NSString* fullPackageMD5; 55 | 56 | /** 57 | * webapp全量包下载路径 58 | */ 59 | @property (nonatomic, copy) NSString* fullDownloadURL; 60 | 61 | /** 62 | * webapp本地路径,例如rootPath/webapps/webapp1 63 | */ 64 | //@property (nonatomic, copy) NSString* localPath; 65 | 66 | /** 67 | * 资源本地相对路径,相对于Document目录 68 | */ 69 | @property (nonatomic, copy) NSString* localRelativePath; 70 | 71 | /** 72 | * 资源本地全路径 73 | */ 74 | @property (nonatomic, copy, readonly) NSString* localFullPath; 75 | 76 | /** 77 | * webapp当前状态 78 | */ 79 | @property (nonatomic, assign) CCWebAppStatus status; 80 | 81 | /** 82 | * webapp更新进度百分比 83 | */ 84 | @property (nonatomic, assign) float updatePercent; 85 | 86 | /** 87 | * webapp所占磁盘大小(字节) 88 | */ 89 | @property (nonatomic, assign) unsigned long long diskSize; 90 | 91 | /** 92 | * 下载压缩包的任务id,用于断点下载的恢复 93 | */ 94 | @property (nonatomic, copy) NSString* taskID; 95 | 96 | /** 97 | * 当前下载任务是否是增量更新任务,用于断点下载的恢复 98 | */ 99 | @property (nonatomic, assign) BOOL isDiffTask; 100 | 101 | 102 | - (NSString*)composeVersion; 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/CacheManager/CCWebAppInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCWebAppInfo.m 3 | // Pods 4 | // 5 | // Created by jw on 6/7/16. 6 | // 7 | // 8 | 9 | #import "CCWebAppInfo.h" 10 | #import "NSString+Path.h" 11 | 12 | @implementation CCWebAppInfo 13 | 14 | 15 | - (instancetype)init 16 | { 17 | self = [super init]; 18 | if (self) { 19 | _domains = @[]; 20 | _version = @""; 21 | _fullPackageMD5 = @""; 22 | _fullDownloadURL = @""; 23 | _localRelativePath = @""; 24 | _localFullPath = @""; 25 | _status = CCWebAppStatusNone; 26 | _updatePercent = 0.0f; 27 | _diskSize = 0; 28 | _taskID = @""; 29 | _isDiffTask = NO; 30 | _diffPackageMD5 = @""; 31 | _diffDownloadURL = @""; 32 | } 33 | return self; 34 | } 35 | 36 | 37 | - (NSString *)description 38 | { 39 | NSMutableString* des = [NSMutableString new]; 40 | [des appendString:@"======\n"]; 41 | [des appendFormat:@"webappName:%@,\n",_name]; 42 | [des appendFormat:@"webappVersion:%@,\n",_version]; 43 | [des appendString:@"domains:"]; 44 | for (NSString* domain in _domains) { 45 | [des appendFormat:@"%@, ",domain]; 46 | } 47 | [des appendString:@"\n"]; 48 | [des appendFormat:@"diffMD5:%@,\n",_diffPackageMD5]; 49 | [des appendFormat:@"diffUrl:%@,\n",_diffDownloadURL]; 50 | [des appendFormat:@"fullMD5:%@,\n",_fullPackageMD5]; 51 | [des appendFormat:@"fullUrl:%@,\n",_fullDownloadURL]; 52 | [des appendFormat:@"localFullPath:%@,\n",_localFullPath]; 53 | [des appendFormat:@"status:%@,\n",_status == CCWebAppStatusAvailable ? @"可用" : @"不可用"]; 54 | [des appendFormat:@"diskSize:%@,\n",@(_diskSize)]; 55 | [des appendString:@"======\n"]; 56 | return des; 57 | } 58 | 59 | - (void)setLocalRelativePath:(NSString *)localRelativePath 60 | { 61 | _localRelativePath = localRelativePath; 62 | _localFullPath = [NSString stringWithFormat:@"%@/%@",[NSString documentPath],localRelativePath]; 63 | } 64 | 65 | - (NSString*)version 66 | { 67 | NSArray* comps = [_version componentsSeparatedByString:@"&"]; 68 | if (comps.count == 2) { 69 | return comps[0]; 70 | } 71 | return _version; 72 | } 73 | 74 | - (NSString*)composeVersion 75 | { 76 | return _version; 77 | } 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/CCBackgroundQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCBackgroundQueue.h 3 | // Pods 4 | // 5 | // Created by jw on 7/5/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * 并发队列 13 | */ 14 | @interface CCBackgroundQueue : NSObject 15 | 16 | + (instancetype)sharedInstance; 17 | 18 | - (void)dispatchAsync:(void (^)(void))block; 19 | 20 | - (void)dispatchSync:(void (^)(void))block; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/CCBackgroundQueue.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCBackgroundQueue.m 3 | // Pods 4 | // 5 | // Created by jw on 7/5/16. 6 | // 7 | // 8 | 9 | #import "CCBackgroundQueue.h" 10 | 11 | static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey; 12 | 13 | 14 | @interface CCBackgroundQueue () 15 | 16 | @property (nonatomic, strong) dispatch_queue_t queue; 17 | 18 | @end 19 | 20 | 21 | @implementation CCBackgroundQueue 22 | 23 | 24 | 25 | + (instancetype)sharedInstance 26 | { 27 | static id instance; 28 | static dispatch_once_t onceToken; 29 | dispatch_once(&onceToken, ^{ 30 | instance = [CCBackgroundQueue new]; 31 | }); 32 | return instance; 33 | } 34 | 35 | 36 | - (instancetype)init 37 | { 38 | self = [super init]; 39 | if (self) { 40 | _queue = dispatch_queue_create([[NSString stringWithFormat:@"cccachemanager.%@", self] UTF8String], DISPATCH_QUEUE_CONCURRENT); 41 | dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); 42 | } 43 | return self; 44 | } 45 | 46 | - (void)dispatchAsync:(void (^)(void))block 47 | { 48 | dispatch_async(_queue, ^{ 49 | if (block) { 50 | block(); 51 | } 52 | }); 53 | } 54 | 55 | - (void)dispatchSync:(void (^)(void))block 56 | { 57 | CCBackgroundQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); 58 | assert(currentSyncQueue != self && "dispatchSync: was called reentrantly on the same queue, which would lead to a deadlock"); 59 | 60 | dispatch_sync(_queue, ^{ 61 | if (block) { 62 | block(); 63 | } 64 | }); 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/CCLogger.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCLogger.h 3 | // Pods 4 | // 5 | // Created by jw on 6/23/16. 6 | // 7 | // 8 | 9 | #import 10 | #import "HTFDLogger.h" 11 | 12 | #define CCLogVerbose HTFDLogVerbose 13 | #define CCLogTest HTFDLogTest 14 | #define CCLogInfo HTFDLogInfo 15 | #define CCLogDebug HTFDLogDebug 16 | #define CCLogWarn HTFDLogWarn 17 | #define CCLogError HTFDLogError 18 | 19 | 20 | 21 | 22 | typedef NS_ENUM(NSInteger,CCLoggerLevel) 23 | { 24 | CCLoggerLevelVerbose = HTFDLoggerLevelVerbose, 25 | CCLoggerLevelTest = HTFDLoggerLevelTest, 26 | CCLoggerLevelInfo = HTFDLoggerLevelInfo, 27 | CCLoggerLevelDebug = HTFDLoggerLevelDebug, 28 | CCLoggerLevelWarning = HTFDLoggerLevelWarning, 29 | CCLoggerLevelError = HTFDLoggerLevelWarning 30 | }; 31 | 32 | 33 | @interface CCLogger : NSObject 34 | + (void)setEnable:(BOOL)enable; 35 | 36 | + (void)setLogLevel:(CCLoggerLevel)level; 37 | @end 38 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/CCLogger.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCLogger.m 3 | // Pods 4 | // 5 | // Created by jw on 6/23/16. 6 | // 7 | // 8 | 9 | #import "CCLogger.h" 10 | 11 | @implementation CCLogger 12 | + (void)setEnable:(BOOL)enable 13 | { 14 | [HTFDLogger setEnable:enable]; 15 | } 16 | 17 | + (void)setLogLevel:(CCLoggerLevel)level 18 | { 19 | [HTFDLogger setLogLevel:(HTFDLoggerLevel)level]; 20 | } 21 | @end 22 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/CCThreadSafeMutableDictionary.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCThreadSafeMutableDictionary.h 3 | // Pods 4 | // 5 | // Created by jw on 7/6/16. 6 | // 7 | // 8 | 9 | #import 10 | #import "HTFDThreadSafeMutableDictionary.h" 11 | 12 | //@interface CCThreadSafeMutableDictionary : NSMutableDictionary 13 | @interface CCThreadSafeMutableDictionary : HTFDThreadSafeMutableDictionary 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/CCThreadSafeMutableDictionary.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCThreadSafeMutableDictionary.m 3 | // Pods 4 | // 5 | // Created by jw on 7/6/16. 6 | // 7 | // 8 | 9 | #import "CCThreadSafeMutableDictionary.h" 10 | #import 11 | #import 12 | 13 | @implementation CCThreadSafeMutableDictionary { 14 | 15 | 16 | } 17 | 18 | @end -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/NSDate+NSDateRFC1123.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+NSDateRFC1123.h 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 24/6/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSDate (NSDateRFC1123) 12 | -(NSString*)rfc1123String; 13 | @end 14 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/NSDate+NSDateRFC1123.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+NSDateRFC1123.m 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 24/6/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import "NSDate+NSDateRFC1123.h" 10 | 11 | @implementation NSDate (NSDateRFC1123) 12 | 13 | -(NSString*)rfc1123String 14 | { 15 | static NSDateFormatter *df = nil; 16 | if(df == nil) 17 | { 18 | df = [[NSDateFormatter alloc] init]; 19 | df.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; 20 | df.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; 21 | df.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'"; 22 | } 23 | NSTimeZone *zone = [NSTimeZone systemTimeZone]; 24 | NSInteger interval = [zone secondsFromGMTForDate: self]; 25 | NSDate *localDate = [self dateByAddingTimeInterval: interval]; 26 | 27 | return [df stringFromDate:localDate]; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/NSString+Encrypt.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Encrypt.h 3 | // Pods 4 | // 5 | // Created by 小丸子 on 23/6/2016. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (Encrypt) 12 | -(NSString *)base64AfterSha256WithKey:(NSString *)key; 13 | @end 14 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/NSString+Encrypt.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Encrpt.m 3 | // Pods 4 | // 5 | // Created by 小丸子 on 23/6/2016. 6 | // 7 | // 8 | 9 | #import "NSString+Encrypt.h" 10 | #import 11 | #import 12 | 13 | @implementation NSString (Encrypt) 14 | 15 | -(NSString *)base64AfterSha256WithKey:(NSString *)key{ 16 | 17 | const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; 18 | const char *cData = [self cStringUsingEncoding:NSASCIIStringEncoding]; 19 | unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH]; 20 | CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC); 21 | NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)]; 22 | NSString * base64String = [HMACData base64EncodedStringWithOptions:0]; 23 | return base64String; 24 | } 25 | @end 26 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/NSString+MD5Encrypt.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+MD5Encrypt.h 3 | // Pods 4 | // 5 | // Created by jw on 6/24/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (MD5Encrypt) 12 | - (NSString*)encryptedMD5; 13 | - (NSString*)decryptedMD5; 14 | @end 15 | 16 | 17 | NSArray* DESKeyEncrypt(NSString* key); 18 | 19 | NSString* DESKeyDecrypt(NSArray* arr); 20 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/NSString+Path.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Path.h 3 | // Pods 4 | // 5 | // Created by jw on 6/22/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (Path) 12 | 13 | + (NSString*)documentPath; 14 | 15 | - (NSString*)stringWithPathRelativeTo:(NSString*)anchorPath; 16 | @end 17 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/Utils/NSString+Path.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Path.m 3 | // Pods 4 | // 5 | // Created by jw on 6/22/16. 6 | // 7 | // 8 | 9 | #import "NSString+Path.h" 10 | 11 | @implementation NSString (Path) 12 | 13 | + (NSString*)documentPath 14 | { 15 | static NSString* documentPath; 16 | static dispatch_once_t onceToken; 17 | dispatch_once(&onceToken, ^{ 18 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 19 | documentPath = [paths objectAtIndex:0]; 20 | }); 21 | return documentPath; 22 | } 23 | 24 | //计算相对路径 25 | - (NSString*)stringWithPathRelativeTo:(NSString*)anchorPath { 26 | NSArray *pathComponents = [self pathComponents]; 27 | NSArray *anchorComponents = [anchorPath pathComponents]; 28 | 29 | NSInteger componentsInCommon = MIN([pathComponents count], [anchorComponents count]); 30 | for (NSInteger i = 0, n = componentsInCommon; i < n; i++) { 31 | if (![[pathComponents objectAtIndex:i] isEqualToString:[anchorComponents objectAtIndex:i]]) { 32 | componentsInCommon = i; 33 | break; 34 | } 35 | } 36 | 37 | NSUInteger numberOfParentComponents = [anchorComponents count] - componentsInCommon; 38 | NSUInteger numberOfPathComponents = [pathComponents count] - componentsInCommon; 39 | 40 | NSMutableArray *relativeComponents = [NSMutableArray arrayWithCapacity: 41 | numberOfParentComponents + numberOfPathComponents]; 42 | for (NSInteger i = 0; i < numberOfParentComponents; i++) { 43 | [relativeComponents addObject:@".."]; 44 | } 45 | [relativeComponents addObjectsFromArray: 46 | [pathComponents subarrayWithRange:NSMakeRange(componentsInCommon, numberOfPathComponents)]]; 47 | return [NSString pathWithComponents:relativeComponents]; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/WebViewProtocol/CCWebViewProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCWebViewProtocol.h 3 | // Pods 4 | // 5 | // Created by 小丸子 on 7/6/2016. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @class CCWebViewProtocol; 12 | 13 | /* 14 | * 此protocol定义了获取cacheData的接口 15 | */ 16 | @protocol CCWebViewProtocolDelegate 17 | 18 | @required 19 | 20 | /** 21 | * 获取指定url资源的本地缓存数据。delegate必须实现此接口 22 | * 23 | * @param protocol CCWebViewProtocol实例对象 24 | * @param requestURL 被请求资源的url 25 | * 26 | * @return 资源的本地缓存数据。 如果本地没有缓存数据,则为nil,表明需要向网络请求资源 27 | */ 28 | -(NSData *)dataForWebViewProtocolWithURL:(NSString *)requestURL; 29 | 30 | /** 31 | * 代理是否能响应url 32 | * 33 | * @param requestURL 被请求资源的url 34 | * 35 | * @return YES or NO 36 | */ 37 | -(BOOL)canWebViewProtocolResponseURL:(NSString *)requestURL; 38 | 39 | @end; 40 | 41 | @interface CCWebViewProtocol : NSURLProtocol 42 | 43 | /* 44 | * 设置单例的delegate对象 45 | */ 46 | +(void)setWebViewProtocolDelegate:(nonnull id)webViewDelegate; 47 | 48 | @end 49 | 50 | -------------------------------------------------------------------------------- /src/CCCandyWebCache/WebViewProtocol/CCWebViewProtocol.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCWebViewProtocol.m 3 | // Pods 4 | // 5 | // Created by 小丸子 on 7/6/2016. 6 | // 7 | // 8 | 9 | #import "CCWebViewProtocol.h" 10 | #import "HTFileDownloader+MD5.h" 11 | #import "CCLogger.h" 12 | 13 | static id webViewProtocolDelegate; 14 | // test code 15 | //static NSString * const MyURLProtocolHandledKey = @"MyURLProtocolHandledKey"; 16 | 17 | @interface CCWebViewProtocol() 18 | 19 | @property (nonatomic, strong) NSMutableData * cacheData; 20 | @property (nonatomic, strong) NSURLSession * session; 21 | @property (nonatomic, strong) NSURLSessionDataTask * downloadTask; 22 | 23 | @end 24 | 25 | @implementation CCWebViewProtocol 26 | 27 | - (NSURLSession *)session { 28 | 29 | if (!_session) { 30 | _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil]; 31 | } 32 | return _session; 33 | } 34 | 35 | +(void)setWebViewProtocolDelegate:(id)webViewDelegate{ 36 | 37 | webViewProtocolDelegate = webViewDelegate; 38 | } 39 | 40 | #pragma mark - test 41 | - (NSString *)filePathWithUrlString:(NSString *)urlString { 42 | 43 | NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 44 | NSString *fileName = [urlString MD5]; 45 | return [cachesPath stringByAppendingPathComponent:fileName]; 46 | } 47 | 48 | 49 | #pragma mark - override 50 | 51 | +(BOOL)canInitWithRequest:(NSURLRequest *)request{ 52 | // 判断是否拦截请求 53 | if (webViewProtocolDelegate && [webViewProtocolDelegate respondsToSelector:@selector(canWebViewProtocolResponseURL:)]) { 54 | return [webViewProtocolDelegate canWebViewProtocolResponseURL:[request.URL absoluteString]]; 55 | }else{ 56 | return NO; 57 | } 58 | // for test 59 | /*if ([NSURLProtocol propertyForKey:MyURLProtocolHandledKey inRequest:request]) { 60 | return NO; 61 | } 62 | 63 | return YES;*/ 64 | } 65 | 66 | + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { 67 | 68 | return request; 69 | } 70 | 71 | + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b { 72 | 73 | return [super requestIsCacheEquivalent:a toRequest:b]; 74 | } 75 | 76 | -(void)startLoading{ 77 | 78 | // 再次获取cacheData 79 | NSURL * url = self.request.URL; 80 | NSData * cacheData = nil; 81 | if ([webViewProtocolDelegate respondsToSelector:@selector(dataForWebViewProtocolWithURL:)]) { 82 | 83 | cacheData = [webViewProtocolDelegate dataForWebViewProtocolWithURL:[url absoluteString]]; 84 | if (cacheData == nil) { 85 | 86 | // 发送网络请求 87 | //NSLog(@"---response through network: %@", url.absoluteString); 88 | self.downloadTask = [self.session dataTaskWithRequest:self.request]; 89 | [self.downloadTask resume]; 90 | } 91 | else{ 92 | // TODO: 考虑response header的问题 93 | //NSLog(@"+++reponse from cache:%@", url.absoluteString); 94 | NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc] 95 | initWithURL:url 96 | statusCode:200 97 | HTTPVersion:@"HTTP/1.1" 98 | headerFields:[NSDictionary dictionary]]; 99 | 100 | [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; 101 | [self.client URLProtocol:self didLoadData:cacheData]; 102 | [self.client URLProtocolDidFinishLoading:self]; 103 | } 104 | } 105 | 106 | } 107 | 108 | -(void)stopLoading{ 109 | 110 | [self.downloadTask cancel]; 111 | self.downloadTask = nil; 112 | } 113 | 114 | - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { 115 | 116 | [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; 117 | // 允许处理服务器的响应,才会继续接收服务器返回的数据 118 | completionHandler(NSURLSessionResponseAllow); 119 | /******* test code *******/ 120 | self.cacheData = [NSMutableData data]; 121 | /*************************/ 122 | } 123 | 124 | -(void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveData:(nonnull NSData *)data{ 125 | 126 | [self.client URLProtocol:self didLoadData:data]; 127 | /******* test code *******/ 128 | [self.cacheData appendData:data]; 129 | /*************************/ 130 | } 131 | 132 | - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { 133 | // 下载完成之后的处理 134 | if (error) { 135 | [self.client URLProtocol:self didFailWithError:error]; 136 | } else { 137 | //将数据存入到本地文件中 138 | /******* test code *******/ 139 | [self.cacheData writeToFile:[self filePathWithUrlString:self.request.URL.absoluteString] atomically:YES]; 140 | /*************************/ 141 | [self.client URLProtocolDidFinishLoading:self]; 142 | } 143 | } 144 | 145 | @end 146 | -------------------------------------------------------------------------------- /src/HTFileDownloader/HTDBManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTDBManager.h 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 2/6/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "HTFileTransferItem.h" 12 | 13 | typedef NS_ENUM(NSUInteger, DB_ACTION) 14 | { 15 | DB_UPDATE = 0, 16 | DB_INSERT, 17 | DB_DELETE, 18 | DB_UPDATE_OR_INSERT 19 | }; 20 | 21 | @interface HTDBManager : NSObject 22 | 23 | /** 24 | * 构造函数 25 | * 26 | * @param dbPath 数据库保存路径 27 | * 28 | * @return HTDBManager实例对象 29 | */ 30 | -(nonnull instancetype)initDatabaseWithPath:(nullable NSString *)dbPath; 31 | 32 | /** 33 | * 创建数据库,创建downloadItems表 34 | * 35 | * @return YES:创建成功 NO:失败 36 | */ 37 | -(BOOL)createDatabase; 38 | 39 | /** 40 | * 更新一条记录,如果该记录不存在,则插入;反之,更新 41 | * 42 | * @param item 要更新的数据 43 | */ 44 | -(void)updateOrInsertDownloadItem:(nonnull HTFileTransferItem *)item; 45 | 46 | /** 47 | * 异步插入一条新的downloadItem 48 | * 49 | * @param item 要插入的downloadItems 50 | * 51 | * @return YES: 插入成功, NO: 插入失败 52 | */ 53 | -(BOOL)insertNewDownloadItem:(nonnull HTFileTransferItem *)item; 54 | 55 | /** 56 | * 异步更新一条downloadItem 57 | * 58 | * @param item 要更新的downloadItem 59 | * 60 | * @return YES: 更新成功, NO: 更新失败 61 | */ 62 | -(BOOL)updateDownloadItem:(nonnull HTFileTransferItem *)item; 63 | 64 | /** 65 | * 异步删除一条downloadItem 66 | * 67 | * @param item 要删除的downloadItem 68 | * 69 | * @return YES: 删除成功, NO: 删除失败 70 | */ 71 | -(BOOL)deleteDownloadItem:(nonnull HTFileTransferItem *)item; 72 | 73 | /** 74 | * 异步删除所有的downloadItems 75 | * 76 | * @return YES: 删除成功, NO: 删除失败 77 | */ 78 | -(BOOL)deleteAllDownloadItems; 79 | 80 | /** 81 | * 异步清理过期的downloadItems。默认expire时间为一周:7 * 24 * 3600。 82 | * 83 | * @return YES: 删除成功, NO: 删除失败 84 | */ 85 | -(BOOL)deleteExpiredDownloadItems; 86 | 87 | /** 88 | * 查询downloadItem 89 | * 90 | * @param downloadId 91 | * 92 | * @return downloadItem 93 | */ 94 | -(nullable HTFileTransferItem *)downloadItemWithDownloadId:(nonnull NSString *)downloadId; 95 | 96 | /** 97 | * 查询downloadItem的状态 98 | * 99 | * @param downloadId 要查询记录的ID 100 | * 101 | * @return downloadItem的状态值 102 | */ 103 | -(HTFileTransferState)downloadItemStatus:(nonnull NSString *)downloadId; 104 | 105 | /** 106 | * 查询所有的downloadItems 107 | * 108 | * @return downloadItems集合 109 | */ 110 | -(nullable NSArray *)allDownloadItems; 111 | 112 | /** 113 | * 查询所有suspended、failed的downloadItems 114 | * 115 | * @return downloadItems集合(suspended,failed) 116 | */ 117 | -(nullable NSArray *)allSuspendedOrFailedDownloadItems; 118 | 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFDLogger.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTFDLogger.h 3 | // Pods 4 | // 5 | // Created by jw on 6/23/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #define HTFDLOGVerbose @"V" 12 | #define HTFDLOGTest @"T" 13 | #define HTFDLOGInfo @"I" 14 | #define HTFDLOGDebug @"D" 15 | #define HTFDLOGWarn @"W" 16 | #define HTFDLOGError @"E" 17 | 18 | #define HTFDLogVerbose(...) HTFDLog(HTFDLoggerLevelVerbose, HTFDLOGVerbose __FILE__, __LINE__, __VA_ARGS__) 19 | #define HTFDLogTest(...) HTFDLog(HTFDLoggerLevelTest, HTFDLOGTest, __FILE__, __LINE__, __VA_ARGS__) 20 | #define HTFDLogInfo(...) HTFDLog(HTFDLoggerLevelInfo, HTFDLOGInfo, __FILE__, __LINE__, __VA_ARGS__) 21 | #define HTFDLogDebug(...) HTFDLog(HTFDLoggerLevelDebug,HTFDLOGDebug, __FILE__, __LINE__, __VA_ARGS__) 22 | #define HTFDLogWarn(...) HTFDLog(HTFDLoggerLevelWarning, HTFDLOGWarn, __FILE__, __LINE__, __VA_ARGS__) 23 | #define HTFDLogError(...) HTFDLog(HTFDLoggerLevelError,HTFDLOGError, __FILE__, __LINE__,__VA_ARGS__) 24 | 25 | typedef NS_ENUM(NSInteger,HTFDLoggerLevel) 26 | { 27 | HTFDLoggerLevelVerbose = 1, 28 | HTFDLoggerLevelTest, 29 | HTFDLoggerLevelInfo, 30 | HTFDLoggerLevelDebug, 31 | HTFDLoggerLevelWarning, 32 | HTFDLoggerLevelError 33 | }; 34 | 35 | @interface HTFDLogger : NSObject 36 | 37 | + (void)setEnable:(BOOL)enable; 38 | 39 | + (void)setLogLevel:(HTFDLoggerLevel)level; 40 | 41 | @end 42 | 43 | 44 | void HTFDLog(HTFDLoggerLevel level,NSString * levelDescription, const char *fname, int lineno,NSString* formatString, ...); -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFDLogger.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTFDLog.m 3 | // Pods 4 | // 5 | // Created by jw on 6/23/16. 6 | // 7 | // 8 | 9 | #import "HTFDLogger.h" 10 | 11 | static HTFDLoggerLevel gLogLevel = HTFDLoggerLevelDebug; 12 | static BOOL gLogEnable = NO; 13 | 14 | @implementation HTFDLogger 15 | 16 | + (void)setEnable:(BOOL)enable 17 | { 18 | gLogEnable = enable; 19 | } 20 | 21 | + (void)setLogLevel:(HTFDLoggerLevel)level 22 | { 23 | gLogLevel = level; 24 | } 25 | 26 | 27 | @end 28 | 29 | void HTFDLog(HTFDLoggerLevel level, NSString * levelString, const char *fname, int lineno,NSString* formatString, ...) 30 | { 31 | if (gLogEnable && level >= gLogLevel) { 32 | va_list args; 33 | va_start(args, formatString); 34 | NSString* filename = [NSString stringWithUTF8String:fname]; 35 | NSLog(@"[%@]:%@_%d %@",levelString, [filename lastPathComponent],lineno,[[NSString alloc] initWithFormat:formatString arguments:args]); 36 | va_end(args); 37 | } 38 | } -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFDThreadSafeMutableDictionary.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTFDThreadSafeMutableDictionary.h 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 6/7/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HTFDThreadSafeMutableDictionary : NSMutableDictionary 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFDThreadSafeMutableDictionary.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTFDThreadSafeMutableDictionary.m 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 6/7/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import "HTFDThreadSafeMutableDictionary.h" 10 | 11 | #import 12 | #import 13 | 14 | #define LOCKED(...) do { \ 15 | OSSpinLockLock(&_lock); \ 16 | __VA_ARGS__; \ 17 | OSSpinLockUnlock(&_lock); \ 18 | } while (NO) 19 | 20 | @interface HTFDThreadSafeMutableDictionary() 21 | @property (nonatomic, assign) OSSpinLock lock; 22 | @property (nonatomic, copy) NSMutableDictionary* dictionary; 23 | @end 24 | 25 | @implementation HTFDThreadSafeMutableDictionary { 26 | 27 | 28 | } 29 | 30 | /////////////////////////////////////////////////////////////////////////////////////////// 31 | #pragma mark - NSObject 32 | 33 | - (id)init { 34 | if ((self = [super init])) { 35 | _dictionary = [[NSMutableDictionary alloc] init]; 36 | _lock = OS_SPINLOCK_INIT; 37 | } 38 | return self; 39 | } 40 | 41 | - (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys { 42 | if ((self = [self initWithCapacity:objects.count])) { 43 | [objects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 44 | _dictionary[keys[idx]] = obj; 45 | }]; 46 | } 47 | return self; 48 | } 49 | 50 | - (id)initWithCapacity:(NSUInteger)capacity { 51 | if ((self = [super init])) { 52 | _dictionary = [[NSMutableDictionary alloc] initWithCapacity:capacity]; 53 | _lock = OS_SPINLOCK_INIT; 54 | } 55 | return self; 56 | } 57 | 58 | /////////////////////////////////////////////////////////////////////////////////////////// 59 | #pragma mark - NSMutableDictionary 60 | 61 | - (void)setObject:(id)anObject forKey:(id)aKey { 62 | LOCKED(_dictionary[aKey] = anObject); 63 | } 64 | 65 | - (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary { 66 | LOCKED([_dictionary addEntriesFromDictionary:otherDictionary]); 67 | } 68 | 69 | - (void)setDictionary:(NSDictionary *)otherDictionary { 70 | LOCKED([_dictionary setDictionary:otherDictionary]); 71 | } 72 | 73 | - (void)removeObjectForKey:(id)aKey { 74 | LOCKED([_dictionary removeObjectForKey:aKey]); 75 | } 76 | 77 | - (void)removeAllObjects { 78 | LOCKED([_dictionary removeAllObjects]); 79 | } 80 | 81 | - (NSUInteger)count { 82 | NSUInteger count; 83 | LOCKED(count = _dictionary.count); 84 | return count; 85 | } 86 | 87 | - (NSArray *)allKeys { 88 | NSArray *allKeys; 89 | LOCKED(allKeys = _dictionary.allKeys); 90 | return allKeys; 91 | } 92 | 93 | - (NSArray *)allValues { 94 | NSArray *allValues; 95 | LOCKED(allValues = _dictionary.allValues); 96 | return allValues; 97 | } 98 | 99 | - (id)objectForKey:(id)aKey { 100 | id obj; 101 | LOCKED(obj = _dictionary[aKey]); 102 | return obj; 103 | } 104 | 105 | - (NSEnumerator *)keyEnumerator { 106 | NSEnumerator *keyEnumerator; 107 | LOCKED(keyEnumerator = [_dictionary keyEnumerator]); 108 | return keyEnumerator; 109 | } 110 | 111 | - (id)copyWithZone:(NSZone *)zone { 112 | return [self mutableCopyWithZone:zone]; 113 | } 114 | 115 | - (id)mutableCopyWithZone:(NSZone *)zone { 116 | id copiedDictionary; 117 | LOCKED(copiedDictionary = [[self.class allocWithZone:zone] initWithDictionary:_dictionary]); 118 | return copiedDictionary; 119 | } 120 | 121 | - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state 122 | objects:(id __unsafe_unretained [])stackbuf 123 | count:(NSUInteger)len { 124 | OSSpinLockLock(&_lock); 125 | 126 | NSDictionary *enumerationDict = objc_getAssociatedObject(self, &stackbuf); 127 | if (!enumerationDict) { 128 | objc_setAssociatedObject(self, &stackbuf, (enumerationDict = _dictionary.copy), OBJC_ASSOCIATION_RETAIN); 129 | } 130 | 131 | NSUInteger count = [enumerationDict countByEnumeratingWithState:state objects:stackbuf count:len]; 132 | 133 | if (!count) { 134 | objc_setAssociatedObject(self, &stackbuf, nil, OBJC_ASSOCIATION_RETAIN); 135 | } 136 | 137 | OSSpinLockUnlock(&_lock); 138 | 139 | return count; 140 | } 141 | 142 | - (void)performLockedWithDictionary:(void (^)(NSDictionary *dictionary))block { 143 | if (block) 144 | LOCKED(block(_dictionary)); 145 | } 146 | 147 | - (BOOL)isEqual:(id)object { 148 | if (object == self) return YES; 149 | 150 | if ([object isKindOfClass:HTFDThreadSafeMutableDictionary.class]) { 151 | HTFDThreadSafeMutableDictionary *other = object; 152 | __block BOOL isEqual = NO; 153 | [other performLockedWithDictionary:^(NSDictionary *dictionary) { 154 | [self performLockedWithDictionary:^(NSDictionary *otherDictionary) { 155 | isEqual = [dictionary isEqual:otherDictionary]; 156 | }]; 157 | }]; 158 | return isEqual; 159 | } 160 | return NO; 161 | } 162 | 163 | - (NSUInteger)hash 164 | { 165 | NSUInteger hash; 166 | LOCKED(hash = [super hash]); 167 | return hash; 168 | } 169 | 170 | @end -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFileDownloadTask.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTFileDownloadTask.h 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 26/5/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "HTFileTransferConst.h" 11 | 12 | @protocol HTFileDownloadTaskDelegate; 13 | @class HTFileDownloader; 14 | @class HTFileTransferItem; 15 | 16 | @interface HTFileDownloadTask : NSObject 17 | 18 | /* 19 | * 优先级 20 | */ 21 | @property (nonatomic, assign) float priority; 22 | 23 | /* 24 | * task相关的数据信息,(readonly) 25 | */ 26 | @property (nonatomic, strong, nullable) HTFileTransferItem * downloadTaskData; 27 | 28 | /* 29 | * urlsession dataTask 对象 30 | */ 31 | @property (nonatomic, strong, nullable) NSURLSessionDataTask * sessionDataTask; 32 | 33 | /* 34 | * 资源本地存储路径 35 | */ 36 | @property (nonatomic, strong, nullable) NSString * fullDownloadPath; 37 | 38 | /* 39 | * 临时存储路径 40 | */ 41 | @property (nonatomic, strong, nullable) NSString * tmpFullDownloadPath; 42 | 43 | /* 44 | * downloader对象 45 | */ 46 | @property (nonatomic, weak, nullable) HTFileDownloader * fileDownloader; 47 | 48 | /* 49 | * 代理对象 50 | */ 51 | @property (nonatomic, nullable) id downloadTaskDelegate; 52 | 53 | /* 54 | * 任务start入口 55 | */ 56 | -(void)resume; 57 | 58 | /* 59 | * 暂停任务。被暂停的任务可以调用resume,继续下载 60 | */ 61 | -(void)suspend; 62 | 63 | /* 64 | * 取消任务。被取消的任务(删除),不被downloader继续管理,所以的数据信息也会被删除。被取消的任务不支持断点继续下载 65 | */ 66 | -(void)cancel; 67 | 68 | /** 69 | * 获取downloadTask的downloadID 70 | * 71 | * @return downloadID 72 | */ 73 | -(nonnull NSString *)downloadID; 74 | 75 | @end 76 | 77 | 78 | @protocol HTFileDownloadTaskDelegate 79 | @optional 80 | 81 | /** 82 | * cutomize 请求header或body. 可通过此方法设置额外的header或body. 83 | * 84 | * @param downloadTask 下载任务对象 85 | * @param request 当前request对象 86 | * 87 | * @return 定制后的request对象 88 | */ 89 | -(nonnull NSMutableURLRequest *)HTFileDownloadTask:(nonnull HTFileDownloadTask *)downloadTask customizeRequest:(nonnull NSMutableURLRequest *)request; 90 | 91 | /** 92 | * 任务出错回调 93 | * 94 | * @param downloadTask 当前fail的task对象,包含失败时刻task的下载状态、进度 95 | * @param error 下载出错信息,错误类型:client-error, server-error, local-error 96 | * @Info: 使用者可以根据错误类型选择性尝试重新下载。eg:如果是client-error:connection lost,可以检测网络正常连接后再尝试重新下载 97 | */ 98 | -(void)HTFileDownloadTask:(nonnull HTFileDownloadTask *)downloadTask didFailedWithError:(nonnull NSError *)error; 99 | 100 | /** 101 | * 任务resume失败 102 | * 103 | * @param downloadTask 失败的task对象 104 | * @param error 出错信息 105 | * @Info:提供默认的处理方式,重新构建新的request,从新开始下载。 106 | */ 107 | -(void)HTFileDownloadTask:(nonnull HTFileDownloadTask *)downloadTask didResumeFailedWithError:(nonnull NSError *)error; 108 | 109 | /** 110 | * 使用者判断httpStatus,决定是否存在server response error。 111 | * 112 | * @prarm httpStatusCode response中获取的return code. 113 | * @Info: 默认的判断200-299都是合法的return code. 否则,存在server error. 114 | */ 115 | -(BOOL)HTFileDownloadTask:(nonnull HTFileDownloadTask*)downloadTask isInvalidForHttpStatusCode:(NSInteger)httpStatusCode; 116 | 117 | /** 118 | * <#Description#> 119 | * 120 | * @param downloadTask <#downloadTask description#> 121 | * @param challenge <#challenge description#> 122 | * @param credential <#credential description#> 123 | * 124 | * @return <#return value description#> 125 | */ 126 | -(NSURLSessionAuthChallengeDisposition)HTFileDownloadTask:(nonnull HTFileDownloadTask*)downloadTask 127 | didReceiveAuthenticationChanllenge:(nonnull NSURLAuthenticationChallenge *)challenge 128 | withCredential:(NSURLCredential **)credential; 129 | 130 | 131 | /** 132 | * 进度更新回调 133 | */ 134 | -(void)HTFileDownloadTask:(nonnull HTFileDownloadTask *)downloadTask 135 | didUpdatedWithProgress:(CGFloat)progress 136 | receivedSize:(NSInteger)receivedSize 137 | totalSizeExpected:(NSInteger) totalSizeExpected 138 | totalSizeReceived:(NSInteger) totalSizeReceived; 139 | 140 | /** 141 | * 下载任务成功结束回调。 142 | */ 143 | -(void)didFinishSuccessWithDownloadTask:(nonnull HTFileDownloadTask *)downloadTask; 144 | 145 | /** 146 | * 任务中止回调。 147 | */ 148 | -(void)didPausedWithDownloadTask:(nonnull HTFileDownloadTask *)downloadTask; 149 | 150 | /** 151 | * 任务取消回调 152 | */ 153 | -(void)didCancelledWithDownloadTask:(nonnull HTFileDownloadTask *)downloadTask; 154 | 155 | /** 156 | * 任务开始回调 157 | */ 158 | -(void)didStartedWithDownloadTask:(nonnull HTFileDownloadTask *)downloadTask; 159 | 160 | 161 | 162 | 163 | @end 164 | -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFileDownloadTask.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTFileDownloadTask.m 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 26/5/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import "HTFileDownloadTask.h" 10 | #import "HTFileDownloader.h" 11 | #import "HTFileDownloader+Private.h" 12 | #import 13 | 14 | @interface HTFileDownloadTask() 15 | 16 | @end 17 | 18 | @implementation HTFileDownloadTask 19 | 20 | - (void)dealloc { 21 | } 22 | 23 | -(void)resume 24 | { 25 | [self.fileDownloader startWithDownloadTask:self]; 26 | } 27 | 28 | -(void)suspend 29 | { 30 | [self.fileDownloader suspendWithDownloadTask:self]; 31 | } 32 | 33 | -(void)cancel 34 | { 35 | [self.fileDownloader deleteWithDownloadTask:self]; 36 | } 37 | 38 | -(nonnull NSString *)downloadID 39 | { 40 | return self.downloadTaskData.downloadId; 41 | } 42 | 43 | @end 44 | 45 | -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFileDownloader+MD5.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTFileDownloader+MD5.h 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 17/6/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import "HTFileDownloader.h" 10 | 11 | @interface NSData (MD5) 12 | - (NSString *)MD5; 13 | @end 14 | 15 | @interface NSString (MD5) 16 | - (NSString *)MD5; 17 | @end -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFileDownloader+MD5.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTFileDownloader+MD5.m 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 17/6/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import "HTFileDownloader+MD5.h" 10 | #import 11 | 12 | @implementation NSData (MD5) 13 | 14 | - (NSString *)MD5{ 15 | 16 | 17 | // Create byte array of unsigned chars 18 | unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH]; 19 | 20 | // Create 16 byte MD5 hash value, store in buffer 21 | CC_MD5(self.bytes, (unsigned int)self.length, md5Buffer); 22 | 23 | // Convert unsigned char buffer to NSString of hex values 24 | NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; 25 | for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) 26 | [output appendFormat:@"%02x",md5Buffer[i]]; 27 | 28 | return output; 29 | } 30 | @end 31 | 32 | @implementation NSString (MD5) 33 | 34 | - (NSString *)MD5{ 35 | 36 | // Create byte array of unsigned chars 37 | unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH]; 38 | 39 | // Create 16 byte MD5 hash value, store in buffer 40 | CC_MD5(self.UTF8String, (unsigned int)self.length, md5Buffer); 41 | 42 | // Convert unsigned char buffer to NSString of hex values 43 | NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; 44 | for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) 45 | [output appendFormat:@"%02x",md5Buffer[i]]; 46 | 47 | return output; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFileDownloader+Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTFileDownloader+Private.h 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 31/5/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import "HTFileDownloader.h" 10 | 11 | @interface HTFileDownloader (Private) 12 | 13 | 14 | -(void)startWithDownloadTask:(nonnull HTFileDownloadTask *)downloadTask; 15 | 16 | -(void)suspendWithDownloadTask:(nonnull HTFileDownloadTask *)downloadTask; 17 | 18 | -(void)deleteWithDownloadTask:(nonnull HTFileDownloadTask *)downloadTask; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFileDownloader.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTFileDownloader.h 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 23/5/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "HTFileDownloadTask.h" 11 | #import "HTFileTransferItem.h" 12 | 13 | @class HTFileDownloader; 14 | 15 | @protocol HTFileDownloaderDelegate 16 | 17 | @optional 18 | 19 | /* 20 | * Optionally customize the background session configuration. 21 | */ 22 | -(void)HTFileDownloader:(nonnull HTFileDownloader*)fileDownloader customizeBackgroundSessionConfiguration:(nonnull NSURLSessionConfiguration*)backgroundSessionConfiguration; 23 | 24 | 25 | -(NSURLSessionAuthChallengeDisposition)HTFileDownloader:(nonnull HTFileDownloader*)fielDownloader 26 | didReceiveAuthenticationChallenge:(nonnull NSURLAuthenticationChallenge *)challenge 27 | withCredential:(NSURLCredential **)credential; 28 | 29 | @end 30 | 31 | @interface HTFileDownloader : NSObject 32 | 33 | /* 34 | * 最大并发数。不设置则采用默认设置:6 35 | */ 36 | @property (nonatomic, assign) NSInteger maxConcurrentDownloadsCount; 37 | 38 | /* 39 | * 下载根路径。只能在创建downloader时设置,如果不设置,则使用默认路径 40 | */ 41 | @property (nonatomic, strong, readonly, nonnull) NSString * rootDownloadPath; 42 | 43 | /** 44 | * 定制的headers.基于downloader的所有下载请求都共享些headers。但是对于同一header项,如果单个下载请求也进行了设置,则单个请求所设置的header优先级较高 45 | */ 46 | @property (nonatomic, strong, readonly, nullable) NSDictionary * httpAdditionalHeaders; 47 | 48 | 49 | /** Attention: 同时只能存在一种类型的downloader**/ 50 | 51 | /* 52 | * 创建并初始化backgroundSession,支持后台下载 (暂时勿用) 53 | * 54 | * @param: delegate, HTFileDownloaderDelegate的delegate对象, 55 | * @param: downloadPathUrl配置的下载路径,可以为空,为空的话,采用默认的下载路径 56 | * @param: httpAdditionalHeaders配置基于此downloader所有task的额外的header 57 | */ 58 | 59 | -(nullable instancetype)initBackgroundDownloaderWithDelegate:(nullable id)aDelegate 60 | withDownloadPath:(nullable NSString *)rootDownloadPath 61 | withAdditionalHeaders:(nullable NSDictionary*)httpAdditionalHeaders; 62 | /** 63 | * 创建defaultSession,不支持后台下载 64 | * 65 | * @param delegate, HTFileDownloaderDelegate对象 66 | * @param downloadPathUrl, 设置的下载路径,如果不设置,NSHomeDirectory()/HTFileDownlader/ 67 | * @param: httpAdditionalHeaders配置基于此downloader所有task的额外的header 68 | */ 69 | 70 | -(nullable instancetype)initStandardDownloaderWithDelegate:(nullable id)delegate 71 | withDownloadPath:(nullable NSString *)rootDownloadPath 72 | withAdditioanlHeaders:(nullable NSDictionary *)httpAdditionalHeaders; 73 | /** 74 | * 根据url构造downloadTask 75 | * 76 | * @param url 下载资源的url 77 | * @param delegate downloadTask代理对象 78 | * 79 | * @return downloadTask对象 80 | */ 81 | -(nullable HTFileDownloadTask *)downloadTaskWithUrl:(nullable NSURL *)url 82 | withDelegate:(nullable id)delegate; 83 | 84 | /** 85 | * 通过HTFileTransferItem对象创建downloadTask, 此类task主要用于重建上次未完成的任务 86 | * 87 | * @param downloadItem 用来构造task的item对象, 88 | * @param delegate downloadTask代理对象 89 | * 90 | * @return downloadTask对象 91 | */ 92 | -(nullable HTFileDownloadTask *)downloadTaskWithDownloadItem:(nullable HTFileTransferItem *)downloadItem 93 | withDelegate:(nullable id)delegate; 94 | 95 | 96 | /** 97 | * 获取所有保存记录的downloadItems,包括已完成的和未完成的 98 | * 99 | * @return 所有记录的downloadItems集合 100 | */ 101 | -(nonnull NSArray *)downloadItems; 102 | 103 | 104 | /** 105 | * 获取上次未完成的所有downloadItems对象。所有的downloadItem对象中包含断点续传的信息。使用者再获取这些items后, 106 | * 可以调用downloadTaskWithDownloadItem方法,创建task,通过调用resume方法,可以进行断点续传。 107 | * 108 | * @return 上次未完成的所有downloadItems对象 109 | */ 110 | -(nullable NSArray*)suspendedOrFailedItems; 111 | 112 | /** 113 | * 暂停当前所有downloadItems; 114 | */ 115 | -(void)suspendedAllDownloadItems; 116 | 117 | 118 | @end 119 | -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFileTransferConst.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTFileTransferConst.h 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 27/5/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #ifndef HTFileTransferConst_h 10 | #define HTFileTransferConst_h 11 | 12 | #import 13 | 14 | typedef NS_ENUM(NSInteger, HTFileTransferState) 15 | { 16 | HTFileTransferStateNone = 0, 17 | HTFileTransferStateReady, // 18 | HTFileTransferStateWaiting, //等待 19 | HTFileTransferStateTransfering, //正在transfer 20 | HTFileTransferStatePaused, //任务中止 21 | HTFileTransferStateCancelled, //任务被取消 22 | HTFileTransferStateDone, //任务成功结束 23 | HTFileTransferStateFailed //任务失败 24 | }; 25 | 26 | #endif /* HTFileTransferConst_h */ 27 | -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFileTransferItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTFileTransferItem.h 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 26/5/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "HTFileTransferConst.h" 11 | 12 | @interface HTFileTransferItem : NSObject 13 | 14 | // downloadTask的ID, 15 | @property (nonatomic, strong, nonnull) NSString * downloadId; 16 | 17 | // 下载目标url 18 | @property (nonatomic, strong, nonnull) NSURL * url; 19 | 20 | // 下载状态 21 | @property (nonatomic, assign) HTFileTransferState status; 22 | 23 | /* 24 | * 文件总大小 25 | */ 26 | @property (nonatomic, assign) NSInteger totalContentLength; 27 | 28 | /* 29 | * 文件已接收大小 30 | */ 31 | @property (nonatomic, assign) NSInteger totalReceivedContentLength; 32 | 33 | /* 34 | * 文件下载进度 35 | */ 36 | @property (nonatomic, assign) CGFloat progress; 37 | 38 | /* 39 | * 临时文件名 40 | */ 41 | @property (nonatomic, strong, nullable) NSString * tempFileName; 42 | 43 | /* 44 | * 文件名 45 | */ 46 | @property (nonatomic, strong, nullable) NSString * fileName; 47 | 48 | /* 49 | * 下载内容的md5值,用于断点续传的完整性校验(暂时不用) 50 | */ 51 | @property (nonatomic, strong, nullable) NSString * md5; 52 | 53 | /** 54 | * 下载首次开始的时间。会根据此时间值清理数据库。 55 | */ 56 | @property (nonatomic, assign) NSInteger startDownloadTime; 57 | 58 | 59 | // http status 60 | @property (nonatomic, assign) NSInteger lastHttpStatusCode; 61 | 62 | // 错误的message信息 63 | @property (nonatomic, strong, nullable) NSString* errorMessageInfo; 64 | 65 | -(nullable HTFileTransferItem *)initWithUrl:(nonnull NSURL *)url; 66 | 67 | -(id) copyWithZone:(NSZone *)zone; 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /src/HTFileDownloader/HTFileTransferItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTFileTransferItem.m 3 | // HTFileDownloader 4 | // 5 | // Created by 小丸子 on 26/5/2016. 6 | // Copyright © 2016 hehui. All rights reserved. 7 | // 8 | 9 | #import "HTFileTransferItem.h" 10 | 11 | @interface HTFileTransferItem() 12 | 13 | @end 14 | 15 | @implementation HTFileTransferItem 16 | 17 | - (nullable HTFileTransferItem *)initWithUrl:(NSURL *)url 18 | { 19 | self = [super init]; 20 | if (self) { 21 | self.url = url; 22 | } 23 | 24 | return self; 25 | } 26 | 27 | -(id)copyWithZone:(NSZone *)zone{ 28 | 29 | HTFileTransferItem * item = [[HTFileTransferItem allocWithZone:zone]init]; 30 | item.downloadId = [_downloadId copy]; 31 | item.url = [_url copy]; 32 | item.status = _status; 33 | item.totalContentLength = _totalContentLength; 34 | item.totalReceivedContentLength = _totalReceivedContentLength; 35 | item.progress = _progress; 36 | item.tempFileName = [_tempFileName copy]; 37 | item.startDownloadTime = _startDownloadTime; 38 | item.fileName = _fileName; 39 | return item; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /src/VersionChecker/HTResourceVersionChecker.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCVersionChecker.h 3 | // Pods 4 | // 5 | // Created by 小丸子 on 7/6/2016. 6 | // 7 | // 8 | 9 | #import 10 | #import "HTResourceVersionInfo.h" 11 | 12 | typedef NS_ENUM(NSInteger, HTResourceType) 13 | { 14 | HTResourceTypeNone = 0, 15 | HTResourceTypeWebApp, 16 | HTResourceTypeHotfix 17 | }; 18 | 19 | @protocol HTResourceVersionCheckerDelegate; 20 | 21 | @interface HTResourceVersionChecker: NSObject 22 | 23 | /* 24 | * 请求VersionCheck的服务器地址 25 | */ 26 | @property (nonatomic, strong, nonnull) NSString * host; 27 | 28 | /* 29 | * 指定额外的request header, 使用者可以通过该属性自定义请求头部 30 | */ 31 | @property (nonatomic, strong, nullable) NSDictionary *HTTPAdditionalHeaders; 32 | 33 | /* 34 | * 指定额外的request body,使用者可以通过该属性设置自定义的request body 35 | */ 36 | @property (nonatomic, strong, nullable) NSString * userAdditionalData; 37 | 38 | /* 39 | * HTResourceVersionChecker的代理对象 40 | */ 41 | @property (nonatomic, weak) id versionCheckerDelegate; 42 | 43 | /* 44 | * 构造函数 45 | */ 46 | -(_Nonnull instancetype)initWithDelegate:(_Nullable id)delegate withHost:( NSString * _Nullable ) host; 47 | 48 | /* 49 | * 指定appInfo以及资源版本信息,使用者通过调用此接口对相关资源进行版本检查, check的结果通过代理对象返回 50 | * 51 | * @param: resourceType 检查版本的资源类型 52 | * @param: appId, native appID 53 | * @param: appVersion, native app version 54 | * @param: resInfos, 本地资源信息信息 55 | * @param: checkCompletionHandler, check结束回调 56 | */ 57 | -(void)checkVersionWithType:(NSInteger)resourceType 58 | appId:(nonnull NSString *)appId 59 | appVersion:(nonnull NSString *)appVersion 60 | resInfos:(nullable NSArray *)resInfos 61 | isDiff:(BOOL)isDiff 62 | isAutoFill:(BOOL)isAutoFill 63 | checkCompletionHandler:(void (^ _Nullable)(NSArray * __nullable versionInfoArray, NSError * __nullable error))checkCompletionHandler; 64 | 65 | 66 | @end 67 | 68 | 69 | @protocol HTResourceVersionCheckerDelegate 70 | 71 | @optional 72 | /* 73 | * 定义request 74 | * 75 | * @param:request, 当前构造的request. 76 | * @return: 返回定制后的request. 77 | * @Info: 可通过此接口添加request header和request body 78 | */ 79 | -(NSMutableURLRequest *)HTResourceVersionChecker:(nonnull HTResourceVersionChecker *)versionChecker 80 | customizeRequest:(nonnull NSMutableURLRequest *)request; 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /src/VersionChecker/HTResourceVersionInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTResourceVersionInfo.h 3 | // Pods 4 | // 5 | // Created by 小丸子 on 7/6/2016. 6 | // 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * HTResourceVersionCheckerState:定义对应WebApp的版本状态 13 | */ 14 | typedef NS_ENUM(NSInteger, HTResourceVersionCheckerState) 15 | { 16 | HTResourceVersionCheckerStateNone = -1, // 初始化状态 17 | HTResourceVersionCheckerStateLatest, // 本地app已最新 18 | HTResourceVersionCheckerStateNeedUpdate, // 需要更新 19 | HTResourceVersionCheckerStateNotExisted, // 资源不存在 20 | HTResourceVesrionCheckerStateAutoFillResource //请求中未携带资源信息,是自动补全资源信息 21 | }; 22 | 23 | /** 24 | * HTResourceVersionCheckerror:定义本次check/update返回的错误码 25 | */ 26 | typedef NS_ENUM(NSInteger, HTResourceVersionCheckerError) 27 | { 28 | HTResourceVersionCheckerSuccess = 200, 29 | HTResourceVersionCheckerErrorProtocolVersion = 401, // 协议版本不支持 30 | HTResourceVersionCheckerErrorAppID = 401, // appID不支持 31 | HTResourceVersionCheckerErrorServer = 501, // 服务端错误 32 | HTResourceVersionCheckerErrorUnknown //其他未知错误 33 | }; 34 | 35 | /** 36 | * HTResourceVersionInfo: 定义返回的版本信息的类对象结构 37 | */ 38 | @interface HTResourceVersionInfo : NSObject 39 | 40 | @property (nonatomic, strong,nonnull) NSString * resID; // 资源 Id 41 | @property (nonatomic, assign) HTResourceVersionCheckerState state; // 资源更新状态码 42 | @property (nonatomic, strong, nullable) NSString * localVersion; // 资源本地版本 43 | @property (nonatomic, strong, nullable) NSString * version; // 资源最新的版本, 44 | @property (nonatomic, strong, nullable) NSString * diffUrl; // 增量包的下载url 45 | @property (nonatomic, strong, nullable) NSString * diffMd5; // 增量包的md5值,用于完整性校验 46 | @property (nonatomic, strong, nullable) NSString * fullUrl; // 全量包的下载url 47 | @property (nonatomic, strong, nullable) NSString * fullMd5; // 全量包的md5值,用于完整性校验 48 | @property (nonatomic, strong, nullable) NSString * userData; // 用户自定义数据 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /src/VersionChecker/HTResourceVersionInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTResourceVersionInfo.m 3 | // Pods 4 | // 5 | // Created by 小丸子 on 7/6/2016. 6 | // 7 | // 8 | 9 | #import "HTResourceVersionInfo.h" 10 | 11 | @implementation HTResourceVersionInfo 12 | 13 | -(instancetype)init{ 14 | 15 | self = [super init]; 16 | if (self) { 17 | 18 | _resID = @""; 19 | _state = HTResourceVersionCheckerStateNone; 20 | _localVersion = @""; 21 | _version = @""; 22 | _diffUrl = @""; 23 | _version = @""; 24 | _diffMd5 = @""; 25 | _fullUrl = @""; 26 | _fullMd5 = @""; 27 | } 28 | 29 | return self; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /src/VersionChecker/HTThreadSafeMutableDictionary.h: -------------------------------------------------------------------------------- 1 | // 2 | // HTThreadSafeMutableDictionary.h 3 | // Pods 4 | // 5 | // Created by 小丸子 on 20/7/2016. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface HTThreadSafeMutableDictionary : NSMutableDictionary 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /src/VersionChecker/HTThreadSafeMutableDictionary.m: -------------------------------------------------------------------------------- 1 | // 2 | // HTThreadSafeMutableDictionary.m 3 | // Pods 4 | // 5 | // Created by 小丸子 on 20/7/2016. 6 | // 7 | // 8 | 9 | #import "HTThreadSafeMutableDictionary.h" 10 | 11 | #import 12 | #import 13 | 14 | #define LOCKED(...) do { \ 15 | OSSpinLockLock(&_lock); \ 16 | __VA_ARGS__; \ 17 | OSSpinLockUnlock(&_lock); \ 18 | } while (NO) 19 | 20 | @interface HTThreadSafeMutableDictionary() 21 | @property (nonatomic, assign) OSSpinLock lock; 22 | @property (nonatomic, copy) NSMutableDictionary* dictionary; 23 | @end 24 | 25 | @implementation HTThreadSafeMutableDictionary { 26 | 27 | 28 | } 29 | 30 | /////////////////////////////////////////////////////////////////////////////////////////// 31 | #pragma mark - NSObject 32 | 33 | - (id)init { 34 | if ((self = [super init])) { 35 | _dictionary = [[NSMutableDictionary alloc] init]; 36 | _lock = OS_SPINLOCK_INIT; 37 | } 38 | return self; 39 | } 40 | 41 | - (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys { 42 | if ((self = [self initWithCapacity:objects.count])) { 43 | [objects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 44 | _dictionary[keys[idx]] = obj; 45 | }]; 46 | } 47 | return self; 48 | } 49 | 50 | - (id)initWithCapacity:(NSUInteger)capacity { 51 | if ((self = [super init])) { 52 | _dictionary = [[NSMutableDictionary alloc] initWithCapacity:capacity]; 53 | _lock = OS_SPINLOCK_INIT; 54 | } 55 | return self; 56 | } 57 | 58 | /////////////////////////////////////////////////////////////////////////////////////////// 59 | #pragma mark - NSMutableDictionary 60 | 61 | - (void)setObject:(id)anObject forKey:(id)aKey { 62 | LOCKED(_dictionary[aKey] = anObject); 63 | } 64 | 65 | - (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary { 66 | LOCKED([_dictionary addEntriesFromDictionary:otherDictionary]); 67 | } 68 | 69 | - (void)setDictionary:(NSDictionary *)otherDictionary { 70 | LOCKED([_dictionary setDictionary:otherDictionary]); 71 | } 72 | 73 | - (void)removeObjectForKey:(id)aKey { 74 | LOCKED([_dictionary removeObjectForKey:aKey]); 75 | } 76 | 77 | - (void)removeAllObjects { 78 | LOCKED([_dictionary removeAllObjects]); 79 | } 80 | 81 | - (NSUInteger)count { 82 | NSUInteger count; 83 | LOCKED(count = _dictionary.count); 84 | return count; 85 | } 86 | 87 | - (NSArray *)allKeys { 88 | NSArray *allKeys; 89 | LOCKED(allKeys = _dictionary.allKeys); 90 | return allKeys; 91 | } 92 | 93 | - (NSArray *)allValues { 94 | NSArray *allValues; 95 | LOCKED(allValues = _dictionary.allValues); 96 | return allValues; 97 | } 98 | 99 | - (id)objectForKey:(id)aKey { 100 | id obj; 101 | LOCKED(obj = _dictionary[aKey]); 102 | return obj; 103 | } 104 | 105 | - (NSEnumerator *)keyEnumerator { 106 | NSEnumerator *keyEnumerator; 107 | LOCKED(keyEnumerator = [_dictionary keyEnumerator]); 108 | return keyEnumerator; 109 | } 110 | 111 | - (id)copyWithZone:(NSZone *)zone { 112 | return [self mutableCopyWithZone:zone]; 113 | } 114 | 115 | - (id)mutableCopyWithZone:(NSZone *)zone { 116 | id copiedDictionary; 117 | LOCKED(copiedDictionary = [[self.class allocWithZone:zone] initWithDictionary:_dictionary]); 118 | return copiedDictionary; 119 | } 120 | 121 | - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state 122 | objects:(id __unsafe_unretained [])stackbuf 123 | count:(NSUInteger)len { 124 | OSSpinLockLock(&_lock); 125 | 126 | NSDictionary *enumerationDict = objc_getAssociatedObject(self, &stackbuf); 127 | if (!enumerationDict) { 128 | objc_setAssociatedObject(self, &stackbuf, (enumerationDict = _dictionary.copy), OBJC_ASSOCIATION_RETAIN); 129 | } 130 | 131 | NSUInteger count = [enumerationDict countByEnumeratingWithState:state objects:stackbuf count:len]; 132 | 133 | if (!count) { 134 | objc_setAssociatedObject(self, &stackbuf, nil, OBJC_ASSOCIATION_RETAIN); 135 | } 136 | 137 | OSSpinLockUnlock(&_lock); 138 | 139 | return count; 140 | } 141 | 142 | - (void)performLockedWithDictionary:(void (^)(NSDictionary *dictionary))block { 143 | if (block) 144 | LOCKED(block(_dictionary)); 145 | } 146 | 147 | - (BOOL)isEqual:(id)object { 148 | if (object == self) return YES; 149 | 150 | if ([object isKindOfClass:HTThreadSafeMutableDictionary.class]) { 151 | HTThreadSafeMutableDictionary *other = object; 152 | __block BOOL isEqual = NO; 153 | [other performLockedWithDictionary:^(NSDictionary *dictionary) { 154 | [self performLockedWithDictionary:^(NSDictionary *otherDictionary) { 155 | isEqual = [dictionary isEqual:otherDictionary]; 156 | }]; 157 | }]; 158 | return isEqual; 159 | } 160 | return NO; 161 | } 162 | 163 | - (NSUInteger)hash 164 | { 165 | NSUInteger hash; 166 | LOCKED(hash = [super hash]); 167 | return hash; 168 | } 169 | 170 | @end 171 | -------------------------------------------------------------------------------- /src/bsdiff/bsdiff/bsdiff.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2003-2005 Colin Percival 3 | * Copyright 2012 Matthew Endsley 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef BSDIFF_H 29 | # define BSDIFF_H 30 | 31 | # include 32 | # include 33 | 34 | struct bsdiff_stream 35 | { 36 | void* opaque; 37 | 38 | void* (*malloc)(size_t size); 39 | void (*free)(void* ptr); 40 | int (*write)(struct bsdiff_stream* stream, const void* buffer, int size); 41 | }; 42 | 43 | int bsdiff(const uint8_t* old, int64_t oldsize, const uint8_t* new, int64_t newsize, struct bsdiff_stream* stream); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/bsdiff/bsdiff/bspatch.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright 2003-2005 Colin Percival 3 | * Copyright 2012 Matthew Endsley 4 | * All rights reserved 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted providing that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | * POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef BSPATCH_H 29 | # define BSPATCH_H 30 | 31 | # include 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | struct bspatch_stream 38 | { 39 | void* opaque; 40 | int (*read)(const struct bspatch_stream* stream, void* buffer, int length); 41 | }; 42 | 43 | //argv[0]:任意;argv[1]:oldFile;argv[2]:newFile;argv[3]:diffFile 44 | int applypatch(int argc, char * argv[]); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif 51 | 52 | -------------------------------------------------------------------------------- /src/bsdiff/bsdiff/config.h: -------------------------------------------------------------------------------- 1 | /* config.h. Generated from config.h.in by configure. */ 2 | /* config.h.in. Generated from configure.ac by autoheader. */ 3 | 4 | /* Define to 1 if you have the header file. */ 5 | #define HAVE_FCNTL_H 1 6 | 7 | /* Define to 1 if you have the header file. */ 8 | #define HAVE_INTTYPES_H 1 9 | 10 | /* Define to 1 if you have the `bz2' library (-lbz2). */ 11 | #define HAVE_LIBBZ2 1 12 | 13 | /* Define to 1 if you have the header file. */ 14 | #define HAVE_LIMITS_H 1 15 | 16 | /* Define to 1 if your system has a GNU libc compatible `malloc' function, and 17 | to 0 otherwise. */ 18 | #define HAVE_MALLOC 1 19 | 20 | /* Define to 1 if you have the header file. */ 21 | #define HAVE_MEMORY_H 1 22 | 23 | /* Define to 1 if you have the `memset' function. */ 24 | #define HAVE_MEMSET 1 25 | 26 | /* Define to 1 if you have the header file. */ 27 | #define HAVE_STDDEF_H 1 28 | 29 | /* Define to 1 if you have the header file. */ 30 | #define HAVE_STDINT_H 1 31 | 32 | /* Define to 1 if you have the header file. */ 33 | #define HAVE_STDLIB_H 1 34 | 35 | /* Define to 1 if you have the header file. */ 36 | #define HAVE_STRINGS_H 1 37 | 38 | /* Define to 1 if you have the header file. */ 39 | #define HAVE_STRING_H 1 40 | 41 | /* Define to 1 if you have the header file. */ 42 | #define HAVE_SYS_STAT_H 1 43 | 44 | /* Define to 1 if you have the header file. */ 45 | #define HAVE_SYS_TYPES_H 1 46 | 47 | /* Define to 1 if you have the header file. */ 48 | #define HAVE_UNISTD_H 1 49 | 50 | /* Name of package */ 51 | #define PACKAGE "bsdiff" 52 | 53 | /* Define to the address where bug reports for this package should be sent. */ 54 | #define PACKAGE_BUGREPORT "" 55 | 56 | /* Define to the full name of this package. */ 57 | #define PACKAGE_NAME "bsdiff" 58 | 59 | /* Define to the full name and version of this package. */ 60 | #define PACKAGE_STRING "bsdiff 0.1" 61 | 62 | /* Define to the one symbol short name of this package. */ 63 | #define PACKAGE_TARNAME "bsdiff" 64 | 65 | /* Define to the home page for this package. */ 66 | #define PACKAGE_URL "" 67 | 68 | /* Define to the version of this package. */ 69 | #define PACKAGE_VERSION "0.1" 70 | 71 | /* Define to 1 if you have the ANSI C header files. */ 72 | #define STDC_HEADERS 1 73 | 74 | /* Version number of package */ 75 | #define VERSION "0.1" 76 | 77 | /* Define for Solaris 2.5.1 so the uint8_t typedef from , 78 | , or is not used. If the typedef were allowed, the 79 | #define below would cause a syntax error. */ 80 | /* #undef _UINT8_T */ 81 | 82 | /* Define to the type of a signed integer type of width exactly 64 bits if 83 | such a type exists and the standard includes do not define it. */ 84 | /* #undef int64_t */ 85 | 86 | /* Define to rpl_malloc if the replacement function should be used. */ 87 | /* #undef malloc */ 88 | 89 | /* Define to `long int' if does not define. */ 90 | /* #undef off_t */ 91 | 92 | /* Define to `unsigned int' if does not define. */ 93 | /* #undef size_t */ 94 | 95 | /* Define to the type of an unsigned integer type of width exactly 8 bits if 96 | such a type exists and the standard includes do not define it. */ 97 | /* #undef uint8_t */ 98 | -------------------------------------------------------------------------------- /src/bsdiff/bzip2/crctable.c: -------------------------------------------------------------------------------- 1 | 2 | /*-------------------------------------------------------------*/ 3 | /*--- Table for doing CRCs ---*/ 4 | /*--- crctable.c ---*/ 5 | /*-------------------------------------------------------------*/ 6 | 7 | /* ------------------------------------------------------------------ 8 | This file is part of bzip2/libbzip2, a program and library for 9 | lossless, block-sorting data compression. 10 | 11 | bzip2/libbzip2 version 1.0.5 of 10 December 2007 12 | Copyright (C) 1996-2007 Julian Seward 13 | 14 | Please read the WARNING, DISCLAIMER and PATENTS sections in the 15 | README file. 16 | 17 | This program is released under the terms of the license contained 18 | in the file LICENSE. 19 | ------------------------------------------------------------------ */ 20 | 21 | 22 | #include "bzlib_private.h" 23 | 24 | /*-- 25 | I think this is an implementation of the AUTODIN-II, 26 | Ethernet & FDDI 32-bit CRC standard. Vaguely derived 27 | from code by Rob Warnock, in Section 51 of the 28 | comp.compression FAQ. 29 | --*/ 30 | 31 | UInt32 BZ2_crc32Table[256] = { 32 | 33 | /*-- Ugly, innit? --*/ 34 | 35 | 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, 36 | 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, 37 | 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, 38 | 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, 39 | 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, 40 | 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, 41 | 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, 42 | 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, 43 | 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, 44 | 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, 45 | 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, 46 | 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, 47 | 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, 48 | 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, 49 | 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, 50 | 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, 51 | 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, 52 | 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, 53 | 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, 54 | 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, 55 | 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, 56 | 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, 57 | 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, 58 | 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, 59 | 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, 60 | 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, 61 | 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, 62 | 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, 63 | 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, 64 | 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, 65 | 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, 66 | 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, 67 | 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, 68 | 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, 69 | 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, 70 | 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, 71 | 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, 72 | 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, 73 | 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, 74 | 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, 75 | 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, 76 | 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, 77 | 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, 78 | 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, 79 | 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, 80 | 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, 81 | 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, 82 | 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, 83 | 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, 84 | 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, 85 | 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, 86 | 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, 87 | 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, 88 | 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, 89 | 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, 90 | 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, 91 | 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, 92 | 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, 93 | 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, 94 | 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, 95 | 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, 96 | 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, 97 | 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, 98 | 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L 99 | }; 100 | 101 | 102 | /*-------------------------------------------------------------*/ 103 | /*--- end crctable.c ---*/ 104 | /*-------------------------------------------------------------*/ 105 | -------------------------------------------------------------------------------- /src/bsdiff/bzip2/randtable.c: -------------------------------------------------------------------------------- 1 | 2 | /*-------------------------------------------------------------*/ 3 | /*--- Table for randomising repetitive blocks ---*/ 4 | /*--- randtable.c ---*/ 5 | /*-------------------------------------------------------------*/ 6 | 7 | /* ------------------------------------------------------------------ 8 | This file is part of bzip2/libbzip2, a program and library for 9 | lossless, block-sorting data compression. 10 | 11 | bzip2/libbzip2 version 1.0.5 of 10 December 2007 12 | Copyright (C) 1996-2007 Julian Seward 13 | 14 | Please read the WARNING, DISCLAIMER and PATENTS sections in the 15 | README file. 16 | 17 | This program is released under the terms of the license contained 18 | in the file LICENSE. 19 | ------------------------------------------------------------------ */ 20 | 21 | 22 | #include "bzlib_private.h" 23 | 24 | 25 | /*---------------------------------------------*/ 26 | Int32 BZ2_rNums[512] = { 27 | 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 28 | 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 29 | 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 30 | 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 31 | 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 32 | 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 33 | 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 34 | 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 35 | 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 36 | 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 37 | 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 38 | 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 39 | 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 40 | 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 41 | 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 42 | 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 43 | 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 44 | 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 45 | 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 46 | 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 47 | 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 48 | 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 49 | 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 50 | 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 51 | 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 52 | 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 53 | 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 54 | 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 55 | 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 56 | 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 57 | 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 58 | 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 59 | 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 60 | 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 61 | 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 62 | 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 63 | 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 64 | 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 65 | 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 66 | 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 67 | 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 68 | 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 69 | 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 70 | 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 71 | 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 72 | 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 73 | 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 74 | 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 75 | 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 76 | 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 77 | 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 78 | 936, 638 79 | }; 80 | 81 | 82 | /*-------------------------------------------------------------*/ 83 | /*--- end randtable.c ---*/ 84 | /*-------------------------------------------------------------*/ 85 | --------------------------------------------------------------------------------