通常在混合app中经常会使用js调用native的方法,一般是:

  1. window.nativeApp.call(XXX);

直接调用native方法,对于简单的处理倒是可以,如果需要回调呢?期待的方式是:

  1. window.nativeApp.call(XXX,function(res){
  2. //XXX处理回调
  3. });

这样处理才更符合项目的需求!

基于这样的思路,自己实现了基于Webview拓展了新功能,代码已上传到git:

https://github.com/cmlbeliever/RX-Volley

核心类为CrossWebview,Extension

下面分析下native处理回调的实现方式:

主要实现步骤:

  1. 将需js的回调函数保存起来
  2. 本地执行业务代码
  3. 调用js的回调函数

下面分别分析每个步骤

1、原先直接调用native方法,需要改成调用带有保存回调函数功能的方法,在此方法中保存回调函数,然后调用native方法。Android在Webview上是允许直接执行js的

  1. webview.loadUrl("javascript:xxxx");

在webview初始化完成后,实例化具有保存回调功能的方法,js代码如下

  1. window.#{alias}Exports={};
  2. window.#{alias}Extension={};
  3. var #{alias}Counter = 0;
  4. var #{alias}SuccessCbs = {};
  5. window.#{alias}Extension.callbackJs=function (message) {
  6. var data=message;
  7. var cb;
  8. if(data.native_id){
  9. cb = #{alias}SuccessCbs[data.native_id];
  10. };
  11. if (cb) {
  12. cb(data);
  13. };
  14. };
  15. window.#{alias}Exports.callNative = function(params,callback) {
  16. if(callback){
  17. #{alias}Counter++;
  18. #{alias}SuccessCbs[#{alias}Counter] = callback;
  19. }
  20. try{
  21. params = JSON.parse(params);
  22. }catch(e){
  23. }
  24. window.#{alias}.postMessage(#{alias}Counter,JSON.stringify({
  25. native_id: #{alias}Counter,
  26. params: params
  27. }));
  28. };

#{alias}是为了在一个webview添加多个native实例提供的占位符。后面会处理

window.#{alias}Exports.callNative 方会保存js的回调函数,并且调用native方法!

2、java类处理

接收到js的调用请求后,native处理自己的业务逻辑,首先要注册js回调:

  1. webView.addExtension("native", new MyExtension());
  2. class MyExtension extends Extension {
  3. @Override
  4. @JavascriptInterface
  5. public void postMessage(int instanceId, final String message) {
  6. //
  7. webView.post(new Runnable() {
  8. @Override
  9. public void run() {
  10. try {
  11. JSONObject paramObject = new JSONObject(message);
  12. JSONObject object = new JSONObject();
  13. object.put("native_id", paramObject.getInt("native_id"));
  14. object.put("result", "我是系统返回:" + System.currentTimeMillis());
  15. webView.callJs("native", object);
  16. } catch (Exception e) {
  17. }
  18. }
  19. });
  20. }
  21. }

3、处理回调

若干时间后,指定的业务逻辑处理后,回调js,只需要调用callJs方法即可

  1. webView.callJs("native", object);
  2. demo:
  3. public void callJs(View v) throws Exception {
  4. JSONObject object = new JSONObject();
  5. object.put("native_id", 1);
  6. object.put("result", "我是系统主动调用:" + System.currentTimeMillis());
  7. webView.callJs("native", object);
  8. }

callJs会调用步骤1保存的回调函数!

这样一个js调用native,native回调js的闭环就完整的实现了。

4、多次回调处理

由于业务需要,可能会出现js调用一次native后,native需要回调多次js方法

此插件完成回调的前提要求是js调用过native。之后再native就可以无限次调用js

