WebView用法与JS交互

本文介绍Android应用中WebView与JavaScript的交互方法,包括从Java调用JS、从JS回调Java、处理JS alert等,并针对Android 4.2及以上版本的兼容性问题提供解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总结:

APK中:

1.调用JS关键代码:

//调用JS方法,并传递参数  
mWebView.loadUrl("javascript:invokedByJava('java_data')");  


2.JS回调JAVA关键代码:

2.1 网页端:

<input type="button" value="调用Java方法" οnclick="window.stub.jsMethod('来至JS的参数');" />  

2.2 APK端:

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

private class JsToJava {
    @JavascriptInterface
public void jsMethod(String paramFromJS) {
        Log.i("CDH", paramFromJS);
     }
}



 

转:http://blog.youkuaiyun.com/chenfeng0104/article/details/7023448

这篇文章讲了一些WebView的使用方法,在项目中,常常会使用到,尤其是需要与JS交互。

效果图

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

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

点击“调JS方法”按钮(这个按钮不是html元素,而是android元素),从Java端调用html中的JS方法,并传递参数到JS方法中。

完整代码

在assets目录下创建一个html文件来模拟WebView访问的内容

编辑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方法" οnclick="window.stub.jsMethod('来至JS的参数');" />
  <input type="button" value="调用alert" οnclick="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的Activity文件

public class WebViewDemo extends Activity {
    private WebView mWebView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.web_view);

        findViewById(R.id.web_view_invoke_js).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //调用JS方法,并传递参数
                mWebView.loadUrl("javascript:invokedByJava('java_data')");
            }
        });

        mWebView = (WebView)findViewById(R.id.web_view);
        mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
        mWebView.getSettings().setBuiltInZoomControls(true);
        mWebView.getSettings().setJavaScriptEnabled(true);

        /* 
          WebView默认用系统自带浏览器处理页面跳转。
                            为了让页面跳转在当前WebView中进行,重写WebViewClient。
                            但是按BACK键时,不会返回跳转前的页面,而是退出本Activity。重写onKeyDown()方法来解决此问题。
         */
        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);//使用当前WebView处理跳转
                return true;//true表示此事件在此处被处理,不需要再广播
            }
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                //有页面跳转时被回调
            }
            @Override
            public void onPageFinished(WebView view, String url) {
                //页面跳转结束后被回调
            }
            @Override
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                Toast.makeText(WebViewDemo.this, "Oh no! " + description, Toast.LENGTH_SHORT).show();
            }
        });

        /*
                            当WebView内容影响UI时调用WebChromeClient的方法
         */
        mWebView.setWebChromeClient(new WebChromeClient() {
            /**
             * 处理JavaScript Alert事件
             */
            @Override
            public boolean onJsAlert(WebView view, String url,
                    String message, final JsResult result) {
                //用Android组件替换
                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");
        
        final EditText mEditText = (EditText)findViewById(R.id.web_view_text);

        findViewById(R.id.web_view_search).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                String url = mEditText.getText().toString();
                if (url == null || "".equals(url)) {
                    Toast.makeText(WebViewDemo.this, "请输入URL", Toast.LENGTH_SHORT).show();
                } else {
                    if (!url.startsWith("http:") && !url.startsWith("file:")) {
                        url = "http://" + url;
                    }
                    mWebView.loadUrl(url);
                }
            }
        });
        //默认页面
        mWebView.loadUrl("file:///android_asset/js_interact_demo.html");
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        //处理WebView跳转返回
        if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
            mWebView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
    
    private class JsToJava {
        public void jsMethod(String paramFromJS) {
            Log.i("CDH", paramFromJS);
        }
    }
}


[Android] Web Console: Uncaught TypeError: Object [object Object] has no method 'xxx'

转:http://blog.youkuaiyun.com/arui319/article/details/18556669

我们开发的产品,有一部分功能,需要在WebView中打开web页面,然后在web页面中通过js方法回调部分native的功能。

