一、離線包緩存的簡(jiǎn)介
離線包緩存含幾個(gè)包的概念:
- 預(yù)裝包:指通過腳本文件在程序編譯時(shí)期下載的包阐斜。
- 增量包:指通過包的文件比對(duì)躯枢,生成的diff文件(差量包)
- 全量包:指完整的包文件
CCCandyWebCache離線包緩存的邏輯
- 第一次啟動(dòng)的時(shí)候先請(qǐng)求預(yù)裝包接口安裝預(yù)裝包,同時(shí)將預(yù)裝包請(qǐng)求的response配置表放在本地中舷丹,獲取預(yù)裝包zip的文件名字氓奈,先去判斷是否在預(yù)裝包配置表里面翘魄,然后判斷預(yù)裝包文件的MD5值和預(yù)裝包配置表fullPackageMD5是否匹配。如果信息都匹配上則將預(yù)裝包移動(dòng)到指定的本地目錄下(....../webapps/res/),然后解壓預(yù)裝包zip文件舀奶。
- 預(yù)裝包解壓成功后暑竟,會(huì)將本地包的信息組裝成body去請(qǐng)求檢查更新接口,將返回的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)模型育勺,根據(jù)state判斷是否需要更新光羞,如果要的話去判斷是全量更新還是增量更新。然后和本地?cái)?shù)據(jù)庫(kù)的模塊名字對(duì)比是否有匹配怀大,有的話判斷該包是否正在更新或者有其他錯(cuò)誤狀態(tài),如果狀態(tài)是正確的則使用版本號(hào)做對(duì)比呀闻,看是否需要更新包化借,如果服務(wù)器返回?cái)?shù)據(jù)的版本號(hào)更大則去更新資源。
- 如果是增量更新捡多,將diff文件下載下來后蓖康,將其MD5值與請(qǐng)求更新的response的對(duì)應(yīng)模塊的MD5值做匹配,匹配失敗則做全量更新,如果匹配成功則開始增量合并垒手,如果本地老的資源zip包已經(jīng)不存在則增量合并失敗蒜焊,做全量更新。如果增量包合并失敗則進(jìn)行全量更新科贬。增量包合并成功則解壓zip包泳梆,替換掉原來的解壓后的文件。資源更新成功清除內(nèi)存緩存榜掌。
- 全量更新优妙,下載成功后,匹配zip包的MD5值憎账,如果成功則移除原來的模塊文件套硼,然后進(jìn)行解壓。
- 每次啟動(dòng)都會(huì)去請(qǐng)求檢查更新這個(gè)接口胞皱,判斷資源是否需要更新邪意。
- 攔截的URl的時(shí)候九妈,先判斷URL 是否包含本地存儲(chǔ)的domain,包含則進(jìn)行本地資源匹配雾鬼,然后匹配上則去加載本地的html,css萌朱,js,等文件呆贿。否則正常去請(qǐng)求這個(gè)URL嚷兔。
二、集成SDK遇到的坑
-
1.因?yàn)槭褂胹wift項(xiàng)目做入,pod是動(dòng)態(tài)庫(kù)冒晰,所以需要用本地庫(kù)去pod
1.SDK的podspec 去掉了作者信息,導(dǎo)致pod不成功.所以要加上
2.SDK的podspec ,homepage 指向不對(duì)竟块,導(dǎo)致pod不成功.
3. SDK的podspec 用了ZipArchive第三方庫(kù)但沒有指明依賴關(guān)系壶运,導(dǎo)致pod不成功.
CCCacheManger 360行 開始 // 字段不正確
appVersionInfos -> resInfos
appId -> resID
Version -> resVersion
info.domains = [dic objectForKey:@"domains"]; // 取值不正確
// 更換如下:
if (dic[@"userData"]) {
info.domains = [dic[@"userData"] objectForKey:@"domains"];
}
-
3.字段fullMD5服務(wù)器要進(jìn)行Des加密+Base64,因?yàn)镾DK對(duì)fullMD5進(jìn)行了Base64 decodo 和 Des解密
-
4.預(yù)裝包和檢查更新是post請(qǐng)求
-
5.檢查更新返回的response 解析數(shù)據(jù)不正常導(dǎo)致 crash
HTResourceVersionChecker 214行 SDK模型里面的userData 是字符串 這里是Data類型
-
6.由于CCCancahce 是正對(duì)UIWebView做的緩存浪秘,而我們項(xiàng)目是WKWebView 蒋情,所以攔截不到網(wǎng)頁的請(qǐng)求,需要做一些處理 添加NSURLProtocol+WebKitSupport 這個(gè)類耸携,才可以攔截WKWebView的網(wǎng)絡(luò)請(qǐng)求
// .h文件
#import <Foundation/Foundation.h>
@interface NSURLProtocol (WebKitSupport)
+ (void)wk_registerScheme:(NSString*)scheme;
+ (void)wk_unregisterScheme:(NSString*)scheme;
@end
// .m文件
#import "NSURLProtocol+WebKitSupport.h"
#import <WebKit/WebKit.h>
/**
* The functions below use some undocumented APIs, which may lead to rejection by Apple.
*/
FOUNDATION_STATIC_INLINE Class ContextControllerClass() {
static Class cls;
if (!cls) {
cls = [[[WKWebView new] valueForKey:@"browsingContextController"] class];
}
return cls;
}
FOUNDATION_STATIC_INLINE SEL RegisterSchemeSelector() {
return NSSelectorFromString(@"registerSchemeForCustomProtocol:");
}
FOUNDATION_STATIC_INLINE SEL UnregisterSchemeSelector() {
return NSSelectorFromString(@"unregisterSchemeForCustomProtocol:");
}
@implementation NSURLProtocol (WebKitSupport)
+ (void)wk_registerScheme:(NSString *)scheme {
Class cls = ContextControllerClass();
SEL sel = RegisterSchemeSelector();
if ([(id)cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[(id)cls performSelector:sel withObject:scheme];
#pragma clang diagnostic pop
}
}
+ (void)wk_unregisterScheme:(NSString *)scheme {
Class cls = ContextControllerClass();
SEL sel = UnregisterSchemeSelector();
if ([(id)cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[(id)cls performSelector:sel withObject:scheme];
#pragma clang diagnostic pop
}
}
@end
-
7.增量更新MD5校驗(yàn)失敗棵癣,進(jìn)行全量更新,資源是更新但是沒有更新本地的version
// 要在CCCandyWebCache 333行進(jìn)行新的版本賦值
NSArray* comps = [info.composeVersion componentsSeparatedByString:@"&"];
info.version = (comps.count == 2 ? comps[1] : comps[0]);
-
8.多個(gè)包domain應(yīng)該對(duì)應(yīng)于ResID 的目錄名 而不是域名夺衍,要不然多個(gè)離線包會(huì)有問題狈谊。
// 如 https://www.baicu.com/feature/task
// feature/task 是zip包解壓后的文件目錄
-
9.攔擊到的URL匹配規(guī)則有問題,要截取到domain的域名去拼接路徑沟沙,然后去匹配本地是否有緩存河劝。
// CCCacheManager 187行
[_domainWebappInfos enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull domain, CCWebAppInfo * _Nonnull webappInfo, BOOL * _Nonnull stop) {
NSString *domainLastObject = [domain componentsSeparatedByString:@"://"].lastObject;
if ([url hasPrefix:domainLastObject]) {
if (webappInfo.status != CCWebAppStatusAvailable) {
CCLogWarn(@"[CCCacheManager]:資源正在更新或已出錯(cuò),請(qǐng)求不使用緩存,url==>:%@矛紫。",url);
}
if (url.length > domainLastObject.length) {
NSString *domainOrigin = [domainLastObject componentsSeparatedByString:@"/"].firstObject;
key = [NSString stringWithFormat:@"%@/%@",webappInfo.name,[url substringFromIndex:domainOrigin.length+1]];
}
[_urlToKeyMapCache setObject:key forKey:url];
*stop = YES;
}
}];
// CCCacheManager 174 對(duì) webView reload方法 低版本系統(tǒng)做兼容
NSArray* strs = [url componentsSeparatedByString:@"://"];
if (strs.count == 2) {
NSArray *strsurl = [strs[1] componentsSeparatedByString:@".html"];
if (strsurl.count == 2 && [strsurl[1] isEqualToString:@"#/"]) {
url = [strsurl[0] stringByAppendingString:@".html"];
} else {
url = strs[1];
}
}
-
10.移除緩存下載進(jìn)度觀察者 不能放在deinit方法里面 要不然會(huì)影響內(nèi)存泄漏赎瞎,添加和移除要放在viewWillAppear 和 viewWillDisappear方法里面
// CCCandyWebCache.m 206行
webappInfo.isDiffTask = _diffEnable ? (versionInfo.diffUrl.length ? YES : NO) : NO;
// 更換如下:
webappInfo.isDiffTask = _diffEnable ? (versionInfo.diffUrl.length > 0 ? YES : NO) : NO;
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者