iOS WebView和JS的交互

前言

现在web前端发展越来越快,为了追求应用的快速开发和迭代,许多产品都会选择混合开发,在手机端嵌入web页面,那么这就会导致一个问题,
原生代码怎么和js交互?那么下边我们共同学习一下iOS和web是怎么交互的。

概述

  1. UIWebViewJavaScriptCore的结合使用。但是我们要知道JavaScriptCore这个框架是在iOS7之后官方才发布。
  2. iOS8之后的WKWebView的使用
  3. 请求路径拦截的使用(WebViewJavascriptBridge第三方库)

我们还需要先了解一下JavaScriptCore框架的基本使用

基本使用

1、UIWebView和js的交互

OC调用js

使用UIWebviewstringByEvaluatingJavaScriptFromString方法执行js代码,或注入js代码

js调用OC

1、使用UIWebview想要js调用OC代码我们只能通过拦截的方式,代码如下:

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSString *url = request.URL.absoluteString;
    if ([url rangeOfString:@"myProtocol://"
         ].location != NSNotFound) {
        NSLog(@"拦截成功了");
        return NO;
    }
    return YES;
}

2、 在iOS7之后我们可以使用JavaScriptCore进行和js的通信

使用方式

先创建一个JSProtocol协议,遵循JSExport协议,添加一个打印方法


@protocol JSProtocol 

-(void)print:(NSString *)str;

@end

创建一个MyJSObject对象,遵循JSProtocol,实现print方法

-(void)print:(NSString *)str
{
    NSLog(@"log=%@",str);
}

然后当web页面加载完毕的时候,通过[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]获取JSContext对象

OC代码如下:

-(void)webViewDidFinishLoad:(UIWebView *)webView
{
    self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
    
    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    NSLog(@"context=%@",context);
    self.context = context;
    // 为js增加log方法
    context[@"log"] = ^(NSString *str){
        NSLog(@"log:%@",str);
    };
    // 为js增加obj对象 遵循该协议jsExport
    MyJSObject *obj = [[MyJSObject alloc] init];
    context[@"obj"] = obj;
    // 为js增加changeLabel的函数
    context[@"changeLabel"] = ^(NSString *str){
        self.text.text = str;
    };
    
    context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
        NSLog(@"异常%@",exception);
    };
    
}

html代码





这里通过JSContextjs增加了logchangeLabel全局方法,挂载到window对象下边。当js调用log或者changeLabel方法时会执行block内的代码,当传入相应的参数,就可以达到jsOC传递参数和交互。

效果图

iOS WebView和JS的交互_第1张图片

2、WKWebView和js的交互

WKWebViewiOS8之后才有,所以如果你的app最低支持iOS可以尽情使用。

OC调用js

使用WKWebViewevaluateJavaScript方法执行js代码,或注入js代码

js调用OC

要想WKWebViewjs交互,需要用到WKUserContentController,下面我们来看一下如何初始化WKWebView

    // 创建配置对象
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    
    // 为WKWebViewConfiguration设置偏好设置
    WKPreferences *preferences = [[WKPreferences alloc] init];
    configuration.preferences = preferences;
    
    // 允许native和js交互
    preferences.javaScriptEnabled = YES;
    
    WKUserContentController *userContentController = [[WKUserContentController alloc] init];
    [userContentController addScriptMessageHandler:self name:@"event"];
    configuration.userContentController = userContentController;
    self.userContentController = userContentController;
    
    // 初始化webview
    WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 64, self.view.frame.size.width, 300) configuration:configuration];
    // 此处替换你本机的ip
    NSURL *url = [NSURL URLWithString:@"http://172.26.233.156:3001/wkWebView"];
    webView.navigationDelegate = self;
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
    [webView loadRequest:request];
    [self.view addSubview:webView];
    self.webView = webView;

首先我们先创建WKWebViewConfiguration配置对象,然后创建WKUserContentController对象,然后我们使用WKUserContentControlleraddScriptMessageHandler
注册要接收消息的名称,这样我们才可以在js代码中通过window.webkit.messageHandlers.名称.postMessage发送消息,那么OC怎么接收消息呢?

下边是接收消息的代理

