Android开发,WebView下Java和JavaScript相互调用(1)

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

本文参考了两篇文章,修改了部分代码,添加很多注释,帮助新手理解

文章来源1
文章来源2

效果图

这里写图片描述

点击“调用alert”按钮,在Android中捕获JS alert,并用Android组件(AlertDialog)替换

这里写图片描述

点击“调用java方法”按钮,在JS中调用并传递参数到Java中的方法

这里写图片描述

代码部分

js_interact_demo.html

<html>  
<head>  
  <title>JS交互</title>  
  <meta http-equiv="content-type" content="text/html; charset=utf-8"/>  
  <script type="text/javascript">  
    function invokedByJava(param) {  
        document.getElementById("content").innerHTML = "Java has invoked JS function and returnd the data:"+param;  
    }  
  </script>  
</head>  
<body>  
  <p id="content"></p>  
  <p>  
  <input type="button" value="调用Java方法" onclick="window.stub.jsMethod('来至JS的参数');" />  
  <input type="button" value="调用alert" onclick="alert('hello')" />  
  </p>  
</body>  
</html>

res/layout目录下:
web_view.xml

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout  
  xmlns:android="http://schemas.android.com/apk/res/android"  
  android:orientation="vertical"  
  android:layout_width="match_parent"  
  android:layout_height="match_parent">  
    <Button android:id="@+id/web_view_invoke_js"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="调JS方法"/>  
    <LinearLayout android:layout_width="fill_parent"  
        android:layout_height="wrap_content">  
        <EditText android:id="@+id/web_view_text"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:layout_weight="1"/>  
        <Button android:id="@+id/web_view_search"  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:text="浏览"/>  
    </LinearLayout>  
    <WebView android:id="@+id/web_view"  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent" />  
</LinearLayout>  

WebViewDemo.java

package com.example.webviewdemo;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.Toast;
import android.graphics.Bitmap;
import android.webkit.JsResult;


