ios wkwebview离线化加载h5资源解决方案
程序员文章站
2023-12-18 18:32:58
思路: 使用nsurlprotocol拦截请求转发到本地。
1.确认离线化需求
部门负责的app有一部分使用的线上h5页,长期以来加载略慢...
于是考虑使用...
思路: 使用nsurlprotocol拦截请求转发到本地。
1.确认离线化需求
部门负责的app有一部分使用的线上h5页,长期以来加载略慢...
于是考虑使用离线化加载。
确保[低速网络]或[无网络]可网页秒开。
2.使用[nsurlprotocol]拦截
区别于uiwebview wkwebview使用如下方法拦截
@interface viewcontroller () @end @implementation viewcontroller - (void)viewdidload { [super viewdidload]; // 区别于uiwebview wkwebview使用如下方法拦截 class cls = nsclassfromstring(@"wkbrowsingcontextcontroller"); sel sel = nsselectorfromstring(@"registerschemeforcustomprotocol:"); if ([(id)cls respondstoselector:sel]) { [(id)cls performselector:sel withobject:@"http"]; [(id)cls performselector:sel withobject:@"https"]; } }
# 注册nsurlprotocol拦截 - (ibaction)regist:(id)sender { [nsurlprotocol registerclass:[filteredprotocol class]]; }
# 注销nsurlprotocol拦截 - (ibaction)unregist:(id)sender { [nsurlprotocol unregisterclass:[filteredprotocol class]]; }
3.下载[zip] + 使用[ssziparchive]解压
需要先 #import "ssziparchive.h
- (void)downloadzip { nsdictionary *_headers; nsurlsession *_session = [self sessionwithheaders:_headers]; nsurl *url = [nsurl urlwithstring: @"http://10.2.138.225:3238/dist.zip"]; nsmutableurlrequest *request = [nsmutableurlrequest requestwithurl:url]; // 初始化cachepath nsstring *cachepath = [nssearchpathfordirectoriesindomains(nscachesdirectory, nsuserdomainmask, yes) lastobject]; nsfilemanager *fm = [nsfilemanager defaultmanager]; // 删除之前已有的文件 [fm removeitematpath:[cachepath stringbyappendingpathcomponent:@"dist.zip"] error:nil]; nsurlsessiondownloadtask *downloadtask=[_session downloadtaskwithrequest:request completionhandler:^(nsurl *location, nsurlresponse *response, nserror *error) { if (!error) { nserror *saveerror; nsurl *saveurl = [nsurl fileurlwithpath: [cachepath stringbyappendingpathcomponent:@"dist.zip"]]; // location是下载后的临时保存路径,需要将它移动到需要保存的位置 [[nsfilemanager defaultmanager] copyitematurl:location tourl:saveurl error:&saveerror]; if (!saveerror) { nslog(@"task ok"); if([ssziparchive unzipfileatpath: [cachepath stringbyappendingpathcomponent:@"dist.zip"] todestination:cachepath]) { nslog(@"unzip ok");// 解压成功 } else { nslog(@"unzip err");// 解压失败 } } else { nslog(@"task err"); } } else { nslog(@"error is :%@", error.localizeddescription); } }]; [downloadtask resume]; }
4.迁移资源至[nstemporary]
[wkwebview]真机不支持直接加载[nscache]资源
需要先迁移资源至[nstemporary]
- (void)migratedisttotempory { nsfilemanager *fm = [nsfilemanager defaultmanager]; nsstring *cachefilepath = [[nssearchpathfordirectoriesindomains(nscachesdirectory, nsuserdomainmask, yes) lastobject] stringbyappendingpathcomponent:@"dist"]; nsstring *tmpfilepath = [nstemporarydirectory() stringbyappendingpathcomponent:@"dist"]; // 先删除tempory已有的dist资源 [fm removeitematpath:tmpfilepath error:nil]; nserror *saveerror; // 从caches拷贝dist到tempory临时文件夹 [[nsfilemanager defaultmanager] copyitematurl:[nsurl fileurlwithpath:cachefilepath] tourl:[nsurl fileurlwithpath:tmpfilepath] error:&saveerror]; nslog(@"migrate dist to tempory ok"); }
5.转发请求
如果[/static]开头 => 则转发[request]到本地[.css/.js]资源
如果[index.html]结尾 => 就直接[load]本地[index.html] (否则[index.html]可能会加载失败)
// // protocolcustom.m // proxy-browser // // created by melo的微博 on 2018/4/8. // copyright © 2018年 com. all rights reserved. // #import <objc/runtime.h> #import <foundation/foundation.h> #import <mobilecoreservices/mobilecoreservices.h> static nsstring*const matchingprefix = @"http://10.2.138.225:3233/static/"; static nsstring*const regprefix = @"http://10.2.138.225:3233"; static nsstring*const filteredkey = @"filteredkey"; @interface filteredprotocol : nsurlprotocol @property (nonatomic, strong) nsmutabledata *responsedata; @property (nonatomic, strong) nsurlconnection *connection; @end @implementation filteredprotocol + (bool)caninitwithrequest:(nsurlrequest *)request { return [nsurlprotocol propertyforkey:filteredkey inrequest:request]== nil; } + (nsurlrequest *)canonicalrequestforrequest:(nsurlrequest *)request { nslog(@"got it request.url.absolutestring = %@",request.url.absolutestring); nsmutableurlrequest *mutablereqeust = [request mutablecopy]; //截取重定向 if ([request.url.absolutestring hasprefix:matchingprefix]) { nsurl* proxyurl = [nsurl urlwithstring:[filteredprotocol generateproxypath: request.url.absolutestring]]; nslog(@"proxy to = %@", proxyurl); mutablereqeust = [nsmutableurlrequest requestwithurl: proxyurl]; } return mutablereqeust; } + (bool)requestiscacheequivalent:(nsurlrequest *)a torequest:(nsurlrequest *)b { return [super requestiscacheequivalent:a torequest:b]; } # 如果[index.html]结尾 => 就直接[load]本地[index.html] - (void)startloading { nsmutableurlrequest *mutablereqeust = [[self request] mutablecopy]; // 标示改request已经处理过了,防止无限循环 [nsurlprotocol setproperty:@yes forkey:filteredkey inrequest:mutablereqeust]; if ([self.request.url.absolutestring hassuffix:@"index.html"]) { nsurl *url = self.request.url; nsstring *path = [filteredprotocol generatedatereadpath: self.request.url.absolutestring]; nslog(@"read data from path = %@", path); nsfilehandle *file = [nsfilehandle filehandleforreadingatpath:path]; nsdata *data = [file readdatatoendoffile]; nslog(@"got data = %@", data); [file closefile]; //3.拼接响应response nsinteger datalength = data.length; nsstring *mimetype = [self getmimetypewithcapiatfilepath:path]; nsstring *httpversion = @"http/1.1"; nshttpurlresponse *response = nil; if (datalength > 0) { response = [self jointresponsewithdata:data datalength:datalength mimetype:mimetype requesturl:url statuscode:200 httpversion:httpversion]; } else { response = [self jointresponsewithdata:[@"404" datausingencoding:nsutf8stringencoding] datalength:3 mimetype:mimetype requesturl:url statuscode:404 httpversion:httpversion]; } //4.响应 [[self client] urlprotocol:self didreceiveresponse:response cachestoragepolicy:nsurlcachestoragenotallowed]; [[self client] urlprotocol:self didloaddata:data]; [[self client] urlprotocoldidfinishloading:self]; } else { self.connection = [nsurlconnection connectionwithrequest:mutablereqeust delegate:self]; } } - (void)stoploading { if (self.connection != nil) { [self.connection cancel]; self.connection = nil; } } - (nsstring *)getmimetypewithcapiatfilepath:(nsstring *)path { if (![[[nsfilemanager alloc] init] fileexistsatpath:path]) { return nil; } cfstringref uti = uttypecreatepreferredidentifierfortag(kuttagclassfilenameextension, (__bridge cfstringref)[path pathextension], null); cfstringref mimetype = uttypecopypreferredtagwithclass (uti, kuttagclassmimetype); cfrelease(uti); if (!mimetype) { return @"application/octet-stream"; } return (__bridge nsstring *)(mimetype); } #pragma mark - 拼接响应response - (nshttpurlresponse *)jointresponsewithdata:(nsdata *)data datalength:(nsinteger)datalength mimetype:(nsstring *)mimetype requesturl:(nsurl *)requesturl statuscode:(nsinteger)statuscode httpversion:(nsstring *)httpversion { nsdictionary *dict = @{@"content-type":mimetype, @"content-length":[nsstring stringwithformat:@"%ld",datalength]}; nshttpurlresponse *response = [[nshttpurlresponse alloc] initwithurl:requesturl statuscode:statuscode httpversion:httpversion headerfields:dict]; return response; } #pragma mark- nsurlconnectiondelegate - (void)connection:(nsurlconnection *)connection didfailwitherror:(nserror *)error { [self.client urlprotocol:self didfailwitherror:error]; } #pragma mark - nsurlconnectiondatadelegate - (void)connection:(nsurlconnection *)connection didreceiveresponse:(nsurlresponse *)response { self.responsedata = [[nsmutabledata alloc] init]; [self.client urlprotocol:self didreceiveresponse:response cachestoragepolicy:nsurlcachestoragenotallowed]; } - (void)connection:(nsurlconnection *)connection didreceivedata:(nsdata *)data { [self.responsedata appenddata:data]; [self.client urlprotocol:self didloaddata:data]; } - (void)connectiondidfinishloading:(nsurlconnection *)connection { [self.client urlprotocoldidfinishloading:self]; } + (nsstring *)generateproxypath:(nsstring *) absoluteurl { nsstring *tmpfilepath = [nstemporarydirectory() stringbyappendingpathcomponent:@"dist"]; nsstring *fileabsoluteurl = [@"file:/" stringbyappendingstring:tmpfilepath]; return [absoluteurl stringbyreplacingoccurrencesofstring:regprefix withstring:fileabsoluteurl]; } + (nsstring *)generatedatereadpath:(nsstring *) absoluteurl { nsstring *filedatareadurl = [nstemporarydirectory() stringbyappendingpathcomponent:@"dist"]; return [absoluteurl stringbyreplacingoccurrencesofstring:regprefix withstring:filedatareadurl]; } @end
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。