JS和Android交互调用

Android开发过程中,我们或多或少都会用到webview,使用webview来展示一些经常变动的界面更加方便简单,也更易于维护。在使用webview来展示网页的时候,有些时候我们需要通过JS和Android原生控件进行交互,以实现自己需要的效果或功能,本文通过一个demo简单实现了JS和Android原生控件的交互。

  • 效果图

JS交互.gif

界面上方是EditView和Button,下方是一个webview控件,通过输入url,然后点击跳转按钮,webview控件会加载该url,本次为了方便学习,我已经写好了一个html文件放置在了Asset文件中,通过file:///android_asset/test.html来进行加载。然后出现四个新的按钮,点击不同的按钮,会产生不同的效果。

  • asset文件夹下面的test.html文件

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <meta name="Generator" content="EditPlus®">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>Document</title>
  <script>
    function jsAlert(){
        var r = alert("I am alert");
        alert(r);
    
    }
    function jsConFirm(){
        var r = confirm("I am conFirm");
        alert(r);
    
    }
    function jsPrompt(){
        //第一个参数是提示
        //第二个参数是默认值
        var r = prompt("请输入姓名:","小明同学");
        alert(r);
    
    }
    function jsJava(){
        //调用java的方法,顶级对象,java方法
        //可以直接访问JSTest,这是因为JSTest挂载到js的window对象下了
        JSTest.showToast("我是被JS执行的Android代码");
    }
  </script>
 </head>
 <body>

<input type="button" value="jsAlert" onclick="jsAlert()"/>
<input type="button" value="jsConFirm" onclick="jsConFirm()"/>
<input type="button" value="jsPrompt" onclick="jsPrompt()"/>
<input type="button" value="jsJava" onclick="jsJava()"/>

 </body>
</html>

代码很简单,整个界面只有四个按钮,以及四个JS写的方法jsAlert(),jsConFirm(),jsPrompt(),jsJava(),当点击按钮触发这些方法的时候,会进一步触发我们写好的java代码,具体实现请参见java代码。

  • 具体的java代码

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.Toast;

public class JSActivity extends AppCompatActivity {

    //assets下的文件的test.html所在的绝对路径
    private static final String DEFAULT_URL = "file:///android_asset/test.html";

    private EditText et_url;
    
    private WebView webView;

