随手记Android JS与Native交互实践

@JavascriptInterface
public void showMessage(String message) {

Toast toast = Toast.makeText(this.activity.getApplicationContext(),
message,
Toast.LENGTH_SHORT);

toast.show();
}
}

webView.addJavascriptInterface(new AppJavaScriptProxy(this),“androidAppProxy”);

// JS代码调用
if(typeof androidAppProxy !== “undefined”){
androidAppProxy.showMessage(“Message from JavaScript”);
} else {
alert(“Running outside Android app”);
}

这样就可以实现JS调用Android代码,使用者只需要关注被JS调用方法的实现,对调用的过程是不可知的。使用的时候有几个要注意的地方:

  1. 提供用于JS调用的方法必须为public类型
  2. 在API 17及以上,提供用于JS调用的方法必须要添加注解@JavascriptInterface
  3. 这个方法不是在主线程中被调用的

WebViewClient.shouldOverrideUrlLoading()是通过拦截Url的方式来实现与JS的交互。shouldOverrideUrlLoading()返回true时,代表拦截这次请求,让我们自己处理。shouldOverrideUrlLoading()返回false时,代表不拦截这次请求,让WebView去处理这次请求。

WebChromeClient.onJsAlert()、onJsConfirm()、onJsPrompt()三种方式和WebViewClient.shouldOverrideUrlLoading()类似,都是通过拦截请求的方式达到交互功能。

总结:这三种方式实际上可以归纳成两种:JavascriptInterface和拦截请求,两者之间各有好坏。

  • JavascriptInterface是系统提供的方式,在效率和可靠性上肯定是优于后者的,而且以后会一直持续维护和优化。缺点在于扩展性和管理方面不太强,在Android 4.2以下存在漏洞,需要移除掉系统提供的一些接口,并小心处理提供的接口。
  • 拦截请求的方式优点是便于管理和扩展,可以按照自身的业务进行设计,方便应对复杂的逻辑,而且可以在安全性上有所保证。缺点主要是官方对这种方式不提供支持,以后高版本有需要迁移整个逻辑的可能性。还有就是效率不高,H5快速调用多个请求时会有丢失的可能。

JS调用框架设计

为了解决前言中提到的通讯方式多样、调用混乱和安全性差等几个问题,需要重新设计JS调用框架,将整个流程从WebView中剥离出来,达到低耦合的目的。综合考虑后,决定沿用项目中之前的解决方式,通过拦截WebView请求的方式来实现。拦截性的方式在设计框架之前还需要考虑到通讯协议的问题。

协议设计

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如上图所示,通过设计通讯协议达到多端统一通讯。协议上面可以参考现有的通讯协议,或者根据项目需求和前端设计一套通用协议。这里推荐一种简单的现有的协议:统一资源标志符。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

jsbridge://method1?a=123&b=345&jsCall=jsMethod1"

该种标识允许用户对网络中(一般指万维网)的资源通过特定的协议进行交互操作,在这里不用完全使用,只使用了其中的三个字段。scheme定义为jsbridge,用于区分别的网络请求。authority用来定义JS需要访问的方法。后面的query用来传参数,如果需要客户端回调信息给前端,就可以加个参数jsCall=jsMethod1,然后客户端处理完后就可以通过WebView进行回调。

WebView.loadUrl(“javascript:jsMethod1(result=1)”)

这样就定义了一种简单的交互方式,能让JS和Native拥有基础的交互能力。如果需要传文件,可以通过将文件流转成Base64然后在通讯,当然如果文件太大,这种方式会有内存方面的风险。这里还有另外一种方式,拦截WebView的资源请求,将文件以流的形式进行通讯:

