Js调用Android回调处理
通常在混合app中经常会使用js调用native的方法,一般是:
window.nativeApp.call(XXX);
直接调用native方法,对于简单的处理倒是可以,如果需要回调呢?期待的方式是:
window.nativeApp.call(XXX,function(res){
//XXX处理回调
});
这样处理才更符合项目的需求!
基于这样的思路,自己实现了基于Webview拓展了新功能,代码已上传到git:
https://github.com/cmlbeliever/RX-Volley
核心类为CrossWebview,Extension
下面分析下native处理回调的实现方式:
主要实现步骤:
- 将需js的回调函数保存起来
- 本地执行业务代码
- 调用js的回调函数
下面分别分析每个步骤
1、原先直接调用native方法,需要改成调用带有保存回调函数功能的方法,在此方法中保存回调函数,然后调用native方法。Android在Webview上是允许直接执行js的
webview.loadUrl("javascript:xxxx");
在webview初始化完成后,实例化具有保存回调功能的方法,js代码如下
window.#{alias}Exports={};
window.#{alias}Extension={};
var #{alias}Counter = 0;
var #{alias}SuccessCbs = {};
window.#{alias}Extension.callbackJs=function (message) {
var data=message;
var cb;
if(data.native_id){
cb = #{alias}SuccessCbs[data.native_id];
};
if (cb) {
cb(data);
};
};
window.#{alias}Exports.callNative = function(params,callback) {
if(callback){
#{alias}Counter++;
#{alias}SuccessCbs[#{alias}Counter] = callback;
}
try{
params = JSON.parse(params);
}catch(e){
}
window.#{alias}.postMessage(#{alias}Counter,JSON.stringify({
native_id: #{alias}Counter,
params: params
}));
};
#{alias}是为了在一个webview添加多个native实例提供的占位符。后面会处理
window.#{alias}Exports.callNative 方会保存js的回调函数,并且调用native方法!
2、java类处理
接收到js的调用请求后,native处理自己的业务逻辑,首先要注册js回调:
webView.addExtension("native", new MyExtension());
class MyExtension extends Extension {
@Override
@JavascriptInterface
public void postMessage(int instanceId, final String message) {
//
webView.post(new Runnable() {
@Override
public void run() {
try {
JSONObject paramObject = new JSONObject(message);
JSONObject object = new JSONObject();
object.put("native_id", paramObject.getInt("native_id"));
object.put("result", "我是系统返回:" + System.currentTimeMillis());
webView.callJs("native", object);
} catch (Exception e) {
}
}
});
}
}
3、处理回调
若干时间后,指定的业务逻辑处理后,回调js,只需要调用callJs方法即可
webView.callJs("native", object);
demo:
public void callJs(View v) throws Exception {
JSONObject object = new JSONObject();
object.put("native_id", 1);
object.put("result", "我是系统主动调用:" + System.currentTimeMillis());
webView.callJs("native", object);
}
callJs会调用步骤1保存的回调函数!
这样一个js调用native,native回调js的闭环就完整的实现了。
4、多次回调处理
由于业务需要,可能会出现js调用一次native后,native需要回调多次js方法
此插件完成回调的前提要求是js调用过native。之后再native就可以无限次调用js
具体的实现方式到git上查看,下面贴出CrossWebview代码
package com.cml.framework.crosswebview;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.webkit.WebView;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
/**
* Created by cmlBeliever on 2016/2/3.
*/
public class CrossWebview extends WebView {
private static final String TAG = CrossWebview.class.getSimpleName();
public static final String NATIVE_ID = "native_id";
private Map<String, Extension> extensions = new HashMap<String, Extension>();
public CrossWebview(Context context) {
super(context);
}
public CrossWebview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CrossWebview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CrossWebview(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public CrossWebview(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) {
super(context, attrs, defStyleAttr, privateBrowsing);
}
@Override
public void addJavascriptInterface(Object object, String name) {
throw new IllegalStateException("addJavascriptInterface not support! see addExtension !!");
}
/**
* 添加拓展功能,多个相同的extension只会保存第一个
*
* @param extension
*/
public void addExtension(String alias, Extension extension) {
if (TextUtils.isEmpty(alias)) {
throw new IllegalArgumentException("alias can not be null!!");
}
if (extensions.containsKey(alias)) {
return;
}
this.extensions.put(alias, extension);
super.addJavascriptInterface(extension, alias);
String baseJs = new JsBuilder(getContext(), alias).build();
loadUrl(baseJs);
}
/**
* 调用js的方法
* @param alias
* @param object
*/
public void callJs(String alias, JSONObject object) {
if (object.optInt(NATIVE_ID, -1) == -1) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "callJs() : native_id is required!!");
}
return;
}
String jsFormat = "javascript:window.%sExtension.callbackJs(%s)";
loadUrl(String.format(jsFormat, alias, object.toString()));
}
static class JsBuilder {
private String baseJs;
private String alias;
public JsBuilder(Context context, String alias) {
baseJs = context.getString(R.string.js_format);
this.alias = alias;
}
public String build() {
baseJs = baseJs.replace("#{alias}", alias);
return "javascript:" + baseJs;
}
}
}
Js调用Android回调处理的更多相关文章
- JS调用Android、Ios原生控件
在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...
- [转]JS调用Android里面的方法,Android调用JS里面的方法
FROM : http://blog.csdn.net/hj563308597/article/details/45197709 Android WebView 在公司Android的开发过程中遇到一 ...
- PhoneGap或者Cordova框架下实现Html5中JS调用Android原生代码
PhoneGap或者Cordova框架下实现Html5中JS调用Android原生代码 看看新闻网>看引擎>开源产品 0人收藏此文章, 发表于8小时前(2013-09-06 00:39) ...
- js调用android本地java代码
js调用android本地java代码 当在Android上使用WebView控件开发一个Web应用时,可以创建一个通过Javascript调用Android端java代码的接口.也就是可以通过Jav ...
- WebView中JS调用Android Method 遇到的坑整理
WebView是android中常用的一个组件,其作用是展示网页,并让网页和android app进行一些业务逻辑上的交互. 其坑无数,相信用过的都知道,一个一个来解决吧. 1.怎么互调: <! ...
- JS调用android逻辑方法
1.安卓打开webview时做如下配置 并做一回调接口 这里注意的是 参数 FULIBANG 和 回调接口方法 jsCallWebView 一会在JS里会用到 ================= ...
- 通过js调用android原生方法
有时候我们有这样一个需求,监听html中控件的一些事件.例如点击html中某个按钮,跳转到别的activity,复制某段文本. 首先是对webview的设置: myWebView = (WebView ...
- Android与JS混编(js调用android相机)
参考android相机调用,http://blog.csdn.net/yanzi1225627/article/details/33028041/,谢谢 相机怎么调用就不做赘述了,下面是js调用 ...
- WebView之js调用Android类的方法传递数据
1,具体的思路如下: 在android中写一个Activity,里面写一个webview,这个webview加载本地的一个html文件,显示这个网页,这个网页包括一个用户名和密码的输入框和两个按钮(只 ...
随机推荐
- python 中自带的堆模块heapq
import heapq my_heap = [] #使用列表保存数据 #网列表中插入数据,优先级使用插入的内容来表示,就是一个比较大小的操作,越大优先级越高 heapq.heappush(my_he ...
- 数组的forEach和map和for方法的区别
一.定义 foreach(): 从头到尾遍历数组,为每个元素调用指定的函数. map(): 将调用的数组的每个元素传递给指定的函数,并返回一个数组,他包含该函数的返回值. 传递的函数是 forea ...
- dns的抓包分析
dns: 域名系统(服务)协议 dns的解析全过程: 1. 浏览器先检查自身缓存中有没有被解析过的这个域名对应的ip地址,如果有,解析结束.同时域名被缓存的时间也可通过TTL属性来设置. 2. 如果浏 ...
- Linux open() 一个函数,两个函数原型
open在手册中有两个函数原型, 如下所示: int open(const char *pathname, int flags); int open(const char *pathname, int ...
- 正则表达式(grep,awk,sed)和通配符
1. 正则表达式 1. 什么是正则表达式? 正则表达式就是为了处理大量的字符串而定义的一套规则和方法. 通过定义的这些特殊符号的辅助,系统管理员就可以快速过滤,替换或输出需要的字符串. Linux正则 ...
- 好程序员分享Web前端面试题汇总JS篇之跨域问题
为什么80%的码农都做不了架构师?>>> 好程序员分享Web前端面试题汇总JS篇之跨域问题,接着上一篇文章我们继续来探讨web前端面试必备面试题. 跨域解决方案 1. 通过jso ...
- 线程状态及各状态下与锁和CPU的关系
线程的状态 Thread.State枚举类型中定义了线程的六种状态:NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING和TERMINATED. 线程在某一时刻只能拥有 ...
- Uber是一部无所不在的数字出行物联网
"Uber化"是整合服务产业与智能车联网的知识经济,是数字时代展现个人化生活态度无可逆转的趋势,是新兴数字族群运用数字工具集体分享出行资源的平台. 搭过Uber的消费者,对其服务质 ...
- R 语言命令行参数处理
在unix.windows外部需要调用R脚本执行,然后又需要输入不同的参数,类似shell脚本的命令行参数输入,可以使用Rcript命令实现. 命令格式:Rscript [options] [-e e ...
- POJ1088 滑雪题解+HDU 1078(记忆化搜索DP)
Description Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道 ...