    private ProgressDialog progressDialog;//加载界面的菊花

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_js);
        initView();
        initWebView();
    }

    /**
     * 初始化控件
     */
    private void initView() {
        webView = (WebView) findViewById(R.id.webView);
        et_url = (EditText) findViewById(R.id.et_url);
    }

    /**
     * 初始化webview
     */
    private void initWebView() {

        //首先设置Webview支持JS代码
        webView.getSettings().setJavaScriptEnabled(true);

        //Webview自己处理超链接(Webview的监听器非常多,封装一个特殊的监听类来处理)
        webView.setWebViewClient(new WebViewClient() {

            /**
             * 当打开超链接的时候,回调的方法
             * WebView:自己本身webView
             * url:即将打开的url
             */
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                //自己处理新的url
                webView.loadUrl(url);
                //true就是自己处理
                return true;
            }

            //重写页面打开和结束的监听。添加友好,弹出菊花
            /**
             * 界面打开的回调
             */
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                if (progressDialog != null && progressDialog.isShowing()) {
                    progressDialog.dismiss();
                }
                //弹出菊花
                progressDialog = new ProgressDialog(JSActivity.this);
                progressDialog.setTitle("提示");
                progressDialog.setMessage("软软正在拼命加载……");
                progressDialog.show();

            }

            /**
             * 界面打开完毕的回调
             */
            @Override
            public void onPageFinished(WebView view, String url) {
                //隐藏菊花:不为空,正在显示。才隐藏
                if (progressDialog != null && progressDialog.isShowing()) {
                    progressDialog.dismiss();
                }

            }

        });

        //设置进度条
        //WebChromeClient与webViewClient的区别
        //webViewClient处理偏界面的操作:打开新界面,界面打开,界面打开结束
        //WebChromeClient处理偏js的操作
        webView.setWebChromeClient(new WebChromeClient() {
            /**
             * 进度改变的回调
             * WebView:就是本身
             * newProgress:即将要显示的进度
             */
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                if (progressDialog != null && progressDialog.isShowing())
                    progressDialog.setMessage("软软正在拼命加载……" + newProgress + "%");
            }
            /**
             * 重写alert、confirm和prompt的回调
             */
            /**
             * Webview加载html中有alert()执行的时候,回调
             * url:当前Webview显示的url
             * message:alert的参数值
             * JsResult:java将结果回传到js中
             */
            @Override
            public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
                AlertDialog.Builder builder = new AlertDialog.Builder(JSActivity.this);
                builder.setTitle("提示");
                builder.setMessage(message);//这个message就是alert传递过来的值
                builder.setPositiveButton("确定", new OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //处理确定按钮了,且通过jsresult传递,告诉js点击的是确定按钮
                        result.confirm();
                    }
                });
                builder.show();
                //自己处理
                return true;
            }

            @Override
            public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
                AlertDialog.Builder builder = new AlertDialog.Builder(JSActivity.this);
                builder.setTitle("提示");
                builder.setMessage(message);//这个message就是alert传递过来的值
                builder.setPositiveButton("确定", new OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //处理确定按钮了,且通过jsresult传递,告诉js点击的是确定按钮
                        result.confirm();
                    }
                });
                builder.setNegativeButton("取消", new OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //处理取消按钮,且通过jsresult传递,告诉js点击的是取消按钮
                        result.cancel();

                    }
                });
                builder.show();
                //自己处理
                return true;
            }

            /**
             * defaultValue就是prompt的第二个参数值,输入框的默认值
             * JsPromptResult:向js回传数据
             */
            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,
                                      final JsPromptResult result) {
                AlertDialog.Builder builder = new AlertDialog.Builder(JSActivity.this);
                builder.setTitle("提示");
                builder.setMessage(message);//这个message就是alert传递过来的值
                //添加一个EditText
                final EditText editText = new EditText(JSActivity.this);
                editText.setText(defaultValue);//这个就是prompt 输入框的默认值
                //添加到对话框
                builder.setView(editText);
                builder.setPositiveButton("确定", new OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //获取edittext的新输入的值
                        String newValue = editText.getText().toString().trim();
                        //处理确定按钮了,且过jsresult传递,告诉js点击的是确定按钮(参数就是输入框新输入的值,我们需要回传到js中)
                        result.confirm(newValue);
                    }
                });
                builder.setNegativeButton("取消", new OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //处理取消按钮,且过jsresult传递,告诉js点击的是取消按钮
                        result.cancel();

                    }
                });
                builder.show();
                //自己处理
                return true;
            }
        });

        //java与js回调,自定义方法
        //1.java调用js
        //2.js调用java
        //首先java暴露接口,供js调用
        /**
         * obj:暴露的要调用的对象
         * interfaceName:对象的映射名称 ,object的对象名,在js中可以直接调用
         * 在html的js中:JSTest.showToast(msg)
         * 可以直接访问JSTest,这是因为JSTest挂载到js的window对象下了
         */
        webView.addJavascriptInterface(new Object() {
            //定义要调用的方法,注意4.2及以后的则多了注释语句@JavascriptInterface
            //msg由js调用的时候传递
            @JavascriptInterface
            public void showToast(String msg) {
                Toast.makeText(getApplicationContext(),
                        msg, Toast.LENGTH_SHORT).show();
            }
        }, "JSTest");

    }

    public void onClick(View view){
        String url = et_url.getText().toString().trim();
        if(TextUtils.isEmpty(url)){
            url = DEFAULT_URL;
        }
        webView.loadUrl(url);
    }


    @Override
    public void onBackPressed() {
        if (webView.canGoBack()) {
            //返回上一个页
            webView.goBack();
            return ;
        }
        super.onBackPressed();
    }

}

  • 布局文件activity_js.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".JSoupHtmlActivity" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <EditText
            android:id="@+id/et_url"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="请输入地址" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="onClick"
            android:text="跳转" />
    </LinearLayout>

    <WebView
        android:id="@+id/webView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

需要注意的有:
一、不要忘记通过setJavaScriptEnabled(true)设置webview支持JS代码
二、在使用addJavascriptInterface方法添加挂载对象时,要注意在Android4.2之后需要给方法加上@JavascriptInterface注解。
最后附上demo下载地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容