webView.setWebViewClient(new WebViewClient(){
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return new WebResourceResponse(“image/jpeg”, “UTF-8”, new FileInputStream(new File(“xxxx”);
}
}

框架设计

在设计中,主要考虑了以下几点:

  1. 安全性: 防止第三方网站获取用户私密信息和通讯被第三方截取信息。(域名白名单、数据加密)
  2. 易用性: 设计框架都需要考虑易用性,方便实用。如Android的JavascriptInterface方式,使用者只用关注被调用方法的实现。(参考Android的JavascriptInterface方式)
  3. 可移植性: 现在Android系统日新月异,每个版本都有较大改动和优化,如果出现更好的方案或者特性时,要方便迁移整个JsBridge方案。(设计中要职责分明)
  4. 扩展性: 方便业务逻辑扩展。(添加中间件)

通过分析整个通讯的流程,结合项目中的需要,大体抽象出通讯流程中的五个角色:

  1. JsBridge: 整个Js框架的管理,提供对外的接口,连接Processor和JsProvider。
  2. JsCall: 抽象一次请求,包含一次请求的内容和环境,拥有回调信息给前端的接口。
  3. IProcessor: 协议的抽象体。由于项目原因需要多套协议兼容,所以抽象出协议,负责请求的分类和解析。
  4. JsProvider: Js方法的提供者,本身是Object类型,方便现有代码迁移,而且和JavascriptInterface方式一致,也方便以后迁移。
  5. @JsMethod: Js方法的一个注解,类似@JavascriptInterface。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这样的模式和系统提供的JavascriptInterface方式基本一致,但是我们可以做的事情比JavascriptInterface方式更多,而且整个系统解耦清晰,但是这个结构实际上还缺乏较多的东西,无法达到设计的目标,整个流程中缺乏扩展性,没有拦截和二次处理机制。

可以在执行JsMethod之前添加一个拦截器,增强扩展性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

安全性方面也可以通过添加拦截器的方式来实现,将JS请求拦截在执行JsMethod之前,而每个JsMethod的安全级别可以通过扩展注解参数来标注。例如下面代码,添加permission字段来标示方法的安全级别。

@JsMethod(permission = “high”)
public void requestInfo(IJsCall jsCall) {
// do something
}

框架骨架搭建好了后,还需要一些优化性的设计:

  1. 日志系统:添加日志开关,打印关键性的日志。
  2. 线程转换:由于WebViewClient.shouldOverrideUrlLoading是在主线程里面执行,可以参考Android做法,将JS方法都放到其它线程去做,不影响页面流畅度。
  3. 异常机制:将框架中发生的异常统一管理后,抛出给框架调用者。
  4. … (结合业务设计)

###实现效果

最后,框架大体设计完毕,实现都是比较简单的。现在来看看使用的时候,首先是JS发起一个请求:

var iframe = document.createElement(‘iframe’);
iframe.setAttribute(‘src’, ‘jsbridge://method1?a=123&b=345’);
document.body.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;

客户端只需要简单的对WebView的请求做拦截。

@Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
boolean handle = super.shouldOverrideUrlLoading(webView, url);
if (!handle) {
handle = JSBridge.parse(activity, webView, url);
}
return handle;
}

创建一个解析当前协议的对象,这个是以后都可以复用的:

public class JsProcessor implements IProcessor {

public static final int TYPE_PROCESSOR = 1;

/**

  • 协议编号
  • @return
    */
    @Override
    public int getType() {
    return TYPE_PROCESSOR;
    }

/**

  • 判断请求是不是属于这个协议
  • @param url
  • @return
    */
    @Override
    public boolean isProtocol(String url) {
    return !TextUtils.isEmpty(url) && url.startsWith(“jsbridge”);
    }

/**

  • 解析协议
  • @param context
  • @param webView
  • @param url
  • @param webViewContext WebView的环境
  • @return
    */
    @Override
    public IJsCall parse(Context context, WebView webView, final String url, Object webViewContext) {
    return new IJsCall<RequestBean, ResponseBean>() {

private String mMethodName;

@Override
public void callback(ResponseBean data, WebView webView) {
JSBridge.callback(data, webView);
}

@Override
public String url() {
return null;
}

@Override
public RequestBean parseData() {
if (TextUtils.isEmpty(url)) {
return null;
}
Uri uri = Uri.parse(url);
String methodName = uri.getPath();
methodName = methodName.replace(“/”, “”);

重要知识点

下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。

高级进阶篇——高级UI,自定义View(部分展示)

UI这块知识是现今使用者最多的。当年火爆一时的Android入门培训,学会这小块知识就能随便找到不错的工作了。不过很显然现在远远不够了,拒绝无休止的CV,亲自去项目实战,读源码,研究原理吧!

  • 面试题部分合集

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
码,研究原理吧!

[外链图片转存中…(img-1I4lF5f0-1715425194449)]

  • 面试题部分合集
    [外链图片转存中…(img-x1jnThPu-1715425194450)]

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 20
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Web开发中,JSNative交互是指通过JavaScriptJS)代码和本地代码进行相互通信的过程。JS是一种脚本语言,在浏览器中执行,而Native是指底层本地代码,如Android的Java或iOS的Objective-C/Swift。 JSNative交互的目的是为了在Web应用程序中获得更强大的功能和更好的用户体验。通过JSNative交互,可以实现以下功能: 1. 调用Native功能:JS可以通过与Native进行通信,调用本地功能,例如访问设备的传感器、获取设备信息、发送本地推送等。这样,Web应用程序就可以更好地与设备硬件和本地特性进行交互。 2. 获取Native数据:JS可以向Native请求数据,例如获取本地数据库的数据、获取设备的位置信息等。通过这种方式,Web应用程序可以使用本地的数据,实现更为复杂和个性化的功能。 3. 更新Web页面:Native可以通过调用JS的代码来更新Web页面的内容,例如在Native端接收到新的数据时,可以通过JS将数据更新到Web页面上,实现实时的页面刷新。 为了实现JSNative交互,通常有以下几种方式: 1. 使用WebView提供的接口:在移动应用中,使用WebView作为嵌入式浏览器可以实现JSNative交互。通过WebView提供的接口,可以在JSNative之间进行消息传递和函数调用。 2. 使用JavaScriptBridge:JavaScriptBridge是一种将JSNative进行桥接的技术。通过在Native代码中注入JavaScriptBridge对象,并在JS代码中引用相关的Native方法和属性,可以实现JSNative的相互调用。 3. 使用消息机制:在一些特定的平台上,还可以通过消息机制实现JSNative之间的通信。例如,Android平台可以使用JavaScriptInterface来定义JS可以调用的Native方法,而iOS平台可以使用WKWebView提供的消息机制进行JSNative交互。 总结来说,JSNative交互是为了实现Web应用程序与本地功能和数据的交互,通过使用WebView接口、JavaScriptBridge或消息机制,可以实现JSNative的相互调用和通信。这样一来,Web应用程序就能获得更多的功能和更好的用户体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值