2019-03-22

iOS WKWebView 遠(yuǎn)端h5優(yōu)先加載本地資源

前言:UIWebView調(diào)用遠(yuǎn)端h5頁(yè)面,優(yōu)先加載本地圖片、js、css等資源,解決辦法就是對(duì)請(qǐng)求進(jìn)行攔截。

服務(wù)端代碼放在本文后面

客戶端需要對(duì)NSURLProtocol 的自定義類進(jìn)行注冊(cè),那么所有的webview 對(duì)http請(qǐng)求都會(huì)被他攔截到;

首先自定義NSURLProtocol類

#import <Foundation/Foundation.h>

#import <CoreFoundation/CoreFoundation.h>

#import <MobileCoreServices/MobileCoreServices.h>

@interface NSURLProtocolCustom : NSURLProtocol

@end

#import "NSURLProtocolCustom.h"

static NSString* const FilteredKey = @"FilteredKey";

@implementation NSURLProtocolCustom

+ (BOOL)canInitWithRequest:(NSURLRequest *)request

{

? ? NSString *extension = request.URL.pathExtension;

? ? BOOL isSource = [@[@"png", @"jpeg", @"gif", @"jpg", @"js", @"css"] indexOfObjectPassingTest:^BOOL(id? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? return [extension compare:obj options:NSCaseInsensitiveSearch] == NSOrderedSame;

? ? }] != NSNotFound;

? ? return [NSURLProtocol propertyForKey:FilteredKey inRequest:request] == nil && isSource;

}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request

{

? ? return request;

}

- (void)startLoading

{

? ? NSString *fileName = [super.request.URL.absoluteString componentsSeparatedByString:@"/"].lastObject;

? ? NSLog(@"fileName is %@",fileName);

? ? //這里是獲取本地資源路徑 如:png,js等

? ? NSString *path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];

? ? if (!path) {

? ? ? ? [self sendResponseWithData:[NSData data] mimeType:nil];

? ? ? ? return;

? ? }


? ? //根據(jù)路徑獲取MIMEType

? ? CFStringRef pathExtension = (__bridge_retained CFStringRef)[path pathExtension];

? ? CFStringRef type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, NULL);

? ? CFRelease(pathExtension);


? ? //The UTI can be converted to a mime type:

? ? NSString *mimeType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType);

? ? if (type != NULL)

? ? ? ? CFRelease(type);


? ? //加載本地資源

? ? NSData *data = [NSData dataWithContentsOfFile:path];

? ? [self sendResponseWithData:data mimeType:mimeType];

}

- (void)stopLoading

{

? ? NSLog(@"stopLoading, something went wrong!");

}

- (void)sendResponseWithData:(NSData *)data mimeType:(nullable NSString *)mimeType

{

? ? // 這里需要用到MIMEType

? ? NSURLResponse *response = [[NSURLResponse alloc] initWithURL:super.request.URL

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MIMEType:mimeType

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? expectedContentLength:-1

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? textEncodingName:nil];


? ? //硬編碼 開始嵌入本地資源到web中

? ? [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];

? ? [[self client] URLProtocol:self didLoadData:data];

? ? [[self client] URLProtocolDidFinishLoading:self];

}

@end


其次實(shí)現(xiàn)對(duì)類的注冊(cè)

#import "CSWebView.h"

#import <WebKit/WebKit.h>

#import "NSURLProtocolCustom.h"

@interface CSWebView ()<WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler>

@property (nonatomic, strong) WKWebView *wkWebView;

@end

@implementation CSWebView

- (void)viewDidLoad {

? ? [super viewDidLoad];

? ? //1.設(shè)置背景顏色

? ? self.view.backgroundColor = [UIColor whiteColor];

? ? //2.注冊(cè)

? ? [NSURLProtocol registerClass:[NSURLProtocolCustom class]];

? ? //3.實(shí)現(xiàn)攔截功能,這個(gè)是核心

? ? Class cls = NSClassFromString(@"WKBrowsingContextController");

? ? SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:");

? ? if ([(id)cls respondsToSelector:sel]) {

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

? ? ? ? [(id)cls performSelector:sel withObject:@"http"];

? ? ? ? [(id)cls performSelector:sel withObject:@"https"];

#pragma clang diagnostic pop

? ? }


? ? //4.添加WKWebView

? ? [self addWKWebView];


}

#pragma mark - WKWebView(IOS8以上使用)