@SuppressLint("JavascriptInterface")
public class WebViewDemo extends Activity {
    private WebView mWebView;//创建私有WebView对象

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);//照抄就行了
        setContentView(R.layout.web_view);//载入web_view布局文件

        findViewById(R.id.web_view_invoke_js).setOnClickListener(new OnClickListener() {//创建点击监听器(调JS方法)
            @Override
            public void onClick(View v) {//重构点击方法
                //调用JS方法,并传递参数
                mWebView.loadUrl("javascript:invokedByJava('我来自Java')");//直接访问js中的invokeByJava方法
            }
        });

        mWebView = (WebView)findViewById(R.id.web_view);//找到web_view
        mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);//设置滚动条
        mWebView.getSettings().setBuiltInZoomControls(true);//允许滚动条
        mWebView.getSettings().setJavaScriptEnabled(true);//允许webview的js有效

        /* 
          WebView默认用系统自带浏览器处理页面跳转。
                            为了让页面跳转在当前WebView中进行,重写WebViewClient。
                            但是按BACK键时,不会返回跳转前的页面,而是退出本Activity。重写onKeyDown()方法来解决此问题。
         */
        mWebView.setWebViewClient(new WebViewClient() {
            //setWebViewClient方法的作用是
            //Sets the WebViewClient that will receive various notifications and requests. 
            //This will replace the current handler.
            //重写WebViewClient,使得webview中页面的跳转是在内部进行,而不是跳转到系统浏览器
            //WebViewClient主要帮助WebView处理各种通知、请求事件的
            //WebChromeClient主要辅助WebView处理Javascript的对话框、网站图标、网站title、加载进度等
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);//使用当前WebView处理跳转
                return true;//true表示此事件在此处被处理,不需要再广播
            }

            /*onPageStarted作用:
            Notify the host application that a page has started loading.
            通知宿主应用程序的页已开始加载。
            This method is called once for each main frame load 
            为每个主frame调用一次该方法
            so a page with iframes or framesets will call onPageStarted one time for the main frame.
            因此有iframes或者framsets的页面将会为主frame调用一次onPageStarted方法
            This also means that onPageStarted will not be called when the contents of an embedded frame changes,
            这也意味着,当内部frame的内容改变时,onPageStarted将不会被调用。
            i.e. clicking a link whose target is an iframe.
            比如,单击是iframe的链接*/
            /*参数:
            view:The WebView that is initiating the callback.
            url:The url to be loaded.
            favicon(图标):The favicon for this page if it already exists in the database.*/
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                //有页面跳转时被回调
            }
            @Override
            public void onPageFinished(WebView view, String url) {
                //页面跳转结束后被回调
            }

            /*Report an error to the host application. These errors are unrecoverable 
             (i.e. the main resource is unavailable). 
            The errorCode parameter corresponds to one of the ERROR_* constants.*/            
            @Override
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                Toast.makeText(WebViewDemo.this, "Oh no! " + description, Toast.LENGTH_SHORT).show();
                //当出现错误时,通知宿主程序,Toast显示的内容
                //show()作用:Show the view for the specified duration.
            }
        });

        /*
                            当WebView内容影响UI时调用WebChromeClient的方法
         */
        mWebView.setWebChromeClient(new WebChromeClient() {
            /**
             * 处理JavaScript Alert事件
             */
            @Override
            public boolean onJsAlert(WebView view, String url,String message, final JsResult result) {
                //用Android组件替换,构建一个Builder来显示网页中的alert对话框
                new AlertDialog.Builder(WebViewDemo.this)
                    .setTitle("JS提示")
                    .setMessage(message)
                    .setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            result.confirm();
                        }
                    })
                    .setCancelable(false)
                    .create().show();
                return true;
            }
        });

        /*
                          绑定Java对象到WebView,这样可以让JS与Java通信(JS访问Java方法)
                          第一个参数是自定义类对象,映射成JS对象
                          第二个参数是第一个参数的JS别名
                          调用示例:
            mWebView.loadUrl("javascript:window.stub.jsMethod('param')");
         */
        mWebView.addJavascriptInterface(new JsToJava(), "stub");//js访问java的关键方法

        final EditText mEditText = (EditText)findViewById(R.id.web_view_text);//找到edittext

        findViewById(R.id.web_view_search).setOnClickListener(new OnClickListener() {//为button设置点击监听器
            @Override
            public void onClick(View view) {//点击事件触发的方法
                String url = mEditText.getText().toString();//取文本框输入的内容,并转换为字符串
                if (url == null || "".equals(url)) {//判断,如果文本框中的内容为空值,或者url的网址为空?
                    Toast.makeText(WebViewDemo.this, "请输入URL", Toast.LENGTH_SHORT).show();//给出toast提示
                } else {
                    if (!url.startsWith("http:") && !url.startsWith("file:")) {//如果内容以http:和file开头
                        url = "http://" + url;//为url赋值
                    }
                    mWebView.loadUrl(url);//传入赋值后的url并加载
                }
            }
        });
        //默认页面,本地html
        mWebView.loadUrl("file:///android_asset/js_interact_demo.html");
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {//重写back退回方法
        //处理WebView跳转返回
        if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {//如果
            mWebView.goBack();//webview返回,而不是退出当前activity
            return true;//返回真
        }
        return super.onKeyDown(keyCode, event);//
    }

    private class JsToJava {

        @JavascriptInterface
        //添加@JavascriptInterface注释
        //解决Uncaught TypeError: Object [object Object] has no method  安全限制问题
        public void jsMethod(String paramFromJS) {
            Log.i("CDH", "paramFromJS");
            Toast.makeText(WebViewDemo.this, "Oh Yeah!终于调用了java,感动 ", Toast.LENGTH_SHORT).show();
        }
    }
}

疑问解答

Alert无法弹出
你应该是没有设置WebChromeClient,按照以下代码设置

myWebView.setWebChromeClient(new WebChromeClient() {});

Uncaught ReferenceError: functionName is not defined
问题出现原因,网页的js代码没有加载完成,就调用了js方法。解决方法是在网页加载完成之后调用js方法

myWebView.setWebViewClient(new WebViewClient() {

@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//在这里执行你想调用的js函数
}

});

Uncaught TypeError: Object [object Object] has no method
安全限制问题
如果只在4.2版本以上的机器出问题,那么就是系统处于安全限制的问题了。Android文档这样说的

Caution: If you’ve set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface annotation to any method that you want available your web page code (the method must also be public). If you do not provide the annotation, then the method will not accessible by your web page when running on Android 4.2 or higher.

中文大意为

警告:如果你的程序目标平台是17或者是更高,你必须要在暴露给网页可调用的方法(这个方法必须是公开的)加上@JavascriptInterface注释。如果你不这样做的话,在4.2以以后的平台上,网页无法访问到你的方法。

