欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android与Js基本交互

程序员文章站 2024-02-05 20:53:16
...

  一直都想写博客,但是一直因为工作、个人时间安排不合理等等各方面原因,一直没有成功(>_<)。不过很开心,今天终于可以付诸行动。分享,带给人乐趣的同时,自己也是种重新学习。
  记得去年做项目的时候,有一天快下班,突然下来一个任务,要求给项目添加一段Js的注入代码,附加一个新功能,当天就要完成。当时听到第一个反应:有点模糊。太久没用了,脑袋里只模糊记得一些用法,但具体细节已经记不清了。当时心里就在想,什么时候写一篇关于Android和Js交互的博客,这样以后要是再忘记了,可以随时翻看,也可以为正好用到的朋友提供一个参考。
  
Android和Js的交互,主要就是分两个部分,一部分:Android调用Js内部的方法;另一部分:Js调用Android端开放的接口方法。Android调用Js内部的方法,一般我们应该比较容易写出:
  Android端代码:

mWebview.loadUrl("javascript:jsMethod()");

  Js部分代码:

 function jsMethod(){
            document.getElementById("text").innerHTML = "我来自Android,调用Js内部的方法";
        }

   当然,这是最简单的直接调用,我们也可以选择在Android端传入一些参数,然后在Js端进行相应的逻辑操作。比如,我们这里Js端有一个用来计算的内部方法:

function jsMethodToCount(a, b){
            var r = a + b;
            document.getElementById("text").innerHTML = "我来自Android,调用Js计算方法,计算结果为:" + r;
        }

计算方法中,将外部传入的两个参数进行简单相加,然后在页面上显示计算结果。
  Android端相应调用:

mWebview.loadUrl("javascript:jsMethodToCount(121,8)");

   这样,Android调用Js的一个简单过程就完成了。Js调用Android,需要在Android端编写开放的接口方法,比如一个最简单的直接调用,
  Android端代码:

@JavascriptInterface
public void callAndroid(){
            Log.w(TAG, "Js调Android callAndroid");
            Toast.makeText(MainActivity.this, "Js调Android", Toast.LENGTH_SHORT).show();
        }

  Js端代码:

function callAndroidMethodNoReturn(){
            invokeTa.callAndroid();
        }

  Js调Android接口,最简单的一种调用就完成了。我们当然也可以选择在Js端传入一些参数,然后Android端接收到参数,然后进行相应逻辑。

function callAndroidMethodNoReturn(a){
             invokeTa.rideNoReturn(a);
        }

  Android端接口方法代码:

 @JavascriptInterface
        public void rideNoReturn(int n){
            Log.w(TAG, "Js调Android,接收到传入参数 n:" + n);
            //进行相应逻辑
        }

  运行一下,发现log输出,证明Js调Android接口方法成功,并且参数成功传入到Android端

05-02 18:37:19.457 13148-13182/com.example.androidandjs W/TAG MainActivity: Js调Android,接收到传入参数 n:100

  这是没有返回值的调用,如果Js端需要返回值,再进行二次的逻辑操作,那我们可以返回返回值,新建Android端接口方法:

@JavascriptInterface
        public int ride(int n){
            Log.w(TAG, "Js调Android,接收到传入参数 n:" + n);
            //进行相应逻辑
            int q = 300;
            return q*n;//返回值
        }

  Js端代码:

 function callAndroidMethodWithReturn(a){
            var result = invokeTa.ride(a);
            document.getElementById("countText").innerHTML = "计算结果:"+result;
        }

  运行程序,
  
