H5如何与原生App(ios,安卓,RN)通信?

使用iframe方式,以唤起Native;以唤起分享组件为例

// h5 js code 将它封装一下

function createIframe(url){

var url = ‘jsbridge://getShare?title=分享标题&desc=分享描述&link=http%3A%2F%2Fwww.douyu.com&cbName=jsCallClientBack’;

var iframe = document.createElement(‘iframe’);

iframe.style.width = ‘1px’;

iframe.style.height = ‘1px’;

iframe.style.display = ‘none’;

iframe.src = https://segmentfault.com/a/url;

document.body.appendChild(iframe);

setTimeout(function() {

iframe.remove();

}, 100);

}

然后客户端通过拦截这个请求,并且解析出相应的方法和参数:这里以ios为例:

// IOS swift code

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {

let url = request.URL

let scheme = url?.scheme

let method = url?.host

let query = url?.query

if url != nil && scheme == “jsbridge” {

switch method! {

case “getShare”:

self.getShare()

default:

print(“default”)

}

return false

} else {

return true

}

}

看不懂就略过,非重点。。。。。

这里我们在请求参数中加上了cbName=jsCallClientBack,这个jsCallClientBack为JS调用客户端所定义的回调函数,在业务层jsBridge封装中,我们传入一个匿名函数作为回调,底层将这个函数绑定在window的jsbridge对象下并为其定义一个独一无二的key,这个key就是jsCallClientBack,客户端在处理完逻辑后,会通过上面已经介绍过的方法来回调window下的方法。

ps: 在将回调绑定在window下时,特别注意要使用bind保持函数内this的原有指向不变

IOS客户端调用H5方法


Native调用Javascript语言,是通过UIWebView组件的stringByEvaluatingJavaScriptFromString方法来实现的,该方法返回js脚本的执行结果。

// IOS swift code

webview.stringByEvaluatingJavaScriptFromString(“window.methodName()”)

从上面代码可以看出它其实就是执行了一个字符串化的js代码,调用了window下的一个对象,如果我们要让native来调用我们js写的方法,那这个方法就要在window下能访问到。但从全局考虑,我们只要暴露一个对象如JSBridge给native调用就好了。

调用客户端原生方法的回调函数也将绑在window下供客户端成功反调用,实际上一次调用客户端方法最后产生的结果是双向互相调用。

H5调用Android客户端方法


在安卓webView中有三种调用native的方式:

通过schema方式,客户端使用shouldOverrideUrlLoading方法对url请求协议进行解析。这种js的调用方式与ios的一样,使用iframe来调用native方法。通过在webview页面里直接注入原生js代码方式,使用addJavascriptInterface方法来实现。

// android JAVA code

class JSInterface {

@JavascriptInterface

public String getShare() {

//…

return “share”;

}

}

webView.addJavascriptInterface(new JSInterface(), “AndroidNativeApi”);

上面的代码就是在页面的window对象里注入了AndroidNativeApi对象。在js里可以直接调用原生方法。

使用prompt,console.log,alert方式,这三个方法对js里是属性原生的,在android webview这一层是可以重写这三个方法的。一般我们使用prompt,因为这个在js里使用的不多,用来和native通讯副作用比较少。

// android JAVA code

class WebChromeClient extends WebChromeClient {

@Override

public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {

// 重写window下的prompt,通过result返回结果

}

@Override

public boolean onConsoleMessage(ConsoleMessage consoleMessage) {

}

@Override

public boolean onJsAlert(WebView view, String url, String message, JsResult result) {

}

}

一般而言安卓客户端选用1、2方案中的一种进行通信,从前端层面来讲,推荐客户端都使用schema协议的方式,便于前端jsBridge底层代码的维护与迭代。

Android客户端调用H5方法


在安卓APP中,客户端通过webviewloadUrl进行调用:

// android JAVA code

webView.loadUrl(“javascript:window.jsBridge.getShare()”);

H5端将方法绑定在window下的对象即可,无需与IOS作区分

H5调用RN客户端


我们知道RN的webView组件实际上就是对原生容器的二次封装,因此我们不需要直接通过schema协议来通信,只需要使用浏览器postMessage、onMessage来传递消息即可,类似于iframe,而真正的通信过程RN已经帮我们做了。

// h5 js code

window.postMessage(data);

// rn js code

<WebView

ref=“webView”

source={require(‘…/html/index.html’)}

injectedJavaScript={‘window.androidConfig = {}’}    // 通过这个props可以在webView初始化时注入属性方法

onMessage={e => {

let { data } = e.nativeEvent;

//…

}}

/>

RN客户端调用H5


postMessage是双向的,所以也可以在RN里发消息,H5里接消息来触发对应的回调

this.refs.webView.postMessage({

cbName: ‘xxx’,

param: {}

});

前端jsBridge的封装


在了解了js与客户端底层的通信原理后,我们可以将IOS、安卓统一封装成jsBridge提供给业务层开发调用。

class JsBridge {

static lastCallTime

constructor() {

if (UA.isReactNative()) {

document.addEventListener(‘message’, function(e) {

window.jsClientCallBacke.data.cbName;

});

}

}

// 通用callNtive方法

callClient(functionName, data, callback) {

// 避免连续调用

if (JsBridge.lastCallTime && (Date.now() - JsBridge.lastCallTime) < 100) {

setTimeout(() => {

this.callClient(functionName, data, callback);

}, 100);

return;

}

JsBridge.lastCallTime = Date.now();

data = data || {};

if (callback) {

const cbName = randomName();

Object.assign(data, { cbName });

window.jsClientCallBack[cbName] = callBack.bind(this);

}

if (UA.isIOS()) {

data.forEach((key, value) => {

try {

data[key] = JSON.stringify(value);

} catch(e) { }

});

var url = ‘jsbridge://’ + functionName + ‘?’ parseJSON(data);

var iframe = document.createElement(‘iframe’);

iframe.style.width = ‘1px’;

iframe.style.height = ‘1px’;

iframe.style.display = ‘none’;

iframe.src = url;

document.body.appendChild(iframe);

setTimeout(() => {

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
usjYiN5C-1715621840031)]

[外链图片转存中…(img-gUi5EpLm-1715621840033)]

[外链图片转存中…(img-Dm7DERqb-1715621840034)]

[外链图片转存中…(img-WnfRUyi4-1715621840035)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 28
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值