对于web回调native的开发方式,如果不了解的话,可以参考我以前的一篇博文《Android中Webview使用自定义的javascript进行回调》http://blog.csdn.NET/arui319/article/details/7044638 

最近测试发现,在某些最新机型上(4.2及以上),JS回调好像不起做用了。打开log,提示Uncaught TypeError: Object [object Object] has no method 'xxx' 。其中xxx就是web页面中写的js方法名。

仔细研究,发现是因为Android4.2及以上版本对于js的支持方式有改变导致(又是一起新版本导致的不兼容事件,最近这种事情越来越多了)。具体的,请看下面这篇文章,写的很详细了,没有必要再写一遍了,请直接参考吧。http://blog.youkuaiyun.com/zgjxwl/article/details/9627685

记录于此,方便网友查询。



 

WebView注入Java对象注意事项

转:http://blog.youkuaiyun.com/zgjxwl/article/details/9627685

在android4.2以前,注入步骤如下:


webview.getSetting().setJavaScriptEnable(true);  
class JsObject {  
    public String toString() { return "injectedObject"; }  
 }  
 webView.addJavascriptInterface(new JsObject(), "injectedObject"); 
Android4.2及以后,注入步骤如下:

webview.getSetting().setJavaScriptEnable(true);  
class JsObject {  
    @JavascriptInterface  
    public String toString() { return "injectedObject"; }  
 }  
 webView.addJavascriptInterface(new JsObject(), "injectedObject");  
发现区别没?4.2之前向webview注入的对象所暴露的接口toString没有注释语句@JavascriptInterface,而4.2及以后的则多了注释语句@JavascriptInterface

经过查官方文档所知,因为这个接口允许JavaScript 控制宿主应用程序,这是个很强大的特性,但同时,在4.2的版本前存在重大安全隐患,因为JavaScript 可以使用反射访问注入webview的Java对象的public fields,在一个包含不信任内容的WebView中使用这个方法,会允许攻击者去篡改宿主应用程序,使用宿主应用程序的权限执行java代码。因此4.2以后,任何为JS暴露的接口,都需要加

@JavascriptInterface
注释,这样,这个Java对象的fields 将不允许被JS访问。

官方文档说明:


From the Android 4.2 documentation:

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.

注:如果将targetSdkVersion 设置为17或者更高,但却没有给暴露的js接口加@JavascriptInterface注释,则logcat会报如下输出:

E/Web Console: Uncaught TypeError: Object [object Object] has no method 'toString'


public void addJavascriptInterface (Object object, String name)
Added in API level 1

Injects the supplied Java object into this WebView. The object is injected into the JavaScript context of the main frame, using the supplied name. This allows the Java object's methods to be accessed from JavaScript. For applications targeted to API level JELLY_BEAN_MR1 and above, only public methods that are annotated with JavascriptInterface can be accessed from JavaScript. For applications targeted to API level JELLY_BEAN or below, all public methods (including the inherited ones) can be accessed, see the important security note below for implications.

Note that injected objects will not appear in JavaScript until the page is next (re)loaded. For example:

class JsObject {
    @JavascriptInterface
    public String toString() { return "injectedObject"; }
 }
 webView.addJavascriptInterface(new JsObject(), "injectedObject");
 webView.loadData("", "text/html", null);
 webView.loadUrl("javascript:alert(injectedObject.toString())");

IMPORTANT:

  • This method can be used to allow JavaScript to control the host application. This is a powerful feature, but also presents a security risk for applications targeted to API level JELLY_BEAN or below, because JavaScript could use reflection to access an injected object's public fields. Use of this method in a WebView containing untrusted content could allow an attacker to manipulate the host application in unintended ways, executing Java code with the permissions of the host application. Use extreme care when using this method in a WebView which could contain untrusted content.
  • JavaScript interacts with Java object on a private, background thread of this WebView. Care is therefore required to maintain thread safety.
  • The Java object's fields are not accessible.

Parameters
object the Java object to inject into this WebView's JavaScript context. Null values are ignored.
name the name used to expose the object in JavaScript



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值