两种解决方法
将targetSdkVersion设置成17或更高,引入@JavascriptInterface注释
自己创建一个注释接口名字为@JavascriptInterface,然后将其引入。注意这个接口不能混淆。
注,创建@JavascriptInterface代码

public @interface JavascriptInterface {
}

代码混淆问题
如果在没有混淆的版本运行正常,在混淆后的版本的代码运行错误,并提示Uncaught TypeError: Object [object Object] has no method,那就是你没有做混淆例外处理。 在混淆文件加入类似这样的代码

-keep class com.example.javajsinteractiondemo$JsInteration {
*;
}
All WebView methods must be called on the same thread
过滤日志曾发现过这个问题。

E/StrictMode( 1546): java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread. (Expected Looper Looper (main, tid 1) {528712d4} called on Looper (JavaBridge, tid 121) {52b6678c}, FYI main Looper is Looper (main, tid 1) {528712d4})
E/StrictMode( 1546): at android.webkit.WebView.checkThread(WebView.java:2063)
E/StrictMode( 1546): at android.webkit.WebView.loadUrl(WebView.java:794)
E/StrictMode( 1546): at com.xxx.xxxx.xxxx.xxxx.xxxxxxx$JavaScriptInterface.onCanGoBackResult(xxxx.java:96)
E/StrictMode( 1546): at com.android.org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method)
E/StrictMode( 1546): at com.android.org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:27)
E/StrictMode( 1546): at android.os.Handler.dispatchMessage(Handler.java:102)
E/StrictMode( 1546): at android.os.Looper.loop(Looper.java:136)
E/StrictMode( 1546): at android.os.HandlerThread.run(HandlerThread.java:61)
在js调用后的Java回调线程并不是主线程。如打印日志可验证

ThreadInfo=Thread[WebViewCoreThread,5,main]
解决上述的异常,将webview操作放在主线程中即可。

webView.post(new Runnable() {
@Override
public void run() {
webView.loadUrl(YOUR_URL).
}
});

AndroidWebview使用Java代码JS相互调用 本文主要记录一些零碎的东西 最近由于项目的需要,需要使用Java代码JS相互调用,特此记录一点入门的东西,仅仅是入门而已 github: https://github.com/CL-window/java_webview_js.git 话不多说,肯定是分为两块的 1.java 调用 js: /** * method here will not load htm 阅读详情

相关推荐

Android基于WebViewJavaJS相互调用实现步骤,附带精简可行的DEMO

Android基于WebViewJavaJS相互调用实现步骤,附带精简可行的DEMO

1805

WebKitWebKit For Android

如需转载,请注明出处!WebSite: http://www.jjos.org/作者: 姜江 linuxemacs@gmail.comQQ: 457283这是一篇自己写于一年前的工作文档,分享出来。原文:http://www.jjos.org/android/2010/05/10/312_webkit-webkit-for-android.html一、WebKit简介W

★果冻★的专栏 4390

Android:javajavascript相互调用

一:WebView的简单了解 1.最基本也是最重要的是在AndroidManifest.xml 中必须添加访问网络权限  android:name="android.permission.INTERNET" /> 2.如果访问的页面中有 Javascript,则 WebView 必须设置支持 Javascript,否则下面都是白扯 WebView.getSettings().setJa

moshuome的专栏 3769

android 4.0.1 webkit Event 事件处理过程分析

键值经由android的GUI事件机制传给了webview.java webview.java的onKeyDown()中会对感兴趣的键值作处理,这些键值可能不会再被传给webkitwebview.java的onKeyDown中通过调用mWebViewCore.sendMessage()将需要webkit处理的键值通过webviewcore.java传给webkit. webviewcor

jaylinzhou的专栏 2229

WebKit 分析–for android【new】

JavaWebView, WebView(UI线程)WebViewCore(WebCore线程)发消息,再由WebViewCore正调BrowserFrame,回调CallbackProxy 网上有许多webkit的分析文章,其中针对android porting的一篇文章WebKitWebKit For Android,写的非常好,分析得非常深入。不过这篇文章针

tuhuolong的专栏 2079

java 调用webkit_Android Webkit内核应用层函数调用方法

Android Webkit内核应用层函数调用方法是本文要介绍的内容,主要是来了解并学习Android Webkit的应用,具体内容的实现来看本文详解。Android Webkit内核JNI层与Java层 函数互相调用方法Java调用JNI层函数:例子:Java层: BrowserFrame::loadurl( )- 调用JNI别名: Nativeloadurl() ;JNI 层:WebFram...