#pragma mark 添加WKWebView

- (void)addWKWebView

{

? ? //1.創(chuàng)建配置項(xiàng)

? ? WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];

? ? config.selectionGranularity = WKSelectionGranularityDynamic;


? ? //1.1 設(shè)置偏好

? ? config.preferences = [[WKPreferences alloc] init];

? ? config.preferences.minimumFontSize = 10;

? ? config.preferences.javaScriptEnabled = YES;

? ? //1.1.1 默認(rèn)是不能通過JS自動(dòng)打開窗口的,必須通過用戶交互才能打開

? ? config.preferences.javaScriptCanOpenWindowsAutomatically = NO;

? ? config.processPool = [[WKProcessPool alloc] init];


? ? //1.2 通過JS與webview內(nèi)容交互配置

? ? config.userContentController = [[WKUserContentController alloc] init];

? ? [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;


? ? //2.添加WKWebView

? ? WKWebView *wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, [UIApplication sharedApplication].keyWindow.bounds.size.width, [UIApplication sharedApplication].keyWindow.bounds.size.height) configuration:config];

? ? wkWebView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth ;

? ? wkWebView.UIDelegate = self;

? ? wkWebView.navigationDelegate = self;


? ? _urlStr = [_urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

? ? NSURL *url = [NSURL URLWithString:_urlStr];

? ? [wkWebView loadRequest:[NSURLRequest requestWithURL:url]];


? ? //[wkWebView loadRequest: [[NSURLRequest alloc] initWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"app" ofType:@"html"]]]];


? ? [self.view addSubview:wkWebView];

? ? _wkWebView = wkWebView;


? ? //3.注冊(cè)js方法

? ? [config.userContentController addScriptMessageHandler:self name:@"webViewApp"];

}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{

? ? //接受傳過來的消息從而決定app調(diào)用的方法

? ? NSDictionary *dict = message.body;

? ? NSString *method = [dict objectForKey:@"method"];

? ? if ([method isEqualToString:@"hello"]) {

? ? ? ? [self hello:[dict objectForKey:@"param1"]];

? ? }else if ([method isEqualToString:@"Call JS"]){

? ? ? ? [self callJS];

? ? }else if ([method isEqualToString:@"Call JS Msg"]){

? ? ? ? [self callJSMsg:[dict objectForKey:@"param1"]];

? ? }

}

- (void)hello:(NSString *)param{

? ? NSLog(@"hello");

}

- (void)callJS{

? ? NSLog(@"callJS");

}

- (void)callJSMsg:(NSString *)msg{

? ? NSLog(@"callJSMsg");

}

//WKNavigationDelegate

// 頁(yè)面開始加載時(shí)調(diào)用

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {// 類似UIWebView的 -webViewDidStartLoad:

? ? NSLog(@"didStartProvisionalNavigation");

? ? [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

}

// 當(dāng)內(nèi)容開始返回時(shí)調(diào)用

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {

? ? NSLog(@"didCommitNavigation");

}

// 頁(yè)面加載完成之后調(diào)用

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { // 類似UIWebView 的 -webViewDidFinishLoad:

? ? NSLog(@"didFinishNavigation");

? ? //[self resetControl];

? ? if (webView.title.length > 0) {

? ? ? ? self.title = webView.title;

? ? }


}

// 頁(yè)面加載失敗時(shí)調(diào)用

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {

? ? // 類似 UIWebView 的- webView:didFailLoadWithError:

? ? NSLog(@"didFailProvisionalNavigation");

}

// 在收到響應(yīng)后,決定是否跳轉(zhuǎn)

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {

? ? decisionHandler(WKNavigationResponsePolicyAllow);

}

// 在發(fā)送請(qǐng)求之前,決定是否跳轉(zhuǎn)

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction*)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

? ? // 類似 UIWebView 的 -webView: shouldStartLoadWithRequest: navigationType:

? ? NSLog(@"decidePolicyForNavigationAction %@",navigationAction.request);

? ? //? ? NSString *url = [navigationAction.request.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

? ? //? ? NSString *url = navigationAction.request.URL.absoluteString;

? ? decisionHandler(WKNavigationActionPolicyAllow);


}

// 接收到服務(wù)器跳轉(zhuǎn)請(qǐng)求之后調(diào)用

- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{

? ? NSLog(@"didReceiveServerRedirectForProvisionalNavigation");

}

//- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {

