WebView JavaScript Interface only seems to work through the Android Studio's Instant-Run, but not when compiled through regular gradle
Asked Answered
A

1

6

The Setup

I have a simple fragment that hosts a WebView component. During the initialization of this fragment, I register a few JavaScript interface methods to my app:

mJavaScriptHooks = new JavaScriptHooks();
...
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(mJavaScriptHooks, "Android");

My JavaScript hooks are nothing spectacular, and all are declared in the following manner:

public class JavaScriptHooks {
    @JavascriptInterface
    public void someMethod() {
       ...
    }
    ...
}

In order to make sure that these methods are not obfuscated or optimized away into oblivion, I've added the following the my ProGuard configuration:

-keepattributes JavascriptInterface
-keepclassmembers class * {
    @android.webkit.JavascriptInterface <methods>;
}

The Problem

Everything works as expected. The web page successfully invokes the methods through the provided "Android" object, the methods are called and perform their corresponding task. However, it only works when I run the app using the APK that was generated through the Android Studio's Instant-Run feature.

It doesn't matter if the APK is installed through Android Studio or if I install it through the command-line using adb install

If I compile my APK through regular gradle (or if I disable Instant-Run), then the JavaScript interface stops working.

Debugging

First off, I've ensured that ProGuard is disabled. Even if ProGuard was somehow ✨ magically ✨ enabled, my ProGuard configuration should ensure that my JS methods are left alone.

I've also disassembled the APK to make sure that the methods being exposed through the JS Interface have not somehow become mangled (or removed). They're not. They seem to be present, as declared, in the DEX file.

When I run the APK that was generated with Instant-Run enabled, I can inspect (through Chrome) that the page loaded in the WebView and see that my "Android" object is available and all the methods I've exposed are there (and invokable):

> Android
Object
    someMethod()
    __proto__

However, when I run the APK with Instant-Run disabled (i.e. vanilla gradle), the "Android" object is available, but none of my methods are there. It's just an empty object.

> Android
Object
    __proto__

The page I'm loading in WebView lives on a publicly-visible server that I control. The same page is loaded in both APK builds, and the methods are invoked in the same manner. Only the APK built with the Instant-Run feature seems to work.

I've been digging around all day, but I couldn't find anything really helpful. Most suggestions point to a ProGuard configuration problem or to old bugs (i.e Gingerbread-era) in WebView.

Adolpho answered 25/1, 2017 at 2:10 Comment(6)
Whats your min Sdk?Rhadamanthus
How do you disable proguard? using minifyEnabled false in build.gradle?Rhadamanthus
@NageshSusarla, minimum SDK version is 19 (4.4). And yeah, minifyEnabled is false. ProGuard is disabled under buildTypes. I don't set proguardFiles for the debug type (which is what I'm targeting).Adolpho
@Adolpho Dex isn't the final thing--on the device, the dex file is recompiled into another form (.oat). What I would try, is to make sure some non-dead code actually calls into the methods of the injected object.Mousy
@MikhailNaganov I tried that too. No difference unfortunately.Adolpho
@Adolpho Is there anyway you can create a bug on b.android.com with the reproducer and link here? I can't seem to reproduce it as mentioned. (Please add Studio version to the bug)Rhadamanthus
I
0

I had the same problem before, WebView can only recognize methods if installed by android studio with the SDK whose version is same as the device. after searching the internet, I found this:

Android WebView JavaScript callbacks fail in APK without Proguard

Have you declared your JavascriptInterface methods public? I saw your example method is public, but you are not showing the real code, maybe you forget this in your real code?

Intermeddle answered 28/11, 2018 at 8:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.