// 接受js发送的消息
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSLog(@"%@,%@",message.name,message.body);
    NSString *name = message.name;
    if ([name isEqualToString:@"event"]) {
        // 打开相册
        if ([message.body isEqualToString:@"打开相册"]) {
            UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
            imagePickerController.delegate = self;
            [self.navigationController presentViewController:imagePickerController animated:YES completion:nil];
        }else {
            
        }
    }
}

一定要记得在dealloc方法移除监听名称

[self.userContentController removeScriptMessageHandlerForName:@"event"];

html代码



效果图


iOS WebView和JS的交互_第2张图片

源码

源码

这里边有两个工程,一个是iOS工程,一个是node工程,用来创建一个web服务器模拟加载远程的web项目

WebViewInteractiveIOS 目录是iOS
WebViewInteractiveWeb web项目

运行

iOS运行这里不多赘述,需要注意的是把webview加载的ip换成本机ip

web运行,执行如下命令,前提是装了node环境的机器

cd WebViewInteractiveWeb
npm install 
npm run server

3、 JSBridge的使用

源码

iOS端webview和jsbridge的使用实现

首先创建一个iOS工程,引入WebViewJavascriptBridge第三方框架,使用pod还是自己手动导入都可以

下面看一下具体实现

创建WKWebview,初始化WebViewJavascriptBridge,设置WebViewJavascriptBridge,WKWebView的代理

// 初始化webview
    WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
    // 此处替换你本机的ip
    NSURL *url = [NSURL URLWithString:kHOSTURL];
    webView.navigationDelegate = self;
    webView.UIDelegate = self;
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
    [webView loadRequest:request];
    [self.view addSubview:webView];
//  self.webView = webView;
    
    self.view.backgroundColor = [UIColor whiteColor];
    // 开启日志
    [WebViewJavascriptBridge enableLogging];
    
    self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
    [self.bridge setWebViewDelegate:self];
前端js手动注册和获取JSBridge
/*这段代码是固定的,必须要放到js中*/
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)
}
// 初始化jsbridge
setupWebViewJavascriptBridge(function(bridge) {
    global.bridge = bridge;// 获取到jsbridge;
})
OC调用js

首先需要js注册交互

this.$bridge.registerhandler('ocCallJs', (data, responseCallback) => {
        alert(data)
        responseCallback(data)
    });

iOS端需要WebViewJavascriptBridge使用callHandler调用js注册的方法

[self.bridge callHandler:@"ocCallJs" data:@"123" responseCallback:^(id responseData) {
        NSLog(@"responseData=%@",responseData);
    }];

js调用OC

需要iOS注册一个交互以供js回调

[self.bridge registerHandler:@"jsCallOc" handler:^(id data, WVJBResponseCallback responseCallback) {
        //将base64字符串转为NSData
        NSData *decodeData = [[NSData alloc]initWithBase64EncodedString:data options:NSDataBase64DecodingIgnoreUnknownCharacters];
        //将NSData转为UIImage
        UIImage *decodedImage = [UIImage imageWithData: decodeData];
        TwoController *twoCtr = [[TwoController alloc] init];
        twoCtr.view.backgroundColor = [UIColor purpleColor];
        [self.navigationController pushViewController:twoCtr animated:YES];
        twoCtr.image = decodedImage;
        
        if (responseCallback) {
            // 反馈给JS
            responseCallback(@{@"jsCallOc的参数1": @"jsCallOc的参数2"});
        }
    }];

js调用交互

this.$bridge.callhandler("jsCallOc",image.replace("data:image/jpeg;base64,",""),(responseData)=>{
          console.log("responseData",responseData);
        })

效果图


iOS WebView和JS的交互_第3张图片
1.gif

Hybrid之JSBridge的实现原理(WebViewJavascriptBridge源码分析)这一篇文章讲述了JSBridge的交互流程和WebViewJavascriptBridge的实现原理。有兴趣的小伙伴可以看这一篇文章,谢谢

其它推荐文章

React

react之组件的生命周期
react+webpack入门指南
react项目整合express+mock实现模拟接口数据
react+webpack4搭建前端项目(一)

RN项目

菜谱项目 源码
天气预报 源码

RN插件

键盘自适应插件 源码

小程序开发

小程序开发知识总结

扫下边的二维码可以天天领红包,以后点外卖什么的再也不用开会员了,从此省出一套房~
iOS WebView和JS的交互_第4张图片
qrcode.jpg

你可能感兴趣的:(iOS WebView和JS的交互)