H5与原生APP交互

您所在的位置:网站首页 h5和原生app的区别 H5与原生APP交互

H5与原生APP交互

2023-04-14 10:26| 来源: 网络整理| 查看: 265

前言

在前端进行开发H5页面的时候,常常会有一些需要内嵌到APP的H5页面。在APP中使用H5页面主要是由于它是运行在浏览器上,所以只需要开发一次便可以在不同的操作系统上显示,并且迭代版本很方便。开发成本比较低。

在开发的过程中,经常需要和APP进行交互。本文已H5的角度整理了双方交互,如有不全面欢迎补充指正,大致将交互分为这两种情况:

单向通信的交互 不满足于单项传参需要return和callback的交互。 单向通信的交互

单向通信又分为不需要传参的通信以及需要传参的通信。

不需要传参的通信

只是需要在原生和H5页面之间完成跳转页面的动作,不需要互相进行数据的传递:

原生跳H5:将H5对应的URL给移动端同学即可 H5跳原生:location.herf = 要跳转的原生页面对应的协议名 示例: // H5 window.location = 'app://login'; // 原生(以IOS端为例) - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { // 一般用作交互的链接都会有一个固定的协议头,这里我们一“app”作为协议头为了,实际项目中可以修改 if ([scheme isEqualToString:@"app"]) { // scheme为“app”说明是做交互的链接 if ([host isEqualToString:@"login"]) { // host为“login”对应的就是登录操作 NSDictionary *paramsDict = [request.URL getURLParams]; UIAlertView *alert = [[UIAlertView alloc] [alert show]; } return YES; } 复制代码

需要传参的通信 H5与APP需要进行单向的数据传递,这里介绍两种方式:

url传参:

将参数携带在H5url后面或者app协议后面,对需要的参数进行拦截过滤便可在各自的开发环境中使用了

H5向原生传参示例: // H5 window.location = 'app://login?account=13011112222&password=123456'; //将参数拼接到协议后面 // 原生(以IOS端为例) - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString *scheme = request.URL.scheme; NSString *host = request.URL.host; // 一般用作交互的链接都会有一个固定的协议头,这里我们一“app”作为协议头为了,实际项目中可以修改 if ([scheme isEqualToString:@"app"]) { // scheme为“app”说明是做交互的链接 if ([host isEqualToString:@"login"]) { // host为“login”对应的就是登录操作 NSDictionary *paramsDict = [request.URL getURLParams]; NSString *account = paramsDict[@"account"]; NSString *password = paramsDict[@"password"]; NSString *msg = [NSString stringWithFormat:@"执行登录操作,账号为:%@,密码为:%@", account, password]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"原生弹窗" message:msg delegate:nil cancelButtonTitle:@"好" otherButtonTitles:nil, nil]; [alert show]; } return YES; } 复制代码 window传参:

因为 app 是宿主,可以直接访问 h5,所以这种调用比较简单,就是在 h5 中曝露一些全局对象(包括方法),然后在原生 app 中调用这些对象。

原生调用H5示例: // H5 window.sdk= { double = value => value * 2 trible = value => value * 3 } // 原生(以IOS端为例) NSString *func = @"window.sdk.double(10)"; NSString *str = [webview stringByEvaluatingJavaScriptFromString:func];// 20 复制代码H5调用原生示例: // 原生(以IOS端为例) @interface AppSdk : NSObject {} - (int) double:(int)value; - (int) triple:(int)value; @end @implementation AppSdk - (int) double:(int)value { return value * 2; } - (int) triple:(int)value { return value * 3; } @end JSContext *context=[webview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; AppSdk *appSdk = [AppSdk new]; context[@"appSdk"] = appSdk; H5: window.appSdk.double(10); // 20 复制代码 双向通信的交互

上面说的单向通信的交互通常会使一个简单的方法变得非常割裂,在一些稍微复杂的场景之下,双端的维护成本很高,因此通常我们使用双向通信的时候更多一些。我们可以在回调函数中做很多事情。这里就要提到大家耳熟能详的WebViewJavaScriptBridge:

WebViewJavaScriptBridge基本原理 WebViewJavaScriptBridge准备工作 WebViewJavaScriptBridge原生调用H5 WebViewJavaScriptBridgeH5调用原生 基本原理

WebViewJavaScriptBridge的基本原理简单来说就是,建立一个桥梁,然后注册自己,调用他人。

把 OC 的方法注册到桥梁中,让 JS 去调用。

把 JS 的方法注册在桥梁中,让 OC 去调用。

准备工作

js初始化:

将下面这两段函数贴进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){ }); 复制代码 原生调用H5

原生要调用H5的js需要两个步骤。首先js要注入一个方法a到桥梁中去。第二步当然就是在原生那边去调用桥梁中的方法a了。

往桥梁中注入js的a方法

在上面准备工作的时候,我们提到了,js中的第二段函数是要注册OC将要调用的JS方法的,具体的操作如下:

// 往桥梁中注入js方法a setupWebViewJavascriptBridge(function(bridge){ // 声明 OC 需要调用的 JS 方法。 bridge.registerHanlder('a',function(data,responseCallback){ // data 是 OC 传递过来的数据. // responseCallback 是调用完毕之后传递给 OC 的数据 alert("JS 被 OC 调用了."); responseCallback({jsdata: "js 的数据",from : "JS"}); }) }); }); 复制代码

OC调用桥梁中的a方法

[_jsBridge callHandler:@"a" data:@"传递给 JS 的参数" responseCallback:^(id responseData) { NSLog(@"JS 的返回值: %@",responseData); }]; 复制代码 H5调用原生

H5调用原生同样是两个步骤。注册自己,调用他人。

往桥梁中注入OC的b方法

[_jsBridge registerHandler:@"b" handler:^(id data, WVJBResponseCallback responseCallback) { // data 是 JS 传递过来的数据. // responseCallback 是调用完毕之后传递给 js 的数据 responseCallback(@"传给js的值"); }]; 复制代码

JS调用桥梁中的b方法

WebViewJavascriptBridge.callHandler('b',{data : "传给 OC 的入参"},function(dataFromOC){ alert("JS 调用了 OC 的方法"); alert('调用结束后OC返回给JS的数据:', dataFromOC); }); 复制代码 调用方式

OC调JS的三种方式

// 单纯的调用 JSFunction,不往 JS 传递参数,也不需要 JSFunction 的返回值。 [_jsBridge callHandler:@"a"]; // 调用 JSFunction,并向 JS 传递参数,但不需要 JSFunciton 的返回值。 [_jsBridge callHandler:@"a" data:@"传给js的入参"]; // 调用 JSFunction ,并向 JS 传递参数,也需要 JSFunction 的返回值。 [_jsBridge callHandler:@"a" data:@"传递给 JS 的参数" responseCallback:^(id responseData) { NSLog(@"JS 的返回值: %@",responseData); }]; 复制代码

JS调OC的三种方式

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


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3