动态卡 jsbridge

您所在的位置:网站首页 js动态添加表单样式失效 动态卡 jsbridge

动态卡 jsbridge

2023-03-08 18:51| 来源: 网络整理| 查看: 265

桥介绍两种通过 webview 实现桥的方式js 调用安卓方法安卓调用 js 方法前端注意点

动态卡片是以前端开发页面(视频放在客户端),内嵌在客户端的 webview 中的形式实现的,即混合开发。涉及到两大类技术:原生Native、Web H5

原生技术主要指iOS、Android,原生开发效率较低,两端同步,开发完成需要重新打包整个App,发布后依赖用户的更新,性能较高功能覆盖率更高,但是成本也更高Web H5主要由HTML、CSS、JavaScript组成(react、vue),Web可以更好的实现发布更新,跨平台也更加优秀,但性能较低,特性也受到限制

混合开发的意义就在于吸取两者的优点,原生为 h5 赋能。而且随着手机硬件的升级迭代、系统对于Web新特性的支持更好,H5的劣势被逐渐缩小 。日常开发中 h5 的改动较多,需求频繁,客户端相对改动较小,h5 打包发布可以与客户端分开独立运行,提升开发效率。

常见渲染形式

原生渲染的混合App(ReactNative、UniApp)小程序

其中的原生、Web相互通信都离不开JSBridge,这里面小程序比较特殊,对于 UI 渲染和 JS 逻辑的执行环境做了隔离,纯 native 层做数据通信,网络请求,数据检测,这里先不进行讨论。

在混合开发下,页面和客户端需要通信,例如 h5 页面需要获取通讯录,调用相机、蓝牙等功能;客户端执行完操作后,也需要通知前端页面执行回调操作,和js进行通信(js 运行在 webview 中或者 jsCore 中),实现两端的通讯方式就是 jsbridge。客户端和前端约定好协议,通过 jsbridge,前端可以调用客户端的接口,客户端也可以调用前端的方法。

介绍两种通过 webview 实现桥的方式 拦截 url原理

因为我们是在 webview 中发出的请求,而 weiview 是客户端创建的,所以客户端侧能监听到发出请求的具体路径,前端和 native 侧约定好协议名,比如:kuaishou://showToast?text=hello&callback=showToastCB,通过 iframe 发出请求时,拼接上字符串参数,客户端拿到数据执行原生操作,最后调用前端的回调函数,完成通信。

为什么使用 iframe 方式发送请求呢?

常见发送请求的方式

a 标签location.href 跳转iframe.src 发送 ajax 请求

这些方法,a 标签需要用户主动操作,location.href 可能会引起页面的跳转丢失调用,发送 ajax 请求 Android 没有相应的拦截方法,所以使用 iframe.src 是经常会使用的方案

这种方式兼容性很好,但是由于是基于 URL 的方式,连接长度会受到限制,数据格式有限制,而且建立请求有时间耗时。

Android 的话,Webview 提供了 shouldOverrideUrlLoading 方法来提供给 Native 拦截 H5 发送的 URL Scheme 请求。代码如下:

public class CustomWebViewClient extends WebViewClient {@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) { // 拦截请求、接收 scheme if (url.equals("xxx")) { // handle ... // callback view.loadUrl("javascript:actionJSMethod(" + json + ");") returntrue; } returnsuper.shouldOverrideUrlLoading(url); }}

iOS 的 WKWebview 可以根据拦截到的 URL Scheme 和对应的参数执行相关的操作。代码如下: ```objectivec

(void)webView:(WKWebView )webView decidePolicyForNavigationAction:(WKNavigationAction )navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{ // url 是否 xxx 开头 if ([navigationAction.request.URL.absoluteString hasPrefix:@”xxx”]) { [[UIApplication sharedApplication] openURL:navigationAction.request.URL]; } decisionHandler(WKNavigationActionPolicyAllow); } ``` 全局注入

这种方式会通过 webView 提供的接口,App 将 Native 的相关接口注入到 JS 的 Context(window)的对象中,一般来说这个对象内的方法名与 Native 相关方法名是相同的,Web 端就可以直接在全局 window 下使用这个全局 JS 对象,进而调用原生端的方法。

js 调用安卓方法

Android 的 Webview 提供了 addJavascriptInterface 方法,支持 Android 4.2 及以上系统

// 安卓侧// 注入全局 JS 对象 KwaiAdwebView.addJavascriptInterface(new KSAdJSBridge(this), "KwaiAd");class KSAdJSBridge { private Context ctx; KSAdJSBridge(Context ctx) { this.ctx = ctx; } // 增加JS调用接口 @JavascriptInterface public void showToast(String text) { new AlertDialog.Builder(ctx).setMessage(text).create().show(); }}// 前端侧调用window.KwaiAd.showToast('hello'); // 参数可以穿个对象,告诉客户端回调函数的名字

创建 webview, 注入全局对象,加载 html 页面

安卓调用 js 方法

在 4.4 以前,通过 loadUrl 方法,执行一段 JS 代码来实现。在 4.4 以后,可以使用 evaluateJavascript 方法实现。loadUrl 方法使用起来方便简洁,但是效率低无法获得返回结果且调用的时候会刷新 WebView

1.evaluateJavascript 执行 JS 方法时,网页必须加载完毕 2.网页中的 JS 方法是全局方法 // 前端定义全局方法function getGreetings(str) { return str;}// 安卓侧private void testEvaluateJavascript(WebView webView) { webView.evaluateJavascript("javascript:getGreetings('"+"hello world!"+"')",newValueCallback() { @Override publicvoidonReceiveValue(String value) { Log.i(LOGTAG,"onReceiveValue value="+ value); } });}从上面的用法中很明显看到,通过 evaluateJavascript 调用 JS 中的方法,可以向其中添加结果回调,来接收 JS 的 return 值。

iOS 的 UIWebview 提供了 JavaScriptScore 方法,支持 iOS 7.0 及以上系统。WKWebview 提供了 window.webkissageHandlers 方法,支持 iOS 8.0 及以上系统。UIWebview 在几年前常用,目前已不常见。以下为创建 WKWebViewConfiguration 和 创建 WKWebView 示例:

WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];WKPreferences *preferences = [WKPreferences new];preferences.javaScriptCanOpenWindowsAutomatically = YES;preferences.minimumFontSize = 40.0;configuration.preferences = preferences;- (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"share"]; [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"pickImage"];}- (void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"share"]; [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"pickImage"];}// js 调用window.webkissageHandlers.share.postMessage(xxx);

ios 调用 js

// 前端定义全局方法function getGreetings(str) { return str;}[jsContext evaluateJavaScript:@"getGreetings(111)"]

前端 window.KwaiAd,获取全局的桥 JsBridgejsBridge 只执行 当前 handler 下的 action 函数,执行完成调用 callback 函数(这里只传给客户端一个函数名),回调绑定在了 window 上。(action 名在前端和客户端都维护了一套)

注意点

promise 时做了回收,每个桥只调用一次,每个模块使用的时候也都会重新 createBridge,避免 promise 一直内存占用



【本文地址】


今日新闻


推荐新闻


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