Android与Js基本交互
  这里注意,Android端定义接口方法的时候,定义的接口方法名不能一样,不然不能识别,就算方法签名不同。比如,上面已经有个定义的接口方法ride(int n),如果我们再定义一个下面的接口方法

 @JavascriptInterface
        public int ride(int n, int b){
            Log.w(TAG, "Js调Android,接收到传入参数(ride2) n:" + n);
            return 300*n*b;
        }

  然后点击Js触发新定义的接口方法,会发现没有效果,调用失效。Js识别不了相同方法名的函数,不管方法签名是否相同。
  到这里,Android和Js基本的相互调用,大致完成了。主要总结的一点:Android调用Js内部的方法,如果存在参数,参数是由Android端传入;Js调用Android端开放的接口方法,如果存在参数,参数是由Js端传入到Android端。参数来去理理清楚,当时公司要求新添加的需求,功能数据有些复杂,这些参数的来来去去,纠结了好一会(>_<)。
  完整代码:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "TAG MainActivity";

    private Button callJsMethodNoParams, callJsMethodWithParams;
    private WebView mWebview;
    public void setupView(){
        callJsMethodNoParams = (Button)findViewById(R.id.call_jsmethod_button);
        callJsMethodWithParams = (Button)findViewById(R.id.call_jsmethod_withParams_button);
        mWebview = (WebView)findViewById(R.id.webView);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setupView();
        //设置支持Js
        mWebview.getSettings().setJavaScriptEnabled(true);
        //添加接口对象 invokeTa 可以随便定义,Android与Js交互的类似标识Id的东西
        mWebview.addJavascriptInterface(new MyJsObject(), "invokeTa");
        //加载Js
        mWebview.loadUrl("file:///android_asset/js.html");
        addListener();
    }

    private void addListener() {
        //Android调用Js 无参
        callJsMethodNoParams.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mWebview.loadUrl("javascript:jsMethod('我来自Android,调用Js')");
            }
        });
        //Android调用Js 传入参数
        callJsMethodWithParams.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mWebview.loadUrl("javascript:jsMethodToCount(121,8)");
            }
        });
    }


    private class MyJsObject {
        @JavascriptInterface
        public void callAndroid(){
            Log.w(TAG, "Js调Android callAndroid");
            Toast.makeText(MainActivity.this, "Js调Android", Toast.LENGTH_SHORT).show();
        }

        @JavascriptInterface
        public void rideNoReturn(int n){
            Log.w(TAG, "Js调Android,接收到传入参数 n:" + n);
            //进行相应逻辑
        }

        @JavascriptInterface
        public int ride(int n){
            Log.w(TAG, "Js调Android,接收到传入参数 n:" + n);
            //进行相应逻辑
            return 300*n;
        }

//        @JavascriptInterface
//        public int ride(int n, int b){
//            Log.w(TAG, "Js调Android,接收到传入参数(ride2) n:" + n);
//            return 300*n*b;
//        }
    }
}

  js.html代码:

<html>
    <head>
        <script type="text/javascript">
        <!--Js内部方法,供Android调用-->
        function jsMethod(){
            document.getElementById("text").innerHTML = "我来自Android,调用Js内部的方法";
        }

        function jsMethodToCount(a, b){
            var r = a + b;
            document.getElementById("text").innerHTML = "我来自Android,调用Js内部的计算方法,计算结果:" + r;
        }
        <!--Js调用Android中的无返回值方法 -->
        function callAndroidMethodNoReturn(){
            invokeTa.callAndroid();
        }
        function callAndroidMethodNoReturn(a){
             invokeTa.rideNoReturn(a);
        }
        <!--Js调用Android中的有返回值方法 -->
        function callAndroidMethodWithReturn(a){
            var result = invokeTa.ride(a);
            document.getElementById("countText").innerHTML = "计算结果:"+result;
        }

        </script>
    </head>
    <body>
        <textarea id="text" cols="35" rows="2"></textarea><br/>
        <!--<button onclick="callAndroidMethodNoReturn()">Js调用Android中的无返回值方法(无参)</button><br/>-->
        <button onclick="callAndroidMethodNoReturn(100)">Js调用Android中的无返回值方法(有参)</button><br/>
        <button onclick="callAndroidMethodWithReturn(100)">Js调用Android中的有返回值方法</button><br/>
        <textarea id="countText" cols="35" rows="2"></textarea><br/>
    </body>
</html>

  注意的细节:在写的案例里,因为使用的是本地的js文件,所以不需要使用到网络权限,如果是要用到网络上的js文件,记得在AndroidManifest.xml里添加网络权限:

<uses-permission android:name="android.permission.INTERNET"/>

  然后Android调用Js的方法,是直接在代码里写死调用,也可以选择动态注入调用

String js = "var newscript = document.createElement(\"script\");";
        js += "newscript.src=\"" + url + "\";";//url网络上的js url
        js += String.format("newscript.onload=function(){%s;};", xxx()); // xxx()代表js中的某个方法
        js += "document.body.appendChild(newscript);";
        mWebview.loadUrl("javascript:" + js);

  第一次写博客,有很多不足,也可能有很多表述不清晰或错误的地方,希望朋友们不吝指出。然后第一次弄,项目运行的gif效果,还不会弄,争取下一次的博客里添上。
  源码下载