前端与Android客户端实现相互调用的几种方案
uri解析
统一资源标识符( Uniform Resource Identifier,URI),可以使用js向android客 户端发送一个uri链接。android 通过解析uri链接从而得知js代码的目的,从而进行下一步动作。简单来说就是js代码通过uri来定位android端上已有的资源,至于这个资源它本身的行为有android端自已决定。
实现的过程- Js 调用 Android
android端
Android 端的webview通过setWebViewClient设置自定义WebViewClient,其中有一个shouldOverrideUrlLoading 函数,可以接收到页面目标路径,通过webResourceRequest.getUrl().toString() 接可以知道js调用uri,并通过解析->执行--回调。
@Override
public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest webResourceRequest) {
if (shouldOverrideUrl(webView,webResourceRequest.getUrl().toString())){
return true;
}else{
return super.shouldOverrideUrlLoading(webView,webResourceRequest);
}
}
private boolean shouldOverrideUrl(WebView view, String url){
if (url.startsWith("demo:") ) {
Log.i("UrlUtil",UrlUtil.getUrlParams(url).get("obj"));
((KalidorBaseWebView)view).analysis(UrlUtil.getUrlParams(url).get("obj"));
return true;
}
return false;
}
js
function speak(obj){
window.location.href ="demo://?obj="+encodeURIComponent(JSON.stringify(obj))
}
JavascriptInterface
JavascriptInterface是Android 提供的一种本地对象的映射,使得webview内的js代码可以通过此映射的对象调用对象中的方法,从而实现webview内的js调用android的能力。其具体映射的过程可以参考blog.csdn.net/sk719887916… ,临时找的,哈哈哈。
实现的过程- Js 调用 Android
android
Android 可以增加一个类,对可以被webview调用的方法设置 @JavascriptInterface(这个是用来增加安全性的),具体原因简单来说就是4.2之前向webview注入对象,对象的某些方法其实是不应该被调用的,但是被映射到了webview,js就可以调用并不想映射到webview的方法。现在流行的是通过映射一个单一的方法来实现类似通信的功能,定义一套调用的协议,然后定义一个通过js注册一些调用的api(内置在android客户端内),并基于这些调用api公开一个jssdk。js就可以安全的调用android的能力了。
@JavascriptInterface
public String postMessage(final String message) {
getmWebView().post(new Runnable() {
@Override
public void run() {
Log.e(this.getClass().getName(), "postMessage: " + message);
webview.analysis(message);
}
});
return "看看b";
}
js
function speak(obj){
var res = window.KalimdorWebContainerBridge.postMessage(
JSON.stringify(
{
className:"com.daojia.calldemo.AlertPopu",
method:"show",
args: {
title:"JsBridge来的哦",
message:"给你们演示一把"
}
}))
}
onJsPrompt -- 强烈不建议这么做,这么做改变这个方法本身的使用场景了
Android通过 WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调分别拦截JS对话框(即上述三个方法),得到他们的消息内容,然后解析即可。 常用的拦截是JS的输入框即prompt()方法,因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定/取消)两个值。 --- 引用自Android WebView与JS的交互方式总结 主要是懒得写了
实现过程
adnroid
Android 端的webview通过setWebChromeClient设置自定义WebChromeClient其中有一个通过onJsPrompt就可以接受到js调用的prompt事件,因为是处理用户输入的所以是可以返回参数的。
@Override
public boolean onJsPrompt(WebView webView, String s, String message, String s2, JsPromptResult jsPromptResult) {
String str = ((KalidorBaseWebView)webView).analysis(message);
jsPromptResult.confirm(str);
return true;
}
js
function speak(obj){
var res = prompt(JSON.stringify(obj))
document.getElementById('a').innerText = res
}
function alertDialog() {
return {
className:"com.daojia.calldemo.AlertPopu",
method:"show",
args: {
title:"JsBridge来的哦",
message:"给你们演示一把"
}
}
}
Socket
通过Socket(我用的是websocket,主要是socket.io没找到Android端的服务器包),android也可以和webview内的js实现相互调用。
实现方式
android
public class MyWebSocketServer extends WebSocketServer {
private KalidorBaseWebView webview;
MyWebSocketServer(InetSocketAddress host,KalidorBaseWebView Review) {
super(host);
this.webview = Review;
}
public void setWebview(KalidorBaseWebView Review) {
this.webview = Review;
}
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
Log.d("websocket", "onOpen()一个客户端连接成功:" + conn.getRemoteSocketAddress());
}
@Override
public void onMessage(WebSocket conn, String message) {
// 需要保证android 和 加载网页的设备(我这边是电脑) 在同一个网段内,连同一个wifi即可
Log.d("websocket", "onMessage()网页端来的消息->" + message);
webview.isSocket = true;
webview.post(new Runnable() {
@Override
public void run() {
Log.e(this.getClass().getName(), "postMessage: " + message);
String res = webview.analysis(message);
MyWebSocketServer.this.broadcast(res);
}
});
}
static MyWebSocketServer myWebsocketServer;
// 实现方法,在服务中或者OnCreate()方法调用此方法
public static void startMyWebsocketServer(KalidorBaseWebView Review) {
// 端口复用
if (myWebsocketServer != null) {
myWebsocketServer.setWebview(Review);
return;
}
// 9090为端口
InetSocketAddress myHost = new InetSocketAddress("127.0.0.1", 9090);
myWebsocketServer = new MyWebSocketServer(myHost, Review);
myWebsocketServer.start();
}
}
js
var ws = new WebSocket('ws://127.0.0.1:9090');
ws.onopen = function () {
console.log('ws onopen');
ws.onmessage = function (e) {
console.log('from server: ' + e.data);
this.dispatch(e)
};;
};
function speak(obj){
ws.send(JSON.stringify(obj));
}
function alertDialog() {
return {
className:"com.daojia.calldemo.AlertPopu",
method:"show",
args: {
title:"JsBridge来的哦",
message:"给你们演示一把"
}
}
}
同步&异步
在上面我们已经搞明白了一些js调用android的方式,那么如果我们希望调用之后android端能够回复js改怎么搞呢?哪些可以同步返回,哪些需要注册一个函数等待异步调用呢?
JavascriptInterface &onJsPrompt
js如果通过这些方式调用Android,Android 可以return 返回值,也就是可以实现同步调用-返回。
异步
在android中,可以通过调用loadUrl("javascript:xxxx('')")(强烈不推荐,一个是页面可能会刷新,主要是这玩意和加载url是一个方法多恐怖)。evaluateJavascript("xxxx('')"),这个方法是可以获取js的返回值的,比较推荐。
webview.evaluateJavascript("window.dispatch('" + dispatchMessage + "')", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此处为js返回的结果
Log.e("onReceiveValue", "onReceiveValue: " + value);
}
});
另外通过socket建立的通信,也可以使用socket的api实现异步返回。
MyWebSocketServer.this.broadcast(res);
题外话
node服务之间的远程调用 简单版本
github.com/runner-up-j… github.com/runner-up-j…
好好学习,一起加油,努力活到最后。