话不多说,上代码
导入库
#import
1、WKWebView 创建 不注册 js 调用 OC 的方法
//初始化
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) ];
// UI代理
_webView.UIDelegate = self;
// 导航代理
_webView.navigationDelegate = self;
// 是否允许手势左滑返回上一级, 类似导航控制的左滑返回
_webView.allowsBackForwardNavigationGestures = YES;
//可返回的页面列表, 存储已打开过的网页
// WKBackForwardList * backForwardList = [_webView backForwardList];
Webview 加载本地HTML
NSString *path = [[NSBundle mainBundle] pathForResource:@"JStoOC.html" ofType:nil];
NSString *htmlString = [[NSString alloc]initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
//加载本地html文件
[_webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
Webview 加载网络HTML
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.chinadaily.com.cn"]];
[request addValue:[self readCurrentCookieWithDomain:@"http://www.chinadaily.com.cn"] forHTTPHeaderField:@"Cookie"];
[_webView loadRequest:request];
Webview 页面后退、前进和刷新
// 是否可以后退,返回 BOOL YES 可以后退, NO 第一页,不可以后退,可以做 pop webView 操作
if ([_webView canGoBack]) {
//页面后退
[_webView goBack];
}
else {
// pop webView 退出 webView 页面
}
// 是否可以前进,返回 BOOL YES 可以前进, NO 第一页,不可以前进
if ([_webView canGoForward]) {
//页面前进
[_webView goForward];
}
else {
// 没有下一页
}
//刷新当前页面
[_webView reload];
2、WKWebView 创建注册 js 调用 OC 的方法,
jsCallOCMethodNames
是一个 js 调用 OC 的方法名称的数组, 这些方法是不带返回值的,即void 方法,可以带参数
例如:JSCallOCMethod1(‘jsonString’){ }
jsCallOCMethodNames = @[@"JSCallOCMethod1",@"JSCallOCMethod2"];
防止循环引用 WebViewScriptMessageDelegate
所以创建一个弱引用的 WeakWebViewScriptMessageDelegate
// WKWebView 内存不释放的问题解决
@interface WeakWebViewScriptMessageDelegate : NSObject
//WKScriptMessageHandler 这个协议类专门用来处理JavaScript调用原生OC的方法
@property (nonatomic, weak) id scriptDelegate;
- (instancetype)initWithDelegate:(id)scriptDelegate;
@end
@implementation WeakWebViewScriptMessageDelegate
- (instancetype)initWithDelegate:(id)scriptDelegate {
self = [super init];
if (self) {
_scriptDelegate = scriptDelegate;
}
return self;
}
#pragma mark - WKScriptMessageHandler
//遵循WKScriptMessageHandler协议,必须实现如下方法,然后把方法向外传递
//通过接收JS传出消息的name进行捕捉的回调方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([self.scriptDelegate respondsToSelector:@selector(userContentController:didReceiveScriptMessage:)]) {
[self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}
}
@end
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
WKUserContentController *wkUController = [[WKUserContentController alloc] init];
//以下代码适配文本大小,由UIWebView换为WKWebView后,会发现字体小了很多,这应该是WKWebView与html的兼容问题,解决办法是修改原网页,要么我们手动注入JS
NSString *jSString = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
//用于进行JavaScript注入
WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
[wkUController addUserScript:wkUScript];
// 创建一个弱引用的 WeakWebViewScriptMessageDelegate 防止循环引用
WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] init];
for (NSString *methodName in jsCallOCMethodNames) {
// 添加方法名监听 (主要是这步)
[wkUController addScriptMessageHandler:weakScriptMessageDelegate name:methodName];
}
config.userContentController = wkUController;
//初始化
_webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) configuration:config];
// UI代理
_webView.UIDelegate = self;
// 导航代理
_webView.navigationDelegate = self;
// 是否允许手势左滑返回上一级, 类似导航控制的左滑返回
_webView.allowsBackForwardNavigationGestures = YES;
//可返回的页面列表, 存储已打开过的网页
// WKBackForwardList * backForwardList = [_webView backForwardList];
核心代码是 [config.userContentController addScriptMessageHandler:self name:methodName]
这样就添加了一个 JS
调用 OC
的方法监听,当 JS
调用方法时,通过WKScriptMessageHandler
代理方法来获取 JS
调用 OC
的方法的处理
JS
主动调用 OC
的方法的处理
OC
代码
处理添加监听的方法名,即 JS
主动调用 OC
的方法
#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage *)message {
// message.name 添加监听的方法名
if ([message.name isEqualToString: @"JSCallOCMethod1"]) {
// message.body 是 `js` 传递的参数 ,一般是 json 字符串
NSLog(@"MessageBody: %@", message.body);
}
}
JS
代码
核心代码
window.webkit.messageHandlers.<添加监听的方法名>.postMessage(参数);
如何不需要参数 postMessage(' ') 这样处理
window.webkit.messageHandlers.JSCallOCMethod1.postMessage({"key1":"value1","key2":"value2"});
OC
主动调用 JS
的方法的处理
// OC 调用 JS 方法 并传参数 jsonString, 当不需要参数时,可以 ('') 这样处理
[self.webView evaluateJavaScript: @"OCCallJSMethod('jsonString')"
completionHandler:^(id response, NSError * error) {
NSLog(@"response: %@, \nerror: %@", response, error);
}];
当 JS
需要调用 OC
带有参数和返回值的方法时
JS
代码
1、代用参数需要返回值的方法
let jsonString = window.prompt("jsCallOCReturnJsonStringMethod","参数jsonString");
// jsonString 就是 OC 返回的 jsonString
2、没有参数需要返回值的方法
let jsonString = window.prompt("jsCallOCReturnJsonStringMethod");
// jsonString 就是 OC 返回的 jsonString
OC
代码
这种方法不需要注册监听,是使用 UIDelegate 方法
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler {
if (prompt) {
// defaultText 是JS 传的JsonString参数
if (defaultText.length > 0) {
// 说明有参数
}
if ([prompt isEqualToString:@"jsCallOCReturnJsonStringMethod"]) {
completionHandler(@"返回的结果,可以自定义");
}
}
webview 设置 userAgent
WKWebView *webView = [WKWebView new];
[webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id _Nullable oldAgent, NSError * _Nullable error) {
if (![oldAgent isKindOfClass:[NSString class]]) {
// 为了避免没有获取到oldAgent,所以设置一个默认的userAgent
// Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148
oldAgent = [NSString stringWithFormat:@"Mozilla/5.0 (%@; CPU iPhone OS %@ like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E216", [[UIDevice currentDevice] model], [[[UIDevice currentDevice] systemVersion] stringByReplacingOccurrencesOfString:@"." withString:@"_"]];
}
NSString *userAgentSuffix = @"自己想要拼接的标识";
//自定义user-agent
if (![oldAgent hasSuffix:userAgentSuffix]) {
NSString *newAgent = [oldAgent stringByAppendingFormat:@" %@",userAgentSuffix];;
[[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent":newAgent}];
[[NSUserDefaults standardUserDefaults] synchronize];
// 一定要设置customUserAgent,否则执行navigator.userAgent拿不到oldAgent
webView.customUserAgent = newAgent;
}
}];
HTML 测试文件源码
Title of this page
// 防止 汉字在 APP 端乱码
This is my first try to write Html5 file.
This text is bold