Android 开发进程 0.36 原生与H5交互
Posted 百密一疏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 开发进程 0.36 原生与H5交互相关的知识,希望对你有一定的参考价值。
JS调用原生方法
H5调用android方法基本有两种,第一步通用的初始化webview
WebSettings settings = webview.getSettings();
settings.setjavascriptEnabled(true); //允许在WebView中使用js
2 创建桥接类,这是第一种方法
private Context mContext;
private WebView mWebView;
public static final String javaInterface= "javaInterface";
public JavaScriptMethod(Context context, WebView webView) {
mContext = context;
mWebView = webView;
}
@JavascriptInterface
public void showToast(String json){
Toast.makeText(context, json, Toast.LENGTH_SHORT).show();
}
这种方法就是在JavaScript中直接调用桥接类定义的方法,在初始化webview的同时执行
JavaScriptMetod m = new JavaScriptMetod(this, webview);
webview.addJavascriptInterface(m, JavaScriptMetod.javaInterface);
如果现在在 tomcat的webapp下文件夹简单填写一个html文件,添加一个按钮并在script标签中添加以下JavaScript方法
function jscallandroid(){
var jsondata={"toast":"js调用了Android方法"};
window.jsInterface.showToast(JSON.stringify(jsondata));
}
运行tomcat服务,在webview中点击按钮即可执行原生方法。
第二种方法使用范围更加普遍,如果在javascript的方法中使用以下方式:
var json = {"data": "I am a toast"};
window.location.href="protocol://android?code=toast&data="+JSON.stringify(json);
webview会重加载给到的链接,再重写webview类的 shouldOverrideUrlLoading方法可以拦截返回的url,从而做出相应。url应提前规定,如开头写作上文的“protocol://android?”,后面的code和data可以区分请求的方法和传输的数据。如以下实例:
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
String pre = "protocol://android";
if (!url.contains(pre)) {
return false;
}
//执行过滤
return true;
}
});
setWebViewClient方法返回false是默认不执行过滤,继续加载。返回true则会拦截uri不直接加载。可以使用uri字符串匹配的方法过滤提取code和data
需注意的是shouldOverrideUrlLoading方法参数为view和url的方法已经弃用,在Lollipop及以上版本不会默认执行,所以需要重写同名的另一个参数为view和request的方法,在重写的方法中调用上述方法。
Android调用JS方法
这个使用较少,可以直接使用webview的loadurl方法。如Javascript中已经有以下代码:
var showMessage=function (json) {
alert(JSON.stringify(json))
}
android中(如在点击事件方法中)可以使用:调用js方法需要在主线程中。
JSONObject json=new JSONObject();
json.put("alert","loading");
webView.loadUrl("javascript:showMessage("+json.toString()+")");
简单聊聊AndroidIPC机制
前言:
首先,我们来看一下IPC是个啥意思。
IPC是英文Inter-process communication的缩写,顾名思义就是进程间通信或者说跨进程通信。
没错,是进程。所以咱们今天主要说的就是有关进程之间的事儿。
在Android中,因为开发的需要我们可能需要跨应用去操作一些业务,或者项目较大的时候我们需要开启多个进程去完成。但是,Android中为了安全考虑呢,进程之间却又是不能进行数据交互的,为了解决这个问题所以就有了所谓的IPC机制。
其次,我们来说一下今天都会接触到哪些东西呢?
IPC的有哪些方式(一笔带过)
序列化(点到为止,不细说)
Binder机制(今天的主角儿)
AIDL(专为主角设计的模板)
一句话概括,在Android中实现进程间通信的方式有不少,但是最主要的就是Binder机制,同时Android为了快速实现这种功能专门设计了一种模板,叫做AIDL(Android Interface Definition Language 翻译为:Android接口定义语言)。
IPC有哪些方式:
1、通过Intent的putExtras()方法传递一个Bundle对象(如果只是简单的在进程间来回传递一些基本数据,这是一个很便捷的办法)。
2、通过共享文件来实现数据的共享(如果对该文件没有较高的数据同步要求的话,这也不失为一种很好的办法)。
3、使用四大组件之一的ContentProvider(Android专为进程间数据共享而生的,它的底层原理就是咱们今天的主角儿Binder,但它需要借助其他的数据存储方式来使用)。
4、使用信使Messenger(通过Messenger可以在进程间传递Message对象,因为它是串行的方式处理信息的,没有并发需求的话采用这个很不错,它的底层同样是今天的主角儿Binder)
5、使用Socket(它不但可以跨进程还可以跨设备,但是内存开销比较大,也不太安全)
6、Binder机制(今天的主角儿,性能高、安全)
序列化:
序列化也叫持久化。进程之间不可以传递对象,Binder也不行。我们要想传递,只能将对象做一下持久化,以便它可以写入到流。详细的咱就不说了,这里主要提一下两种序列化的方式。
1、实现Serializable接口(使用简单,但是开销较大)
2、实现Parcelable接口(使用较为复杂,一般用在内存序列化上,但是效率高)
Binder机制:
咱们先来介绍一下进程空间,以及它的特点。
一个进程空间是分为两个部分的,分别是用户空间和内核空间。其中,用户空间之间数据是不可共享的,内核空间是可以数据共享的。
这样说可能比较抽象,我来举个例子。
我们可以把进程想象成一棵棵的大树,其中树地面以上部分我们可以理解成为用户空间,地下的或者说整个大地我们可以理解为内核空间。每棵大树都是独立的存在,但是大地却是大家所共享的。
在一个进程空间中,用户空间和内核空间之间可以通过ioctl等方法来进行数据的交互的。(copy_to_user/copy_from_user)
这样来回拷贝就需要两次。如图
而Binder
则是基于C/S架构( Client - Server),并且通过内存映射来实现IPC通信的,下面咱们具体的介绍一下。
内存映射:
Binder IPC 通信过程:
1、首先 Binder 驱动在内核空间创建一个数据接收缓存区。2、接着在内核空间开辟一块内核缓存区。
Binder通讯模型:
1、Client:客户端(发送请求的进程)
2、Server:服务端(接受请求的进程)
3、Binder驱动:类似网络通信中的路由器,负责将Client的请求转发到具体的Server中执行,并将Server返回的数据传回给Client。
4、ServiceManager:管理所有的需要提供Binder服务的Server的注册与查询,将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。
这里咱们着重说一下ServiceManager:
流程:
1、Server向ServiceManager注册。Server通过Binder驱动向ServiceManager注册,声明可以对外提供服务。ServiceManager中会保留一份映射表。
2、Client向ServiceManager请求Server的Binder引用。Client想要请求Server的数据时,需要先通过Binder驱动向ServiceManager请求Server的Binder引用(代理对象)。再向具体的Server发送请求。Client拿到这个Binder代理对象后,就可以通过Binder驱动和Server进行通信了。
3、Server返回结果。Server响应请求后,需要再次通过Binder驱动将结果返回给Client。
原理:
ServiceManager是一个单独的进程,那么Server与ServiceManager通讯是靠什么呢?当Android系统启动后,会创建一个名称为Servicemanager的进程,这个进程通过一个约定的命令BINDERSETCONTEXT_MGR向Binder驱动注册,申请成为为ServiceManager,Binder驱动会自动为ServiceManager创建一个Binder实体。并且这个Binder实体的引用在所有的Client中都为0,也就说各个Client通过这个0号引用就可以和ServiceManager进行通信。Server通过0号引用向ServiceManager进行注册,Client通过0号引用就可以获取到要通信的Server的Binder引用。
2、 Client进程向ServiceManager查询,我要调用Server进程的computer对象的add方法,可以看到这个过程经过Binder驱动,这时候Binder驱动就开始发挥他的作用了。当向ServiceManager查询完毕,是返回一个computer对象给Client进程吗?其实不然,Binder驱动将computer对象转换成了computerProxy对象,并转发给了Client进程,因此,Client进程拿到的并不是真实的computer对象,而是一个代理对象,即computerProxy对象。很容易理解这个computerProxy对象也是有add方法,(如果连add方法都没有,岂不是欺骗了Client?),但是这个add方法只是对参数进行一些包装而已。
3、当Client进程调用add方法,这个消息发送给Binder驱动,这时驱动发现,原来是computerProxy,那么Client进程应该是需要调用computer对象的add方法的,这时驱动通知Server进程,调用你的computer对象的add方法,将结果给我。然后Server进程就将计算结果发送给驱动,驱动再转发给Client进程,这时Client进程还蒙在了鼓里,他以为自己调用的是真实的computer对象的add方法,其实他只是调用了代理而已。不过Client最终还是拿到了计算结果。
AIDL:
感谢巨人的肩膀
本文也就是作者学习当中,做的一个随笔,借鉴了很多优秀的文章,算是自己IPC这块的一个笔记吧,当然啦,在这些博文里或多或少的都向我们展示代码,大家多读读代码理解的肯定会更加的深刻。(见下面的参考)
以上是关于Android 开发进程 0.36 原生与H5交互的主要内容,如果未能解决你的问题,请参考以下文章
Android与H5交互 -- 点击H5跳转到 Android原生 页面