虚位以待(AD)
虚位以待(AD)
首页 > 软件编程 > IOS编程/Objective-C > ios wkwebview离线化加载h5资源解决方案

ios wkwebview离线化加载h5资源解决方案
类别:IOS编程/Objective-C   作者:码皇   来源:互联网   点击:

本篇文章主要介绍了ios wkwebview离线化加载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

结语:

完整[DEMO]请参考: https://github.com/meloalright/wk-proxy

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

您可能感兴趣的文章:

  • WKWebView、WebView和JS的交互方式详解
  • iOS WKWebView无法处理URL Scheme和App Store链接的问题解决
  • JS交互点击WKWebView中的图片实现预览效果
  • iOS11 WKWebView问题汇总
  • iOS11 WKWebView 无法加载内容的解决方法
  • iOS中WKWebView白屏问题的分析与解决
  • iOS11 WKWebView内容过滤规则详解
  • IOS中UIWebView、WKWebView之JS交互
  • 清除WKWebView cookies的方法
  • ios下OC与JS交互之WKWebView
相关热词搜索: wkwebview离线缓存h5 wkwebview 离线缓存