具体的实现方式到git上查看,下面贴出CrossWebview代码

  1. package com.cml.framework.crosswebview;
  2. import android.annotation.TargetApi;
  3. import android.content.Context;
  4. import android.os.Build;
  5. import android.text.TextUtils;
  6. import android.util.AttributeSet;
  7. import android.util.Log;
  8. import android.webkit.WebView;
  9. import org.json.JSONObject;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. /**
  13. * Created by cmlBeliever on 2016/2/3.
  14. */
  15. public class CrossWebview extends WebView {
  16. private static final String TAG = CrossWebview.class.getSimpleName();
  17. public static final String NATIVE_ID = "native_id";
  18. private Map<String, Extension> extensions = new HashMap<String, Extension>();
  19. public CrossWebview(Context context) {
  20. super(context);
  21. }
  22. public CrossWebview(Context context, AttributeSet attrs) {
  23. super(context, attrs);
  24. }
  25. public CrossWebview(Context context, AttributeSet attrs, int defStyleAttr) {
  26. super(context, attrs, defStyleAttr);
  27. }
  28. @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  29. public CrossWebview(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
  30. super(context, attrs, defStyleAttr, defStyleRes);
  31. }
  32. public CrossWebview(Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) {
  33. super(context, attrs, defStyleAttr, privateBrowsing);
  34. }
  35. @Override
  36. public void addJavascriptInterface(Object object, String name) {
  37. throw new IllegalStateException("addJavascriptInterface not support! see addExtension !!");
  38. }
  39. /**
  40. * 添加拓展功能,多个相同的extension只会保存第一个
  41. *
  42. * @param extension
  43. */
  44. public void addExtension(String alias, Extension extension) {
  45. if (TextUtils.isEmpty(alias)) {
  46. throw new IllegalArgumentException("alias can not be null!!");
  47. }
  48. if (extensions.containsKey(alias)) {
  49. return;
  50. }
  51. this.extensions.put(alias, extension);
  52. super.addJavascriptInterface(extension, alias);
  53. String baseJs = new JsBuilder(getContext(), alias).build();
  54. loadUrl(baseJs);
  55. }
  56. /**
  57. * 调用js的方法
  58. * @param alias
  59. * @param object
  60. */
  61. public void callJs(String alias, JSONObject object) {
  62. if (object.optInt(NATIVE_ID, -1) == -1) {
  63. if (Log.isLoggable(TAG, Log.WARN)) {
  64. Log.w(TAG, "callJs() : native_id is required!!");
  65. }
  66. return;
  67. }
  68. String jsFormat = "javascript:window.%sExtension.callbackJs(%s)";
  69. loadUrl(String.format(jsFormat, alias, object.toString()));
  70. }
  71. static class JsBuilder {
  72. private String baseJs;
  73. private String alias;
  74. public JsBuilder(Context context, String alias) {
  75. baseJs = context.getString(R.string.js_format);
  76. this.alias = alias;
  77. }
  78. public String build() {
  79. baseJs = baseJs.replace("#{alias}", alias);
  80. return "javascript:" + baseJs;
  81. }
  82. }
  83. }

Js调用Android回调处理的更多相关文章

  1. JS调用Android、Ios原生控件

    在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...

  2. [转]JS调用Android里面的方法,Android调用JS里面的方法

    FROM : http://blog.csdn.net/hj563308597/article/details/45197709 Android WebView 在公司Android的开发过程中遇到一 ...

  3. PhoneGap或者Cordova框架下实现Html5中JS调用Android原生代码

    PhoneGap或者Cordova框架下实现Html5中JS调用Android原生代码 看看新闻网>看引擎>开源产品 0人收藏此文章, 发表于8小时前(2013-09-06 00:39) ...

  4. js调用android本地java代码

    js调用android本地java代码 当在Android上使用WebView控件开发一个Web应用时,可以创建一个通过Javascript调用Android端java代码的接口.也就是可以通过Jav ...

  5. WebView中JS调用Android Method 遇到的坑整理

    WebView是android中常用的一个组件,其作用是展示网页,并让网页和android app进行一些业务逻辑上的交互. 其坑无数,相信用过的都知道,一个一个来解决吧. 1.怎么互调: <! ...

  6. JS调用android逻辑方法

    1.安卓打开webview时做如下配置 并做一回调接口 这里注意的是 参数 FULIBANG   和 回调接口方法  jsCallWebView 一会在JS里会用到 ================= ...

  7. 通过js调用android原生方法

    有时候我们有这样一个需求,监听html中控件的一些事件.例如点击html中某个按钮,跳转到别的activity,复制某段文本. 首先是对webview的设置: myWebView = (WebView ...

  8. Android与JS混编(js调用android相机)

       参考android相机调用,http://blog.csdn.net/yanzi1225627/article/details/33028041/,谢谢 相机怎么调用就不做赘述了,下面是js调用 ...

  9. WebView之js调用Android类的方法传递数据

    1,具体的思路如下: 在android中写一个Activity,里面写一个webview,这个webview加载本地的一个html文件,显示这个网页,这个网页包括一个用户名和密码的输入框和两个按钮(只 ...

随机推荐

  1. C# 静态变量、静态函数、实体变量、实体函数在一个类中的执行顺序

    为了弄清这个代码,写了个测试,但是测试的结果和往上的代码有所差别,仁者见仁,智者见智了.如果我的测试用例用问题,欢迎指出. 首先,方法的是在被调用时执行,但是静态方法在所有地方都可以调用,应该在很早的 ...

  2. 解决IE升级后必须以管理员运行的问题

    很多网友可能都遇到过这样的问题,在ie升级后,无法打开,必须以管理员身份运行.今天我也遇到了这个问题.最终找到了解决办法. 1.Win + R 2.输入 regedit,定位到 HKEY_CURREN ...

  3. 调用ocx ActiveX控件详解(做一个简单的ocx控件)

    背景 最近做的项目都和插件有关,就是在页面中调用插件的方法,然后进行操作. 插件就是ocx ActiveX控件,具体的说明可以自己去了解一下,在这里就不做赘述. 具体调用方式很简单: 1.在页面中写一 ...

  4. VideoView--简单获取进度条的方法

    使用MediaController类就可以简单的把视频中的进度条加进去 实例: 现在布局哪里放一个VideoView,然后: videoView = (VideoView) findViewById( ...

  5. 在Spring Boot中配置web app

    文章目录 添加依赖 配置端口 配置Context Path 配置错误页面 在程序中停止Spring Boot 配置日志级别 注册Servlet 切换嵌套服务器 在Spring Boot中配置web a ...

  6. POJ2155/LNSYOJ113 Matrix【二维树状数组+差分】【做题报告】

    这道题是一个二维树状数组,思路十分神奇,其实还是挺水的 题目描述 给定一个N∗NN∗N的矩阵AA,其中矩阵中的元素只有0或者1,其中A[i,j]A[i,j]表示矩阵的第i行和第j列(1≤i,j≤N)( ...

  7. Forrester:开源APM发展势头强劲

    在企业的运营团队看来,系统的稳定性和可靠运行时间是至关重要的.因此,企业更乐意向能够负责的技术提供商购买开发完整的.有文档记录的,并且有售后支持的工具或软件. 一般来说,运营团队没有额外精力来应付新奇 ...

  8. Bind+DLZ+MySQL智能DNS的正向解析和反向解析实现方法

    使用文本配置文件的配置方式结合bind的最新的acl和view特性来实现智能DNS想必很多人已经很熟悉了,使用MySQL数据库来存放zone文件的方式可能也不少.对于两者都熟悉的,实现 Bind+DL ...

  9. codeforce 227E 矩阵快速幂求斐波那契+N个连续数求最大公约数+斐波那契数列的性质

    E. Anniversary time limit per test2 seconds memory limit per test256 megabytes inputstandard input o ...

  10. 图论--最短路--SPFA模板(能过题,真没错的模板)

    [ACM常用模板合集] #include<iostream> #include<queue> #include<algorithm> #include<set ...