Android 与JS 互相调用示例

本文详细介绍了Android应用中如何实现与JavaScript的互相调用。包括JS调用Android原生方法的步骤,如定义JavaScriptInterface,处理主线程与子线程的问题,以及混淆规则设置。同时,也阐述了Android调用JS的方法,强调需在网页加载完成后进行。最后讨论了WebViewClient常见问题,如加载菊花的显示、HTTPS加载HTTP图片以及防止网页唤起外部浏览器。

我们做项目经常会用到Android 嵌套网页,然后就会有互相调用的情况,但是之前没有总结,懂的人懂了,换了一批开发人员就又要研究了,所以现在把相关知识点总结一下。

先上前端代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Android 与JS互相调用示例</title>
    </head>
    <body class="bg_gray">
        <input type="submit" id="collect" οnclick="collect()" value="收藏"></a>
        <input type="submit" οnclick="dialogSelectType()" value="选择"></a>
 
        <a id="url", href="http://www.baidu.com">百度</a>
        <input type="submit" οnclick="getContent(1)" value="修改内容1"></a>
        <input type="submit" οnclick="getContent(2)" value="修改内容2"></a>
        <h2 >啦啦啦内容</h2>
    </body>
    <script type="text/javascript">
         
        function collect()
        {
            window.Js_Interactive.collection(1);
        }
 
        function getContent(id)
        {
            var content = window.Js_Interactive.getContent(id);
            document.getElementsByTagName('h2')[0].innerHTML = content;
        }
        function changeUrl(url, name)
        {
            var el = document.getElementById('url');
            el.setAttribute('href', url);
            el.innerHTML = name;
        }
        function dialogSelectType()
        {
            window.Js_Interactive.dialogSelectType();
        }
         
        function changeBtnColor()
        {
            var el = document.getElementById('collect');
            el.style.background = "#22AAEE";
        }
    </script>
</html>

一、 JS 调用Android 原生
1、接口定义 
window.Js_Interactive.getContent(id);
window 是api固定的,Js_Interactive 是可以根据不同项目改变的,但是一个项目,不建议有多个名字,也就是整个项目这个定义好了也不会改变,
getContent 是方法名,不同地方调用的方法名、参数都不一致,参数数据类型也不一样,有些js传参id传的时候看起来是Int,但是有可能在移动端这边接收的是String,所以建议都传String类型


在Android 端需要定义一个JavascriptInterface 来接收来自JS的调用
 

webView.addJavascriptInterface(new JavascriptInterface(this), "Js_Interactive");

 后面的参数Js_Interactive与JS定义的Js_Interactive要一致,整个工程最好固定这个属性定定义,JavascriptInterface 类需写好前端定义好的方法名,具体代码如下


/**js通信接口*/
public class JavascriptInterface {
    private Context context;
    public JavascriptInterface(Context context) {
        this.context = context;
    }
    @android.webkit.JavascriptInterface
    public void dialogSelectType(){
        //javascript 从子线程调用
        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, "javascript调用了popwindow", Toast.LENGTH_SHORT).show();
                //接到web里面的javascript传来的命令,调用显示dialog
                shareDialog.show();
            }
        });
    }
    @android.webkit.JavascriptInterface
    public String collection(long id){
        LogUtil.e("collection("+id+")");
        Toast.makeText(context, "javascript传来的商品id:"+id, Toast.LENGTH_SHORT).show();
        return "哈哈哈";
    }
    @android.webkit.JavascriptInterface
    public String collection(String id){
        Toast.makeText(context, "javascript传来的商品String id:"+id, Toast.LENGTH_SHORT).show();
        return "返回返回";
    }
    //这是网页控制跳去一个新的Activity
    @android.webkit.JavascriptInterface
    public void comment(String id){
        Toast.makeText(context, "javascript传来的商品id:"+id, Toast.LENGTH_SHORT).show();
        Intent intent = new Intent(WebActivity.this,WebStartActivity.class);
        startActivity(intent);
    }
    @android.webkit.JavascriptInterface
    public void business_go(String bussID){
        Toast.makeText(context, "javascript传来的商家id:"+bussID, Toast.LENGTH_SHORT).show();
    }
    @android.webkit.JavascriptInterface
    public String getContent(String id){
        int type = 0;
        try{
            type = Integer.parseInt(id);
        } catch (NumberFormatException e){
            e.printStackTrace();
        }
        switch (type){
            case 1:
                return "内容11111111111111111111111111";
            case 2:
                return "内容2222222222";
            default:
                return "内容333333333333333333333333";
        }
    }
}


2、需要允许加载JS ,所以代码需要加上如下语句:

webview.getSettings().setJavaScriptEnabled(true);
 

3、每个方法上要加注解@android.webkit.JavascriptInterface

4、部分情况前端传过来的有可能是子线程的,处理UI相关时就需要转到主线程调用。

5、返回值

当JS调用Android 时希望带着返回值回去,那么我们可以定义方法成有返回值的就可以了,比如上面的public String getContent(String id)方法,但是Android调JS时是用webview,loadUrl的形式调用,所以不存在返回值的情况。

6、混淆

这些方法定义好后,打包上架时需要混淆,然后你就发现调用失效了,那么我们还需要对这些

JavascriptInterface 类进行防止混淆,但是每个有WebView的页面都要检查一遍是很麻烦的,所以我们应该定义一个父类,所有
JavascriptInterface 类全部继承至这个父类,然后混淆就好写很多了。

 

public class JavascriptInterface extends BaseJavascriptInterface {  
    //...
}

混淆时加上 

-keep public class extends com.aiitec.technicalreserve.interfaces
.BaseJavascriptInterface {* ;} 

就可以了。

二、 Android 调用 JS

Android 调用JS就更简单了,首先JS 必须事先定义好方法,如

function changeBtnColor()
{
    var el = document.getElementById('collect');
    el.style.background = "#22AAEE";
}

然后Android 调用 

webView.loadUrl("javascript:changeBtnColor()"); 


就这么简单,但是需要再网页加载完成才能调用,有的人实例化好立即调用是无效的,所以想一开始就调用的必须在WebViewClient的onPageFinished(WebView view, String url) 里调用。 

我看有的人多加一个冒号javascript::,但是结果都一样 。

 

三、 WebViewClient 常见问题

1、 加载菊花

如果想做加载监时增加选中菊花可以在 

onPageStarted(WebView view, String url, Bitmap favicon) 弹出加载菊花
onPageFinished(WebView view, String url) 取消加载菊花 

2、 https加载http图片

如果在https里面加载http的图片需要用到下面这句,否则可能加载不出来。

if (Build.VERSION.SDK_INT >= 21) {
webview.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
}

 

3、 加载部分网友时莫名唤起浏览器加载

有时候加载百度等网站时会自动唤起浏览器打开,这个是我们不希望有的,那么在WebViewClient里加上这么一句,返回true 就好了。

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器
    view.loadUrl(url);
    return true;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值