weixin_32892145的博客 473

android webkit js脚本注入(js内部对象由java层构建)

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33674976的博客 228

Androidwebview里jsjava相互调用--含代码demo解析

Toast.makeText(getBaseContext(), “js调用了本地java方法”, Toast.LENGTH_LONG).show();原因是在4.4.2中对JavascriptInterface安全性的要求更高更严格,需要标识出这个方法是能被js调用的方法,以增加安全性。

2401_87555412的博客 849

AndroidWebView使用详解及Java与js相互调用

经常用到WebView,还没有系统的总结过它的用法,下面就系统的总结下,不足的地方希望大家多多指教 一、基本用法 1、加载在线URL void loadUrl(String url) 这个函数主要加载url所对应的网页地址,或者用于调用网页中的指定的JS方法(调用js方法的用法,后面会讲),但有一点必须注意的是:loadUrl()必须在主线程中执行,否则就会报错。 注意:加载在线网页...

yushuangping的博客 5586

AndroidWebView中js与java代码相互调用

近期一直在做nwjs的东西,所以整理android的时间比较少;今天将webview相关的知识点整理上来。 现在越来越多的的项目中会采用webview的形式的展示自己的页面,通过这种形式的最大优点是展示的内容的可控性非常强,服务器可以通过更新服务端html文件来展示最新的内容。有些复杂html页面不单单是展示内容,可能还会有一些按钮,点击按钮后会跳转到android的本地页面,这个时候就需要通过

njweiyukun的博客 1267

Android WebView与js相互调用以及传值

Android WebView与js相互调用以及传值 一. JS通过WebView调用 Android 代码: mWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = mWebView.getSettings(); // 设置与Js交互的权限 webSettings.setJavaScriptEnable...

yue_233的博客 707

Android WebView JAVA 与 JS 相互调用

WebView 代码 package webview.test; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener;

699

WebViewJavascript交互(相互调用参数、传值)

现在很多App里都内置了Web网页(Hyprid App),比如说很多电商平台,淘宝、京东、聚划算等等,如下图京东首页上述功能是由AndroidWebView实现的,其中涉及到Android客户端与Web网页交互的实现 今天我将全面介绍Android通过WebView与JS交互的全面方式目录1. 交互方式总结Android与JS通过WebView互相调用方法,实际上是:Android调用JS的代码 JS去调用Android的代码二者沟通的桥梁是WebView对于Android调用JS代码的方法有2种:通

qq_32534441的博客 8493

android调用js函数方法,AndroidJavaScript相互调用的方法

本文实例讲述了AndroidJavaScript相互调用的方法。分享给大家供大家参考,具体如下:Html页面Java代码结合的方式一般用在界面经常被更改 的情况下,可以讲html放在网络中,软件一打开就会访问网络获取到最新的界面。缺点是会受到网络信号的影响,从而导致访问速度慢。1.用WebView来显示HTML代码2.允许WebView执行JavaScriptwebView.getSettin...

weixin_42523670的博客 4391

AndroidWebView使用html,且实现androidJS的互相调用

本文原创,转载注明出处JUSTYiSheng1、创建html文件       创建文件很简单,用基本的文本编辑器保存成.html格式即可        web.html文件如下&lt;html&gt; &lt;head&gt; &lt;meta charset="utf-8"&gt; &lt;script type="text/javascript"&gt; function javaToJS(...

JUSTYiSheng的博客 8441

AndroidWebViewJavascript交互(相互调用参数、传值)

AndroidWebViewJavascript交互(相互调用参数、传值)

books1958的专栏 3万+

javaJS代码相互调用

挺帅的移动开发专栏 http://blog.csdn.net/wangtingshuai/article/details/8631835         在android开发过程中,有很多时候需要用到本地java代码javascript进行交互。android对交互进行了很好的封装,在开发中我们可以很简单的用java代码调用webview中的js,也可以用webview中的js

bingkingboy的博客 9369

AndroidWebViewJavascript 交互(相互调用参数、传值)

Android中可以使用WebView加载网页,同时Android端的Java代码可以与网页上的Javascript代码之间相互调用。 效果图: (一)Android部分: 布局代码: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schem...

weixin_42814000的博客 1925
上一篇: WebViewClient与WebChromeClient的区别
下一篇: Android开发,WebView下Java和JavaScript互相调用(2)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值