文档章节

Android WebView实现js与java交互

开源中国首席劝架师
 开源中国首席劝架师
发布于 2017/09/07 14:10
字数 994
阅读 997
收藏 10

行业解决方案、产品招募中!想赚钱就来传!>>>

刚学Android用WebView来做应用

Android Studio下载: http://www.android-studio.org/

写此文时最新稳定版是2.3.3,预览版3.0.0,3.0.0支持使用Kotlin进行开发,有点坑,毕竟还不够成熟

安卓开发文档:https://developer.android.google.cn/develop/index.html

网上比较流行的js与java交互解决方案:https://github.com/lzyzsd/JsBridge

百度、Google过好多文章,都是对addJavascriptInterfaceevaluateJavascript很粗暴的解释,很少具体实例代码,所以自己整理了一下,以下方案仅对android4.4以上可用

照着安卓官方开发文档新建一个安卓工程出来不难,就不详说了,直接上代码,看注释

MainActivity.java

package com.example.demo.mydemo;

import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends AppCompatActivity {
    WebView view;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        view = new WebView(this);
        super.onCreate(savedInstanceState);
        // 注释默认视图,稍候将我们创建的WebView渲染出来
        // setContentView(R.layout.activity_main);
        // 开启对javascript支持,WebView默认是不支持javascript的
        view.getSettings().setJavaScriptEnabled(true);
        // 允许chrome浏览器进行远程调试
        view.setWebContentsDebuggingEnabled(true);
        // 如果不重写shouldOverrideUrlLoading这个方法,默认使用外部浏览器打开网页
        view.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                if (Build.VERSION.SDK_INT >= 21) {
                    view.loadUrl(request.getUrl().toString());
                } else {
                    view.loadUrl(request.toString());
                }
                return false;
            }
        });
        // 注入可在webview用js调用java方法的对象和变量Android
        view.addJavascriptInterface(new MyJs(), "Android");
        // 加载首页
        view.loadUrl("file:///android_asset/index.html");

        // 使activity显示webview的内容
        setContentView(view);
    }

    public class MyJs {
        // 注册给js用的方法
        @JavascriptInterface
        public void showToast (final String id, final String context) {
            // 在Android Monitor的logcat可以查看这句java的输出
            Log.i("toast", context);

            // 调用js的全局方法将数据返回给js(必须用UI线程,否则app会崩溃)
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                // 返回给js的回调数据,
                // id 用于给js找到对应的局部回调函数,
                // context 应该是java获取到的数据,这里为了方便,直接将js传过来的数据返回
                String data = "{id:" + id + ", result: '" + context + "'}";

                //执行js的方法(只能执行windows域下的全局方法)
                view.evaluateJavascript("exec(" + data + ")", new ValueCallback<String>() {
                    @Override
                    public void onReceiveValue(String s) {
                        // 当exec方法执行完成,会回调这个java方法
                        // s 是exec的return值(一般很少用到)
                        Log.i("callback", s);
                    }
                });
                }
            });
        }
    }

    // 处理返回键
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode==KeyEvent.KEYCODE_BACK)
        {
            if(view.canGoBack())
            {
                view.goBack();//返回上一页面
                return true;
            }
            else
            {
                System.exit(0);//退出程序
            }
        }
        return super.onKeyDown(keyCode, event);
    }
}

在WebView里必须使用UI线程的官方原文:https://developer.android.google.cn/guide/webapps/migrating.html#Threads

If you call methods on WebView from any thread other than your app's UI thread, it can cause unexpected results.

我自己翻译:如果你使用了非UI线程的其它线程去调用WebView里的方法,将会产生不被期待的结果。

上文我说APP会崩溃是实践所得。

创建index.htmlindex.js文件,放到assets文件夹里,如果项目里没assets文件夹,可以这样创建:File > New > Folder > Assets Folder

index.html

<html>
    <head>
        <meta charset="utf-8" />
        <title>Hello Demo</title>
    </head>
    <body>
        <button id="a">A</button>
        <script src="index.js"></script>
    </body>
</html>

index.js

