溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

ios中wkwebview離線化加載h5資源的示例分析

發(fā)布時間:2021-08-05 10:26:07 來源:億速云 閱讀:262 作者:小新 欄目:移動開發(fā)

這篇文章主要介紹ios中wkwebview離線化加載h5資源的示例分析,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

思路: 使用NSURLProtocol攔截請求轉發(fā)到本地。

1.確認離線化需求

部門負責的app有一部分使用的線上h6頁,長期以來加載略慢...

于是考慮使用離線化加載。

確保[低速網絡]或[無網絡]可網頁秒開。

2.使用[NSURLProtocol]攔截

區(qū)別于uiwebview wkwebview使用如下方法攔截

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  // 區(qū)別于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.轉發(fā)請求

如果[/static]開頭 => 則轉發(fā)[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已經處理過了,防止無限循環(huán)
  [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

以上是“ios中wkwebview離線化加載h5資源的示例分析”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業(yè)資訊頻道!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI