iOS原生与H5交互

一、WKWebView

  WKWebView 初始化时,有一个参数叫configuration,它是WKWebViewConfiguration类型的参数,而WKWebViewConfiguration有一个属性叫userContentController,它又是WKUserContentController类型的参数。

   WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.preferences = [[WKPreferences alloc] init];
    config.preferences.minimumFontSize = 10;
    config.preferences.javaScriptEnabled = YES;
    config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
    config.userContentController = [[WKUserContentController alloc] init];
    config.processPool = [[WKProcessPool alloc] init];
    config.userContentController = [WKUserContentController new];
    //在创建wkWebView时,需要将被js调用的方法注册进去,oc与js端对应实现
    [config.userContentController addScriptMessageHandler:self name:@"callFunciton"];

    WKWebView *wkWebView = [[WKWebView alloc]initWithFrame:self.view.frame configuration:config];
    self.wkWebView = wkWebView;
    wkWebView.navigationDelegate = self;
    wkWebView.UIDelegate = self;
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:self.url];
    [wkWebView loadRequest:request];
    [self.view addSubview:wkWebView];

1.JS调用原生MessageHandler

WKUserContentController对象有一个方法

- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;

JS调用OC时,这句代码非常重要

// 在创建wkWebView时,需要将被js调用的方法注册进去,oc与js端对应实现
[config.userContentController addScriptMessageHandler:self name:@"callFunciton"];

  addScriptMessageHandler:name:有两个参数,第一个参数是userContentController的代理对象,第二个参数是JS里发送postMessage的对象。 
所以要使用MessageHandler功能,就必须要实现WKScriptMessageHandler协议。

1.实现WKScriptMessageHandler代理方法

  当js调用callFunction方法时,会回调此代理方法:

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
    if ([message.name isEqualToString:@"callFunction"]) {
        //调用原生扫码
    }
}

Tip:addScriptMessageHandler很容易引起循环引用,导致控制器无法被释放

- (void)dealloc{
    [self.wkWebView.configuration.userContentController removeScriptMessageHandlerForName:@"callFunction"];
}

2.JS中使用方法:

window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
//其中<name>,就是上面方法里的第二个参数`name`。
//例如我们调用API的时候第二个参数填@"callFunction",那么在JS里就是:
window.webkit.messageHandlers.callFunction.postMessage(<messageBody>)
//<messageBody>是一个键值对,键是body,值可以有多种类型的参数,body 的类型:Allowed types are NSNumber, NSString, NSDate, NSArray, NSDictionary, and NSNullmessageBody可以为NULL或者其他参数,不能什么都不写,否则不走代理方法

2.原生调用JS

 [self.webView evaluateJavaScript:@"show()" completionHandler:^(id _Nullable response, NSError * _Nullable error) {                  //TODO
 }];

3.WKNavigationDelegate

  可以在此通过连接的方式传递一些简单的参数,也是一种H5与原生交互

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {      NSString *url = navigationAction.request.URL.absoluteString;    if(![url isEqualToString:self.strURL]) {              // 页面跳转
   }
   decisionHandler(WKNavigationActionPolicyAllow);
}

二、WebViewJavaScriptBridge

WebViewJavaScriptBridge 用于 WKWebView & UIWebView 中 OC 和 JS 交互。
它的基本原理是: 把 OC 的方法注册到桥梁中,让 JS 去调用;把 JS 的方法注册在桥梁中,让 OC 去调用。

1. 初始化

1.导入头文件 #import <WebViewJavascriptBridge.h>

2.建立 WebViewJavaScriptBridge 和 WebView 之间的关系

_jsBridge = [WebViewJavascriptBridge bridgeForWebView:_webView];

3.在HTML 文件中,复制粘贴这两段 JS 函数

function setupWebViewJavascriptBridge(callback) {
  if (window.WebViewJavascriptBridge) {     return callback(WebViewJavascriptBridge);   }
  if (window.WVJBCallbacks) {     return window.WVJBCallbacks.push(callback);   }
  window.WVJBCallbacks = [callback]; // 创建一个 WVJBCallbacks 全局属性数组,并将 callback 插入到数组中。
  var WVJBIframe = document.createElement(‘iframe‘); // 创建一个 iframe 元素  WVJBIframe.style.display = ‘none‘; // 不显示  WVJBIframe.src = ‘wvjbscheme://__BRIDGE_LOADED__‘; // 设置 iframe 的 src 属性
  document.documentElement.appendChild(WVJBIframe); // 把 iframe 添加到当前文导航上。
  setTimeout(function() {     document.documentElement.removeChild(WVJBIframe)   }, 0)
}

    // 这里主要是注册OC将要调用的JS方法。
    setupWebViewJavascriptBridge(function(bridge){

    });

2. 注入OC、JS方法

往桥梁中注入 OC 方法

/* scanClick 是 OC block 的一个别名
*  block本身,是JS通过某种方式调用到scanClick的时候,执行的代码块
*  data,由于OC这端由JS调用,所以data是JS端传递过来的数据
*  responseCallback OC端的block 执行完毕之后,往JS端传递的数据
*/
[_jsBridge registerHandler:@"scanClick" handler:^(id data, WVJBResponseCallback responseCallback) {
  NSLog(@"dataFrom JS : %@",data[@"data"]);
  responseCallback(@"扫描结果 : www.baidu.com");
}];

往桥梁中注入 JS 函数

/*
*  estJavaScriptFunction: 是注入到桥梁中JS函数的别名,以供OC端调用。
*  data: 回调函数的data,既然JS函数由OC调用,所以data是OC端传递过来的数据。
*  responseCallback: JS调用在被OC调用完毕之后,向OC端传递的数据
*/
// 这里主要是注册 OC 将要调用的 JS 方法。
    setupWebViewJavascriptBridge(function(bridge){
        // 声明 OC 需要调用的 JS 方法。
        bridge.registerHanlder(‘testJavaScriptFunction‘,function(data,responseCallback){
            // data 是 OC 传递过来的数据.
            // responseCallback 是 JS 调用完毕之后传递给 OC 的数据
            alert("JS 被 OC 调用了.");
            responseCallback({data: "js 的数据",from : "JS"});
        })
    });

3. 调用OC、JS方法

OC调用JS

// 单纯的调用 JSFunction,不往 JS 传递参数,也不需要 JSFunction 的返回值。
[_jsBridge callHandler:@"changeBGColor"];
// 调用 JSFunction,并向 JS 传递参数,但不需要 JSFunciton 的返回值。
[_jsBridge callHandler:@"changeBGColor" data:@"把 HTML 的背景颜色改成橙色!!!!"];
// 调用 JSFunction ,并向 JS 传递参数,也需要 JSFunction 的返回值。
[_jsBridge callHandler:@"changeBGColor" data:@"传递给 JS 的参数" responseCallback:^(id responseData) {
  NSLog(@"JS 的返回值: %@",responseData);
}];

JS调用OC

// JS单纯的调用OC的block
WebViewJavascriptBridge.callHandler(‘scanClick‘);
// JS调用OC的block,并传递JS参数
WebViewJavascriptBridge.callHandler(‘scanClick‘,"JS 参数");
// JS调用OC的block,传递JS参数,并接受OC的返回值。
WebViewJavascriptBridge.callHandler(‘scanClick‘,{data : "这是JS传递到OC的扫描数据"},function(dataFromOC){
  alert("JS 调用了 OC 的扫描方法!");
  document.getElementById("returnValue").value = dataFromOC;
});

4. OC释放Block

OC中,在当前控制器消失的时候,要记得把注入到桥梁中的 OC block,从桥梁中删除,否则,可能会出现控制器无法释放的情况。

[_jsBridge removeHandler:@"scanClick"];

5.示例

1.JS -> OC 的交互

在 OC 中,通过 WebViewJavascriptBridge 注册一个修改 navigationBar 颜色的 Block

[_jsBridge registerHandler:@"colorClick" handler:^(id data, WVJBResponseCallback responseCallback) {
  self.navigationController.navigationBar.barTintColor = [UIColor colorWithRed:arc4random_uniform(256) / 255.0 green:arc4random_uniform(256) / 255.0 blue:arc4random_uniform(256) / 255.0 alpha:1.0];
  responseCallback(@"颜色修改完毕!");
}];

在 JS 中,通过某种方式去调用这个 OC 的 block。

WebViewJavascriptBridge.callHandler(‘colorClick‘,function(dataFromOC) {
  alert("JS 调用了 OC 注册的 colorClick 方法");
  document.getElementById("returnValue").value = dataFromOC;
})

OC -> JS 的交互

往桥梁中,注入一个修改 HTML body 颜色的 JSFunction。

// 在这里声明OC需要主动调用JS的方法。
setupWebViewJavascriptBridge(function(bridge) {
  bridge.registerHandler(‘changeBGColor‘,function(data,responseCallback){
    // alert(‘aaaaaa‘);
    document.body.style.backgroundColor = "orange";
    document.getElementById("returnValue").value = data;
   });
}); 

然后在 OC 端通过桥梁调用这个 changeBGColor

 [_jsBridge callHandler:@"changeBGColor" data:@"把 HTML 的背景颜色改成橙色!!!!"];

原文地址:https://www.cnblogs.com/liuluoxing/p/11769596.html

时间: 2024-07-29 21:01:31

iOS原生与H5交互的相关文章

iOS原生与H5交互WKWebView

一.原生与H5页面交互方式 登陆后将token放入wkwebview的cookie中.以后wkwebview也可以同步原生app的登陆状态了. 以下代码   @"document.cookie = 'UID=%@';document.cookie = 'CLIENT=App';document.cookie = 'TOKEN=%@'" 根据自己项目的cookie格式传递. 1 NSString *js = @"function clearCache(){localStorag

IOS 原生与HTML交互

跟原生开发相比,H5的开发相对来一个成熟的框架和团队来讲在开发速度和开发效率上有着比原生很大的优势,至少不用等待审核.那么问题来了,H5与本地原生代码势必要有交互的,比如本地上传一些信息,H5打开本地的页面,打开本地进行微信等第三方分享等,今天就简单讲一下iOS中本地UIWebView,WKWebView与H5的交互. DEMO地址:点击下载 UIWebView的交互 stringByEvaluatingJavaScriptFromString的使用 UIWebView在2.0时代就有的类,一直

ios和安卓H5交互桥接

ios交互 demo1(摘自网络) 1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"> 6 <

安卓原生与hml交互(WebView基础)

WebView加载页面 webView有两种加载方式, 加载网络地址 webView.loadUrl("www.xxx.com/index.html"); 加载本地资源 webView.loadUrl("file:///android_asset/example.html"); 添加请求头信息,在这里可以加入认证信息等等 Map<String,String> map=new HashMap<String,String>(); map.put(

iOS原生和H5的相互调用

为什么现在越来越多的APP中开始出现H5页面? 1,H5页面开发效率更高,更改更加方便: 2,适当缩小APP安装包的大小: 3,蹭热点更加方便,比如五一,十一,双十一搞活动: 那么为什么说H5无法取代原生的APP,只能处在一个共存的例子呢? 1,这个是由系统的底层决定的,极端例子,所有的应用都通过H5展示,那么你是否需要一个浏览器? 2,涉及庞大的功能,涉及复杂的逻辑结构,涉及安全性的要求,H5可以胜任吗? 所以,H5和原生的融合会出现动态的调和,最终会找到一个平衡. 那么接下来就说下iOS开发

webview和H5交互

由于H5的灵活多变,动态可配的特点,也为了避免冗长 的审核周期,H5页面在app上的重要性正日益突显. iOS应用于H5交互的控件主要是UIWebView及WKWebView WKWebView是14年随iOS8推出的,很好的解决了UIWebView加载速度慢,内存占用大的问题 WebViewJavaScriptBridge是一款轻量级的框架,使用它结合wkwebview能十分方便的实现源生与H5的交互 webviewJavaScrptBridge的基本使用 1.初始化需bind视图 [WebV

iOS与H5交互的方案

iOS与H5交互的方案 纵观所有iOS与H5交互的方案,有以下几种: 第一种:有很多的app直接使用在webview的代理中通过拦截的方式与native进行交互,通常是通过拦截url scheme判断是否是我们需要拦截处理的url及其所对应的要处理的功能是什么.任意版本都支持. 第二种:iOS7之后出了JavaScriptCore.framework用于与JS交互,但是不支持iOS6,对于还需要支持iOS6的app,就不能考虑这个了.若需要了解,看最后的推荐阅读. 第三种:WebViewJava

iOS与H5交互

前提:在oc控制器中加载UIWebView,设置代理,遵守UIWebViewDelegate协议. 一.iOS调用JS方法 通过iOS调用JS代码实现起来比较方便直接调用UIWebView的方法- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script; 1.查询标签 // 查询标签      NSString *str = @"var word = document.getElementByI

iOS与H5交互遇到的坑

之前的博客写过使用<JavaScriptCore/JavaScriptCore.h>类来实现与H5的交互,但是在项目中还是遇到了一些不得不踩的坑.在这里将我遇到的问题以及参考网上几位大神的解决方案列举出来,如果有更好的办法,欢迎讨论指正.在阅读本博客前,请参阅我之前的<iOS与H5交互>. 一.在webView中加载H5界面,在此webView中的H5一级界面可以轻松实现oc与js方法互调,但如果在H5界面上进入二级界面,在二级界面中再使用之前方法来交互就会失效.如图:左图为H5一