【问题标题】:Best practice implementing JavascriptInterface using WebView in Android?在 Android 中使用 WebView 实现 JavascriptInterface 的最佳实践?
【发布时间】:2016-06-24 20:54:28
【问题描述】:

我有一个与此问题相同的错误的崩溃报告:WebView methods on same thread error

这里建议创建一个 Runnable()。

我不明白为什么这能解决问题。错误显示“同一线程上的 Webview 方法”,但答案建议在 UI 线程(主线程)上创建方法。但是 UI-Thread 不是唯一的线程吗?有人可以详细解释整个过程吗(考虑到我在构造函数的每个活动中都创建了一个新的 Webview)?

我实现 Javascript 函数/方法的代码如下所示:

public class JS_Bind {
    private static final String TAG = "JS_Bind";
    private Context context;
    private AdvancedWebView mWebView;

    public JS_Bind(Context c, AdvancedWebView mWebView) {
        context = c;
        this.mWebView = mWebView;
    }
    @JavascriptInterface
    public void openActivity(String activityName) {
        try {
            Class activityClass = Class.forName(PACKAGE_NAME + "." + activityName);
            context.startActivity(new Intent(MainActivity.this, activityClass));
        } catch (ClassNotFoundException e) {
            Toast.makeText(context, "Invalid activity name: " + activityName, Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }
    @JavascriptInterface
    public void makeToast(String toast) {
        Toast mToast = Toast.makeText(context, toast, Toast.LENGTH_SHORT);
        mToast.setGravity(Gravity.CENTER, 0, 0);
        mToast.show();
    }
    @JavascriptInterface
    public void external(String url) {
        mTracker.send(new HitBuilders.EventBuilder().setCategory("Action").setAction("External Link: " + url).build());
        Uri uri = Uri.parse(url);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);
    }
    @JavascriptInterface
    public String showToken() {
        return gcmToken;
    }
    @JavascriptInterface
    public int showUid() {
        SharedPreferences pref = getSharedPreferences("Pref", Activity.MODE_PRIVATE);
        int uid = pref.getInt("uid", 0);
        return uid;
    }
    @JavascriptInterface
    public void buyPremium() {
        bp.purchase(MainActivity.this, PRODUCT_ID);
    }
}

我是否必须将每个函数都更改为此代码 (first answer in the question I refered to):

@JavascriptInterface
    mWebView.post(new Runnable() {
        @Override
        public void makeToast() {
          // ...
        }
    });

顺便说一句,这就是我在构造函数活动onCreate方法中创建webview的方式:

mWebView = (AdvancedWebView) findViewById(R.id.webView);
mWebView.setListener(this, this);
mWebView.addJavascriptInterface(new JS_Bind(this, mWebView), "Android");
mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

if (!DetectConnection.checkInternetConnection(this)) {
    mWebView.loadUrl("file:///android_asset/offline.html");
}
else {
        mWebView.loadUrl("http://example.com/tw3/index.php?s=home");
}

【问题讨论】:

    标签: java android multithreading webview


    【解决方案1】:

    但是 UI 线程不是唯一的线程吗?

    没有。 WebView 有自己的线程池。可以有many other threads in an Android application

    我是否必须将每个函数都更改为此代码

    不一定。

    首先,我看不到您是如何从上面显示的 @JavascriptInterface 方法中得到该错误 (A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread.) 的。该错误是当您在 WebView 本身上调用方法时,您没有这样做。

    如果出现以下情况,您将需要使用runOnUiThread()(或等效技术):

    • 您的@JavascriptInterface 方法指的是WebView 本身,或者

    • 您的@JavascriptInterface 尝试执行必须在主应用程序线程上执行的其他操作(这将产生不同的错误消息,因为它不会专门与WebView 绑定)

    您的startActivity() 调用可能需要在主应用程序线程上调用——我忘记了是否可以在后台线程上调用它。与您的Toast 工作类似——虽然我认为这可以在后台线程上完成,但我不确定。自从我尝试从后台线程中做这些事情以来已经有很长时间了。


    另外,请仅在您控制 WebView 中显示的每个字节的情况下使用您的代码。将 startActivity() 暴露给任意 Web 内容具有重大的安全隐患。

    【讨论】:

    • 对不起,我忘了说我没有列出每个JavascriptInterface函数,所以我只发布了2个来演示。我不太确定我的哪些功能导致了错误。我会在 1 分钟内更新我的问题,向您展示剩下的问题。我也想过在 AsyncTask 中使用 webview,你会推荐吗?关于安全问题:我应该为每个活动创建多个硬编码方法吗?
    • @Vaia:“我也想过在 AsyncTask 中使用 webview,你会推荐吗?” - 不。 “那我应该为每一个活动创建多个硬编码方法吗?” ——这将是一个进步。或者,只是验证输入,而不是根据传入的字符串盲目地打开任何活动。
    • @Vaia:你没有在任何地方引用mWebView。所以,我看不出你怎么会从中得到错误,但我也不明白你为什么一开始就有它。
    • 我用private AdvancedWebView mWebview; 初始化了我的webview,并在我的问题末尾粘贴了我如何在构造函数中创建mWebView 的代码。抱歉,也许是因为英语不是我的母语,但你说我为什么首先拥有它是什么意思?谢谢你的时间,我很感激。
    • @Vaia: "我初始化了我的 webview..." -- 是的,但是你永远不会在任何地方引用它。删除该字段。或者,粘贴您 引用它的方法。
    猜你喜欢
    • 1970-01-01
    • 2016-08-29
    • 1970-01-01
    • 2016-05-28
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    相关资源
    最近更新 更多