混合开发的App(Hybrid App)就是在一个App中内嵌一个轻量级的浏览器,一部分原生的功能改为Html5来开发,这部分功能不仅能够在不升级App的情况下动态更新,而且可以在Android或iOS的App上同时运行,让用户的体验更好又可以节省开发的资源。
Android提供了一个很强大的WebView控件用来处理Web网页,当然不仅仅就是显示一个WebView那么简单,有时候还需要本地Java代码与HTML中的JS进行交互。所以,在平常的开发中我们总会遇到Android的原生Java代码与网页中的Js代码之间相互调用从而产生的交互问题。

一、Android原生Java与JS交互方式

Android原生Java与JS二者之间的沟通的桥梁就是WebView,通过WebView可以实现它们之间的互相调用。
1.Android原生Java代码调用JS代码
方式一:通过WebView的loadUrl()方法实现;
方式二:通过WebView的evaluateJavascript()方法实现;
2.JS代码调用Android原生Java代码
方式一:通过WebView的addJavascriptInterface()方法进行对象映射;
方式二:通过 WebViewClient 的shouldOverrideUrlLoading ()方法进行回调拦截 url;
方式三:通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt()消息;

二、Android原生Java代码调用JS代码

将需要调用的JS代码放到src/main/assets文件夹里(调用本地JS代码和调用远程JS代码均可)
本地html代码如下:

                            

1.通过WebView的loadUrl()方法实现

public class JavaCallJsActivity extends AppCompatActivity{    private WebView webView;    private Button btnCallNoMessage;    private Button btnCallMessage;    private Button btnEvaluateJs;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_java_call_js);        btnCallNoMessage = findViewById(R.id.btn_call_with_no_message);// 点击调用无参Js方法        btnCallMessage = findViewById(R.id.btn_call_with_message);// 点击调用有参Js方法        btnEvaluateJs = findViewById(R.id.btn_evaluate_js);// 点击通过evaluateJavascript调用Js方法        webView = findViewById(R.id.webview);        WebSettings webSettings = webView.getSettings();        webSettings.setJavaScriptEnabled(true);// 设置与Js交互的权限        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);// 设置允许JS弹窗        webView.loadUrl("file:///android_asset/hybrid.html");        // 由于设置了弹窗检验调用结果,所以需要支持js对话框,通过设置WebChromeClient对象处理JavaScript的对话框        webView.setWebChromeClient(new WebChromeClient() {            @Override            public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {                AlertDialog.Builder builder = new AlertDialog.Builder(JavaCallJsActivity.this);                builder.setTitle("Alert");                builder.setMessage(message);                builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        result.confirm();                    }                });                builder.setCancelable(false);                builder.create().show();                return true;            }        });        btnCallNoMessage.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                javaCallJsWithNoMessage();            }        });        btnCallMessage.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                javaCallJsWithMessage();            }        });        btnEvaluateJs.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                //evaluateJavascript();            }        });    }    private void javaCallJsWithNoMessage() {        webView.post(new Runnable() {            @Override            public void run() {                webView.loadUrl("javascript:javaCallJsWithNoMessage()");            }        });    }    private void javaCallJsWithMessage() {        webView.post(new Runnable() {            @Override            public void run() {                webView.loadUrl("javascript:javaCallJsWithMessage(" + "'Message From Java:略略略'" + ")");            }        });    }}

注意:
(1)WebViewClient类有一个onPageFinished()方法,主要在页面加载结束时调用。JS代码调用一定要在 onPageFinished() 回调之后才能调用,否则不会调用。
(2)调用JS有参方法时,String类型的参数需要使用单引号 “’” 包裹,数组类型的参数则不用,其他复杂类型的参数可以转换为 Json 字符串的形式传递。

2.通过WebView的evaluateJavascript()方法实现