//? ? completionHandler(NSURLSessionAuthChallengePerformDefaultHandling,internal);

//}

//WKUIDelegate

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction*)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {

? ? // 接口的作用是打開新窗口委托

? ? //[self createNewWebViewWithURL:webView.URL.absoluteString config:Web];


? ? return _wkWebView;

}

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler

{? ? // js 里面的alert實(shí)現(xiàn),如果不實(shí)現(xiàn),網(wǎng)頁(yè)的alert函數(shù)無效

? ? UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? message:nil

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? preferredStyle:UIAlertControllerStyleAlert];

? ? [alertController addAction:[UIAlertAction actionWithTitle:@"確定"

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style:UIAlertActionStyleCancel

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? handler:^(UIAlertAction *action) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? completionHandler();

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }]];


? ? [self presentViewController:alertController animated:YES completion:^{


? ? }];


}

//? js 里面的alert實(shí)現(xiàn),如果不實(shí)現(xiàn),網(wǎng)頁(yè)的alert函數(shù)無效

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString*)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {


? ? UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? message:nil

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? preferredStyle:UIAlertControllerStyleAlert];

? ? [alertController addAction:[UIAlertAction actionWithTitle:@"確定"

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style:UIAlertActionStyleDefault

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? handler:^(UIAlertAction *action) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? completionHandler(YES);

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }]];

? ? [alertController addAction:[UIAlertAction actionWithTitle:@"取消"

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style:UIAlertActionStyleCancel

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? handler:^(UIAlertAction *action){

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? completionHandler(NO);

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }]];


? ? [self presentViewController:alertController animated:YES completion:^{}];


}

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void(^)(NSString *))completionHandler {


? ? completionHandler(@"Client Not handler");


}

- (void)showAlert:(NSString *)content Title:(NSString *)title{

? ? UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? message:content

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? preferredStyle:UIAlertControllerStyleAlert];


? ? [alertController addAction:[UIAlertAction actionWithTitle:@"確定"

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? style:UIAlertActionStyleCancel

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? handler:^(UIAlertAction *action) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [self.navigationController popToRootViewControllerAnimated:YES];

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }]];

? ? [self presentViewController:alertController animated:YES completion:^{


? ? }];

}

@end


服務(wù)端代碼


<!DOCTYPE html>

<html>

<head>

? ? <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

? ? <title>測(cè)試iOS與JS之間的互調(diào)</title>

? ? <style type="text/css">

? ? ? ? {

? ? ? ? ? ? font-size: 40px;

? ? ? ? }

? ? </style>

</head>

<body>

<div style="rargin-top: 100px;">

? ? <h1>Test how to use Objective-C call js</h1>

? ? <input type="button" value="Call iOS" onclick="calliOS('call iOS')">

? ? <input type="button" value="Call JS Alert" onclick="jsFunc()">

</div>

<div>

? ? <input type="button" value="iOS Call With No JSON" onclick="callJS()">

? ? <input type="button" value="iOS Call With JSON" onclick="callJSMsg('iOS Call JS')">

</div>

<div>

? ? <span id="jsParatFuncSpan" style="color:red; font-size:50px;"></span>

</div>

</body>

<script type="text/JavaScript" src="appJs.js"></script>

</html>

本地js文件

function calliOS(Msg) {

? ? var message = {

? ? ? ? 'method' : 'hello',

? ? ? ? 'param1' : Msg,

? ? };

? ? window.webkit.messageHandlers.webViewApp.postMessage(message);

}

function callJS() {

? ? var message = {

? ? ? ? 'method' : 'Call JS',

? ? };

? ? window.webkit.messageHandlers.webViewApp.postMessage(message);

}

function callJSMsg(Msg) {

? ? var message = {

? ? ? ? 'method' : 'Call JS Msg',

? ? ? ? 'param1' : Msg,

? ? };

? ? window.webkit.messageHandlers.webViewApp.postMessage(message);

}

function jsFunc() {

? ? alert('Hello World');

}

iOS WKWebView 遠(yuǎn)端h5優(yōu)先加載本地資源_IOS開發(fā)-織夢(mèng)者

WKWebView實(shí)現(xiàn)網(wǎng)頁(yè)靜態(tài)資源優(yōu)先從本地加載 - JackLee18 - CSDN博客

iOS WKWebView 遠(yuǎn)端h5優(yōu)先加載本地資源 - AFun_day的博客 - CSDN博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容