// 用于区别回调
var id = 0
// 回调池,存放局部回调
window.pool = []
// 给java调用的全局方法
window.exec = function (data) {
  for (var i = 0; i < pool.length; i++) {
    if (pool[i][0] == data.id) {
      pool[i][1](data.result)
      pool.splice(i, 1)
      return true
    }
  }
}
// 封闭java方法的全局空间,方便给js调用
window.orz = {
  showToast: function (msg, callback) {
    Android.showToast(++id, msg)
    pool.push([id, callback])
  }
}
document.getElementById('a').onclick = function () {
  // 经过上面的一层封装,调用原生并执行回调就很方便了
  orz.showToast('Call', function (txt) {
    // 这里用了console输出,需要在谷歌浏览器Remote devices对应的Inspect的Console查看,不能用alert,alert方法还没实现
    console.log(txt)
  })
  orz.showToast('Me', function (txt) {
    console.log(txt)
  })
  orz.showToast('Superman', function (txt) {
    console.log(txt)
  })
}

总结:js和java交互的原理主要是用addJavascriptInterface给WebView注入java方法,让js可以调用,然后用evaluateJavascript执行js方法将数据传回js,也可以用view.loadUrl("javascript:...")来代替evaluateJavascript

开源中国首席劝架师

开源中国首席劝架师

粉丝 58
博文 21
码字总数 20303
作品 4
广州
高级程序员
私信 提问
加载中
请先登录后再评论。
Netty那点事(三)Channel与Pipeline

Channel是理解和使用Netty的核心。Channel的涉及内容较多,这里我使用由浅入深的介绍方法。在这篇文章中,我们主要介绍Channel部分中Pipeline实现机制。为了避免枯燥,借用一下《盗梦空间》的...

黄亿华
2013/11/24
2W
22
用vertx实现高吞吐量的站点计数器

工具:vertx,redis,mongodb,log4j 源代码地址:https://github.com/jianglibo/visitrank 先看架构图: 如果你不熟悉vertx,请先google一下。我这里将vertx当作一个容器,上面所有的圆圈要...

jianglibo
2014/04/03
3.9K
3
浅入浅出Android(003):使用TextView类构造文本控件

基础: TextView是无法供编辑的。 当我们新建一个项目MyTextView时候,默认的布局(/res/layout/activity_main.xml)中已经有了一个TextView: <TextView 运行效果如下: 修改其文本内容...

樂天
2014/03/22
593
1
SQLServer实现split分割字符串到列

网上已有人实现sqlserver的split函数可将字符串分割成行,但是我们习惯了split返回数组或者列表,因此这里对其做一些改动,最终实现也许不尽如意,但是也能解决一些问题。 先贴上某大牛写的s...

cwalet
2014/05/21
9.6K
0
程序猿媛一:Android滑动翻页+区域点击事件

滑动翻页+区域点击事件 ViewPager+GrideView 声明:博文为原创,文章内容为,效果展示,思路阐述,及代码片段。文尾附注源码获取途径。 转载请保留原文出处“http://my.oschina.net/gluoyer...

花佟林雨月
2013/11/09
4.1K
1

没有更多内容

加载失败,请刷新页面

加载更多

揭秘神秘的MarxDB

主题:MarxDB金融级分布式数据库 大纲: 1、石老师好像是第一次来3306π,可以先重点自我介绍一下。 2、石老师可以简单介绍一下MarxDB的情况吗? 3、跟传统的关系型数据库相比,MarxDB有什么...

叶金荣
昨天
7
0
ASP.NET Core搭建多层网站架构【13-扩展之支持全球化和本地化多语言】

2020/02/03, ASP.NET Core 3.1, VS2019, ResXManager 摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站架构【13-扩展之支持全球化和本地化多语言】 使用资源管理多语言文件实现网站本地化...

osc_wip0vvls
30分钟前
9
0
浙江移动正式采用蚂蚁集团自研数据库OceanBase

近日,浙江移动正式引入蚂蚁集团的自研数据库OceanBase,首期应用于其政企网格智慧运营系统,这也是OceanBase首次落地于运营商场景。 政企网格智慧运营平台是浙江移动针对政企用户推出的服务...

支付宝技术
昨天
13
0
使用Charles代理功能将网络请求定向至本地文件

  最近在进行前端开发的时候发现Charles一个非常牛叉的功能,就是可以通过代理将网络请求定向至本地文件。有了这个功能在进行iOS开发时就可以在缺少后台接口的情况下更加真实的进行数据moc...

osc_qvtw8r10
31分钟前
7
0
多边形裁剪图片升级啦!Cocos Creator !

支持合图,支持gizmo添加节点和调整位置,支持缩放旋转。文章底部获取完整项目! 效果预览与使用 原理 回顾 在gizmo入门探索介绍了 gizmo 与多边形裁剪的配合。 在使用 mesh 实现多边形裁剪图...

白玉无冰
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部