private void evaluateJavascript() {        // 因为该方法在 Android 4.4 版本才可使用,所以使用时需进行版本判断        if (Build.VERSION.SDK_INT < 19) {            webView.loadUrl("javascript:javaCallJsWithNoMessage()");        } else {            webView.evaluateJavascript("javascript:javaCallJsWithNoMessage()", new ValueCallback() {                @Override                public void onReceiveValue(String value) {                    //Js返回的结果                }            });        }    }

三、JS代码调用Android原生Java代码

本地html代码如下:

                                                    

1.通过WebView的addJavascriptInterface()方法进行对象映射

public class JsCallJavaActivity extends AppCompatActivity {    private WebView webView;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_js_call_java);        webView = findViewById(R.id.webview);        WebSettings webSettings = webView.getSettings();        webSettings.setJavaScriptEnabled(true);// 设置与Js交互的权限        webView.addJavascriptInterface(new JSInterface(), "jsObj");//JSInterface类对象映射到js的jsObj对象        webView.loadUrl("file:///android_asset/hybrid.html");    }    public class JSInterface {        // 定义JS需要调用的方法        // 被JS调用的方法必须加入@JavascriptInterface注解        @JavascriptInterface        public void call(String message) {            Toast.makeText(JsCallJavaActivity.this, message, Toast.LENGTH_LONG).show();        }    }}

我们可以看到此方式的关键是定义一个与JS对象映射关系的Android类,即JSInterface类。然后,再通过addJavascriptInterface()方法将Java对象映射到JS对象,注意Java代码和JS代码中的jsObj对象名要保持一致。
注意:JS调用Java方法时,不是在主线程中运行的,而是在一个名为JavaBridge的线程中执行的。所以这里需要注意的是,当JS调用Java时,如果需要Java继续回调JS,千万别在 JavascriptInterface方法体中直接执行 loadUrl() 方法,而是进行线程切换操作。

2.通过 WebViewClient 的shouldOverrideUrlLoading ()方法进行回调拦截 url

webView.setWebViewClient(new WebViewClient() {            @Override            public boolean shouldOverrideUrlLoading(WebView view, String url) {                //假设传入的url = "boohee://goods/2018"                if (url.contains("boohee://")) {                    //如何符合约定的协议,则拦截url,开始调用Android的一些方法干事情                    Toast.makeText(JsCallJavaActivity.this, "Js Call Java自定义协议", Toast.LENGTH_LONG).show();                    //doSomething                    return true;                }                return super.shouldOverrideUrlLoading(view, url);            }        });

3.通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt()消息

本地html代码如下:

                                            

该种方式与方式二的原理类似:
如果是拦截警告框(即alert()),则触发回调onJsAlert();
如果是拦截确认框(即confirm()),则触发回调onJsConfirm();
如果是拦截确认框(即prompt()),则触发回调onJsPrompt();

webView.setWebChromeClient(new WebChromeClient() {            @Override            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {                //假设传入的url = "boohee://goods/2018"                if (message.contains("boohee://")) {                    //如何符合约定的协议,则拦截url,开始调用Android的一些方法干事情                    Toast.makeText(JsCallJavaActivity.this, "Js Call Java Prompt", Toast.LENGTH_LONG).show();                    //doSomething                    return true;                }                return super.onJsPrompt(view, url, message, defaultValue, result);            }        });

更多相关文章

  1. Android中java反射(Reflection)实战
  2. Android(安卓)Studio 解决引入java.awt.*以及javax.包问题的一种
  3. react-native启动流程(android端)
  4. Android(安卓)集成 FFmpeg (四) 轻松实现一个音视频编辑 App
  5. java后台程序员转android 《三》之 集成腾讯云 云直播 直播推流
  6. Android(安卓)复杂的列表视图新写法 MultiType
  7. android调用系统相机实现拍照功能
  8. Android中集成支付宝
  9. Android开发指南-用户界面-对话框

随机推荐

  1. android WebView登录状态session id 和co
  2. Android中工作线程与主线程同步方式
  3. Android常用UI组件 - TextView
  4. Android中JNI 的一些常用说明 JNI_OnLoad
  5. Android(java)学习笔记125:Clock app编写报
  6. android xml 分析1--- AndroidManifest.x
  7. Android 关闭线程(转)
  8. android Supporting multiple screen翻译
  9. android中调用系统功能 来显示本地相册图
  10. android小功能实现之发送短信