OC与JS交互,总结就是下面的图:
Demo演示地址: github.com/tanghaitao/…
- webView底层是 http 2.0 12.0
性能不佳
- WK 底层是webKit 苹果内核 操作要多一些配置,
性能更好
1. WebView
Demo演示地址: github.com/tanghaitao/…
// webView底层是 http 2.0 12.0 性能不佳 WK 底层是webKit 苹果内核 操作要多一些 配置
self.webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
self.webView.delegate = self;
[self.view addSubview:self.webView];
NSURL *url = [[NSBundle mainBundle] URLForResource:@"index.html" withExtension:nil];
NSURLRequest *reqeust = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:reqeust];
// NSString *path = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
// NSString *htmlString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
// [self.webView loadHTMLString:htmlString baseURL:nil];
执行顺序:
shouldStartLoadWithRequest // 控制是否加载
****************华丽的分界线****************
开始加载咯!!!! //webViewDidStartLoad
****************华丽的分界线****************
加载完成了咯!!!! // webViewDidFinishLoad
// 开始加载
- (void)webViewDidStartLoad:(UIWebView *)webView{
//可以加载progress,这里因为html还没加载完成,所以不能获取html的元素
}
// 加载完成
- (void)webViewDidFinishLoad:(UIWebView *)webView{
NSString *title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];// 放到上面的代理函数则没有效果
self.title = title;
}
// 加载所有请求数据,以及控制是否加载
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
//navigationType JS响应的样式 点击,提交,返回,刷新,重复提交,其他等都可以拦截到.
// request : host + 路由 : 拦截,不加载
return NO;// 拦截,不执行请求
}
1.2 OC ---> JS
- (IBAction)didClickRightItemClick:(id)sender {
NSLog(@"响应按钮");
// OC --> JS
NSLog(@"%@",[self.webView stringByEvaluatingJavaScriptFromString:@"showAlert('mumu')"]);
}
index.html
<script>
function showAlert(name){
alert('我是弹窗'+ name);
}
</script>
1.2 JS ---> OC
在模拟器中 点击html页面的 点击跳转效应OC方法
按钮
<a href="tzedu://getSum:/helloword/js">点击跳转效应OC方法</a>
就会调用shouldStartLoadWithRequest
// 加载所有请求数据,以及控制是否加载
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
}
po request
<NSMutableURLRequest: 0x600003a80ad0> { URL: tzedu://getSum/helloword/js }
NSURL的三个重要属性
NSString *urlStr = @"https://www.baidu.com/photos";
NSURL *url2 = [NSURL URLWithString:urlStr];
NSLog(@"scheme :%@, host :%@, relativePath :%@",url2.scheme,url2.host,url2.relativePath);
打印结果: scheme :https, host :www.baidu.com, relativePath :/photos
// http://www.example.com/index.html -> http
// tzedu://getPlus/helloword/js -> tzedu
2. JavaScriptCoreDemo
2.1 JS ---> OC
Demo地址: github.com/tanghaitao/…
#import <JavaScriptCore/JavaScriptCore.h>
@property (nonatomic, strong) JSContext *jsContext;
- (void)webViewDidFinishLoad:(UIWebView *)webView{
NSString *titlt = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
self.title = titlt;
//JSContext就为其提供着运行环境 H5上下文
JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
self.jsContext = jsContext;
// token userID
[jsContext evaluateScript:@"var arr = ['NSLog','隼龙','叶秋']"];
//点击了弹框按钮...NSLog,隼龙,叶秋,
// 监听 js的函数的实现 js -> oc
jsContext[@"showMessage"] = ^{
NSArray *arr = [JSContext currentArguments];
NSLog(@"=====%@",arr);
};
}
2.2 OC ---> JS
- (IBAction)didClickRightItemAction:(id)sender {
NSLog(@"响应");
// OC 调 JS
[self.jsContext evaluateScript:@"submit()"];
}
index.html
<script>
function showAlert(){
showMessage("点击了弹框按钮..."+arr);
}
function submit(){
alert('submit');
}
function ocCalljs(dict){
var name = dict['name'];
var age = dict['age'];
alert(name + age);
// 传回去
showDict(dict)
}
</script>
alert('submit');
更多处理,请参考Demo。
3. WKWebView
Demo地址: github.com/tanghaitao/…
WKWebView主要是注意 跨域Cookie失效的问题,解决方法是在原来的cookie上再添加新的数据,具体代码自己网上搜索
一般是使用WKWebViewConfiguration初始化,可以设置request:
#import <WebKit/WebKit.h>
@interface WKMessageHandleVC ()<WKUIDelegate,WKScriptMessageHandler>
@property (strong, nonatomic) WKWebView *webView;
@end
- (void)viewDidLoad {
[super viewDidLoad];
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
NSString *jScript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
WKUserContentController *wkUController = [[WKUserContentController alloc] init];
[wkUController addUserScript:wkUScript];
//比例,大小适应设备尺寸
config.userContentController = wkUController;
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
self.webView.navigationDelegate = self;
self.webView.UIDelegate = self;
[self.view addSubview:self.webView];
NSURL *url = [[NSBundle mainBundle] URLForResource:@"index.html" withExtension:nil];
[self.webView loadFileURL:url allowingReadAccessToURL:url];
}
设置title:
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
self.title = webView.title;
}
由于js的弹框界面不是很好看,推荐使用oc的弹框:
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:nil];
}
3.1 OC --> JS
NSString *jsStr2 = @"var arr = [3, 'haitao', 'abc']; ";
// oc -> js
[self.webView evaluateJavaScript:jsStr2 completionHandler:^(id _Nullable result, NSError * _Nullable error) { NSLog(@"%@----%@",result, error); }];
3.2 JS --> OC (不拦截)
3.2.1 拦截请求(非常规)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
// 拦截 -- 超链接 -- 自定义
// if (路由) {
//
// NSLog(@"%@",navigationAction.request);
//
// decisionHandler(WKNavigationActionPolicyCancel);
//
// }
decisionHandler(WKNavigationActionPolicyAllow);
}
3.2.2 不拦截请求(常规处理方法)
一般wkwebview处理事件handle,在类WKMessageHandleVC.m
中,
index.html
<script>
function loadURL(url) {
var iFrame;
iFrame = document.createElement("iframe");
iFrame.setAttribute("src", url);
iFrame.setAttribute("style", "display:none;");
iFrame.setAttribute("height", "0px");
iFrame.setAttribute("width", "0px");
iFrame.setAttribute("frameborder", "0");
document.body.appendChild(iFrame);
iFrame.parentNode.removeChild(iFrame);
iFrame = null;
}
function showAlert(messgae){
alert('我是一个可爱的弹框 \n'+messgae+'\n'+arr[1]);
return "token";
}
function submit(){
alert('<<<<提示框>>>>>');
loadURL("tzedu://jsCallOC?username=Cooci&password=123456");
}
function messgaeHandle(){
// JS --> OC
// ANDROID
window.webkit.messageHandlers.messgaeOC.postMessage("haitao 消息");
}
</script>
JS文件中 JS --> OC的关键代码:
function messgaeHandle(){
// JS --> OC
// ANDROID
window.webkit.messageHandlers.messgaeOC.postMessage("haitao 消息");
}
window.webkit.messageHandlers.messgaeOC.postMessage
webkit内核处理类messageHandlers,
messgaeOC对应viewWillAppear
中的name:@"messgaeOC"
-
点击html页面中的按钮 message,报错
-[WKMessageHandleVC userContentController:didReceiveScriptMessage:]: unrecognized selector sent to instance 0x7fe02740aa60
需要在oc中执行代理函数[WKMessageHandleVC userContentController:didReceiveScriptMessage:]
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
NSLog(@"%@---%@",message.name,message.body); //messgaeOC---haitao 消息
// 展示不出来 -- 会打开 : iframe
// if (message.name) {
// <#statements#>
// }
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"messgaeOC"];
}
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"messgaeOC"];
}
上面的需要成对出现,如果不调用disappear会导致循环引用。
4. WebViewJavascriptBridge
Demo地址: github.com/tanghaitao/…
从uiwebview直接过渡到wkwebview,处理逻辑(拦截请求,非拦截代理函数)不需要重新修改
pod 'WebViewJavascriptBridge', '~> 6.0.3'
+ (instancetype)bridge:(id)webView {
#if defined supportsWKWebView
if ([webView isKindOfClass:[WKWebView class]]) {
return (WebViewJavascriptBridge*) [WKWebViewJavascriptBridge bridgeForWebView:webView];
}
#endif
//#define WVJB_WEBVIEW_TYPE UIWebView
if ([webView isKindOfClass:[WVJB_WEBVIEW_TYPE class]]) {
WebViewJavascriptBridge* bridge = [[self alloc] init];
[bridge _platformSpecificSetup:webView];
return bridge;
}
[NSException raise:@"BadWebViewType" format:@"Unknown web view type."];
return nil;
}
4.1 JS-->OC
#import "ViewController.h"
#import <WebViewJavascriptBridge.h>
#import <WebKit/WebKit.h>
// An iOS/OSX bridge for sending messages between Obj-C and JavaScript in WKWebViews, UIWebViews & WebViews.
@interface ViewController ()<WKUIDelegate,WKNavigationDelegate>
@property (strong, nonatomic) WKWebView *webView;
@property (nonatomic, strong) WebViewJavascriptBridge *wjb;
@end
// JS-->OC
self.wjb = [WebViewJavascriptBridge bridgeForWebView:self.webView];
[self.wjb setWebViewDelegate:self];
[self.wjb registerHandler:@"jsCallsOC" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"%@---%@----%@",[NSThread currentThread],data,responseCallback);
}];
index.html文件:
<script>
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}
setupWebViewJavascriptBridge(function(bridge) {
// JS 被调用的方法 OCCallJSFunction 定义的标识
bridge.registerHandler('OCCallJSFunction', function(data, responseCallback) {
alert('JS方法被调用:'+data);
responseCallback('js执行过了');
})
})
function showWBJ(){
WebViewJavascriptBridge.callHandler('jsCallsOC', {'haitao': '18'}, function(response) {
alert(response);
})
}
</script>
点击按钮'提交', WebViewJavascriptBridge.callHandler('jsCallsOC', {'haitao': '18'},funx x x
,就会响应oc中注册的jsCallsOC
处理请求
4.2 OC --> JS
[self.wjb callHandler:@"OCCallJSFunction" data:@"糊涂蛋" responseCallback:^(id responseData) {
NSLog(@"%@--%@",[NSThread currentThread],responseData);
}];
更多处理,比如WKNavigationDelegate
,请参考Demo
5. WebViewJavascriptBridgeUIWebView
自行学习,具体用法参照Demo
6. CordovaWebView
自行学习,具体用法参照Demo