WebView calling Java code in Android (inner workings of Javascript bridges)

1,242 views
Skip to first unread message

guliz...@gmail.com

unread,
Mar 18, 2016, 6:49:43 PM3/18/16
to android-webview-dev

I am trying to figure out how WebView is able to give javascript code access to Java code via addJavascriptInterface, as well as redirect prompt and alert javascript functions to the event handlers (onJsPrompt, onJsAlert). What I've understood so far is that there is a mechanism called JNI, we can make certain Java functionality invokable by the code outside JVM through the use of JNI. There is also something called NPAPI that allows the use of plugins in web applications. A combination of these two will be used to allow javascript code running in a WebView to invoke methods of the exported Java class (via addJavascriptInterface).

However, I am not able to see how prompt and alert functions are redirected. Is it something similar to what I've described above, and if so how?

Also, it looks like NPAPI is deprecated in Chromium. Does this mean that it isn't used in WebViews anymore either and if so, what does it use now?


Finally, how is the WebView API connected to the Android System WebView app, what does this app actually do and is it connected to the libwebviewchromium.so library to perform webview functionality?


Thanks very much in advance for all the help!

Paul Miller

unread,
Mar 18, 2016, 7:15:51 PM3/18/16
to guliz...@gmail.com, android-webview-dev
WebView doesn't do plugins. JNI is how C++ code communicates with Java code. App/web developers shouldn't have to worry about it. App developers would typically only care about the Java/JS interface. The WebView API is part of Android. The "Android System WebView" app contains the WebView implementation. As for how the API connects to the implementation, I drew up this ugly diagram a while ago. Maybe it will help confuse you:

                     WebViewProvider       WebView → calls → WebViewFactory           WebViewFactoryProvider

Android                      ↑            ↙                                  ↘                   ↑   

=====================   implements    calls   ===========================   creates   ====   implements   =======

Chrome       creates/        ↑       ↙                                           ↘               ↑   

AwContents ← calls ← WebViewChromium ←---------------- creates ←----------------- WebViewChromiumFactoryProvider

We may be of more help if you give more context as to what you want to do.

--
You received this message because you are subscribed to the Google Groups "android-webview-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to android-webview...@chromium.org.
To post to this group, send email to android-w...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/android-webview-dev/9d3e236b-c9fd-4d67-aa71-e7827d5ffb5e%40chromium.org.

Message has been deleted

Alice

unread,
Mar 19, 2016, 6:32:16 PM3/19/16
to android-webview-dev, guliz...@gmail.com, paulm...@google.com

Hi Paul,

Thanks very much for your response. What I'm trying to do is that whenever some javascript code loaded in the webview wants to use an exported java method (through a javascript interface) or calls prompt or alert functions (hence onJsPrompt etc gets invoked), I want to intercept this call. I am not about to understand yet where I can intercept these calls. I would be glad if you could give me ideas.

Thanks!

Mikhail Naganov

unread,
Mar 19, 2016, 11:11:59 PM3/19/16
to Alice, android-webview-dev, Paul Miller
I want to intercept this call. I am not about to understand yet where I can intercept these calls

If you mean that you are running some 3rd-party (not yours) code in your WebView, and want to intercept the calls that code makes to `window.alert` or `window.prompt` functions, you have two possibilities:

1) Define your WebChromeClient object in your Java code, and set it in WebView:


2) "Override" the standard `window.alert` and `window.print` functions with your JavaScript code. See here how you can do that:


Just be sure to run this code after you have loaded the page.

In absolutely same way you can override any method in JavaScript, including methods of injected Java objects. Although, I'm not quite sure why would you want to do that on the JavaScript side.

--
You received this message because you are subscribed to the Google Groups "android-webview-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to android-webview...@chromium.org.
To post to this group, send email to android-w...@chromium.org.

Paul Miller

unread,
Mar 21, 2016, 1:54:27 PM3/21/16
to mnag...@chromium.org, Alice, android-webview-dev
The diagram is supposed to look like this.
monospace_fonts_how_do_they_work.png

Torne (Richard Coles)

unread,
Mar 22, 2016, 6:47:34 AM3/22/16
to guliz...@gmail.com, android-webview-dev, paulm...@google.com
On Sat, 19 Mar 2016 at 21:50 <guliz...@gmail.com> wrote:
Hi Paul,

Thanks very much for your response. Would it be possible for you to redraw the diagram as it isn't aligned and I didn't understand where the arrows point to. 

What I'm trying to do is that whenever some javascript code loaded in the webview wants to use an exported java method (through a javascript interface) or calls prompt or alert functions (hence onJsPrompt etc gets invoked), I want to intercept this call. I am not about to understand yet where I can intercept these calls. I would be glad if you could give me ideas.

One thing that might help you is to know that addJavascriptInterface is a totally different mechanism to all the actual web API functions (like prompt/alert/etc) - they aren't related at all and you won't be able to find a single way to intercept both kinds of thing.

All regular web APIs are implemented by the chromium rendering engine, and some of them end up being passed up to the WebView-specific code. For things like alert/confirm we have callbacks in the WebView API which are expected to be invoked. This is implemented separately for each API, there isn't a single generic mechanism here, and so you'd have to trace the path that every call you care about takes through the chromium implementation.

addJavascriptInterface is a separate mechanism that is entirely webview-specific, and not handled by the common chromium code at all. This used to be implemented using some parts of the NPAPI plugin support, but it wasn't actually a plugin (it was just reusing some code), and this is no longer the case, it was reimplemented to remove all the dependencies on NPObject. We now use Gin instead, which is a generic interface for binding stuff across parts of chromium.
 
Thanks!

--
You received this message because you are subscribed to the Google Groups "android-webview-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to android-webview...@chromium.org.
To post to this group, send email to android-w...@chromium.org.

guliz...@gmail.com

unread,
Mar 24, 2016, 9:42:31 PM3/24/16
to android-webview-dev, guliz...@gmail.com, paulm...@google.com
One thing that might help you is to know that addJavascriptInterface is a totally different mechanism to all the actual web API functions (like prompt/alert/etc) - they aren't related at all and you won't be able to find a single way to intercept both kinds of thing.

That makes sense, thank you! 

All regular web APIs are implemented by the chromium rendering engine, and some of them end up being passed up to the WebView-specific code. For things like alert/confirm we have callbacks in the WebView API which are expected to be invoked. This is implemented separately for each API, there isn't a single generic mechanism here, and so you'd have to trace the path that every call you care about takes through the chromium implementation.

For alert and prompt, where exactly in the code should I look at if I want to intercept these calls and get access to the origin information (host + port number, as in same origin policy)?
 

addJavascriptInterface is a separate mechanism that is entirely webview-specific, and not handled by the common chromium code at all. This used to be implemented using some parts of the NPAPI plugin support, but it wasn't actually a plugin (it was just reusing some code), and this is no longer the case, it was reimplemented to remove all the dependencies on NPObject. We now use Gin instead, which is a generic interface for binding stuff across parts of chromium.

Again, the same question. I need to access the origin that makes the call. What would be a good place to intercept?
Thank you very much for your help!

guliz...@gmail.com

unread,
Mar 24, 2016, 10:33:09 PM3/24/16
to android-webview-dev, mnag...@chromium.org, guliz...@gmail.com, paulm...@google.com
Thanks very much Paul. This helps a lot. So from this, I understand that Chromium project implements WebViewProvider and WebViewFactoryProvider interfaces, which is the back end of WebView. What I don't understand is how WebView API binds to this code that implements the interfaces. I do not see WebViewChromium or WebViewChromiumFactoryProvider objects being created anywhere in the android source code.

Selim Gurun

unread,
Mar 25, 2016, 2:34:49 AM3/25/16
to guliz...@gmail.com, android-webview-dev, Mikhail Naganov, Paul Miller

On Thu, Mar 24, 2016 at 7:33 PM, <guliz...@gmail.com> wrote:
Thanks very much Paul. This helps a lot. So from this, I understand that Chromium project implements WebViewProvider and WebViewFactoryProvider interfaces, which is the back end of WebView. What I don't understand is how WebView API binds to this code that implements the interfaces. I do not see WebViewChromium or WebViewChromiumFactoryProvider objects being created anywhere in the android source code.

--
You received this message because you are subscribed to the Google Groups "android-webview-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to android-webview...@chromium.org.
To post to this group, send email to android-w...@chromium.org.

Güliz Seray Tuncay

unread,
Apr 5, 2016, 11:33:14 PM4/5/16
to android-webview-dev
What is the flow of the code (in terms of components and possibly classes) from the time some javascript code loaded into the webview calls one of the methods exposed to it by addJavascript interface, to when the actual Java code for this call is run? I'm having a hard time trying to figure this out.

Thanks!

Paul Miller

unread,
Apr 11, 2016, 2:05:14 PM4/11/16
to Güliz Seray Tuncay, Mikhail Naganov, android-webview-dev
That would be Gin, I think. And this thing: https://code.google.com/p/chromium/codesearch#chromium/src/content/browser/android/java/gin_java_bridge_dispatcher_host.h Sorry, I don't know how that works. Mikhail gave a presentation on it some time ago. Maybe he still has the slides?

--
You received this message because you are subscribed to the Google Groups "android-webview-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to android-webview...@chromium.org.
To post to this group, send email to android-w...@chromium.org.

Mikhail Naganov

unread,
Apr 11, 2016, 2:32:26 PM4/11/16
to Paul Miller, Güliz Seray Tuncay, android-webview-dev
Presentation contains some classified material, so I can't publish it, sorry!

The actual code that uses Gin for injecting JS proxy objects into V8 is on the renderer side:


The "browser" side to which Paul has pointed to is the part that interacts with the injected Java objects. It talks to the renderer side via IPC messages.

Güliz Seray Tuncay

unread,
Apr 12, 2016, 2:58:39 AM4/12/16
to mnag...@chromium.org, Paul Miller, android-webview-dev
Thanks very much Mikhail and Paul for the helpful responses. I started tracing from the addJavascriptInterface method in WebView.java in AOSP, and I reached exactly the code Paul pointed. @Mikhail, do you mean that this code ( addObject in gin_java_bridge_dispatcher_host.cc ) makes an IPC call to gin_java_bridge_dispatcher.cc to insert the object into V8 (Though I fail to see where that IPC call is made.)? If not, could you elaborate what you mean by the previous answer?

One more question: Where in the code is the @Javascript annotation tag checked for the methods? I did not see it on the AOSP side.

Thanks again! 

 
--
Guliz Seray Tuncay
Ph.D.candidate in Computer Science
University of Illinois. at Urbana-Champaign

Mikhail Naganov

unread,
Apr 12, 2016, 11:41:44 AM4/12/16
to Güliz Seray Tuncay, Paul Miller, android-webview-dev
On Mon, Apr 11, 2016 at 11:58 PM, Güliz Seray Tuncay <guliz...@gmail.com> wrote:
Thanks very much Mikhail and Paul for the helpful responses. I started tracing from the addJavascriptInterface method in WebView.java in AOSP, and I reached exactly the code Paul pointed. @Mikhail, do you mean that this code ( addObject in gin_java_bridge_dispatcher_host.cc ) makes an IPC call to gin_java_bridge_dispatcher.cc to insert the object into V8 (Though I fail to see where that IPC call is made.)? If not, could you elaborate what you mean by the previous answer?

Not exactly. GinJavaBridgeDispatcherHost::AddObject only registers the object in the internal lists. It sends IPC commands to the renderer side when a RenderFrame object gets created there, as earlier there is nobody to talk to. This is handled in GinJavaBridgeDispatcherHost::RenderFrameCreated.

 

One more question: Where in the code is the @Javascript annotation tag checked for the methods? I did not see it on the AOSP side.


It's completely in Chromium code. In Android, the @JavascriptInterface annotation is only defined. See ContentViewCore.addJavascriptInterface -- the class of the annotation is passed to the native code, and ends up in GinJavaBridgeDispatcherHost::AddObject as safe_annotation_clazz argument. Filtering of the injected object's methods by the annotation is done inside GinJavaBoundObject::EnsureMethodsAreSetUp

Güliz Seray Tuncay

unread,
Apr 23, 2016, 2:44:34 PM4/23/16
to Mikhail Naganov, Paul Miller, android-webview-dev
Thanks a lot for your answers Mikhail. I now have a better idea how the JS proxy objects are inserted. Now I'm trying to understand what happens when we execute something like JsObjectWithInterface.myMethod() in javascript. I think I need to look at the "browser" side of the code that Paul had pointed to before. Could you please walk me through it?

Güliz Seray Tuncay

unread,
Apr 23, 2016, 7:03:19 PM4/23/16
to Mikhail Naganov, Paul Miller, android-webview-dev
Also, one more question.  I had read in an article that, the java objects needed to be wrapped into V8Objects in order to insert them. However, I do not see where this is done. Could you please point me to this code?

On Tue, Apr 12, 2016 at 10:41 AM, Mikhail Naganov <mnag...@chromium.org> wrote:

Mikhail Naganov

unread,
Apr 25, 2016, 12:38:49 PM4/25/16
to Güliz Seray Tuncay, Paul Miller, android-webview-dev
When JavaScript calls a method on an injected object, this is what happens. Actually, calling a methods consists of two stages on the JavaScript side: first, a function object is retrieved from the specified property, e.g. in your example, a property named "myMethod" is retrieved from "JsObjectWithInteface"; then, the retrieved function gets called.

Retrieving of the named property value is handled by GinJavaBridgeObject::GetNamedProperty. It may query the browser side for the first time. If the name of the property corresponds to a Java method name, then GinJavaBridgeObject returns a JavaScript function object. A call to this function is handled by GinJavaFunctionInvocationHelper::Invoke. It converts the arguments as needed and passes them to the browser side. All actual IPC message sending is handled by GinJavaBridgeDispatcher -- GinJavaBridgeDispatcher::InvokeJavaMethod in this case.

On the browser side, the message eventually gets to GinJavaBridgeDispatcherHost::OnInvokeMethod, which then executes the corresponding Java method via JNI and sends the result back. One interesting case here is when the Java method returns an instance of a class which also has @JavascriptInterface annotations. In this case, the renderer side needs to return a "transient" injected object. "Transient" objects work the same way as objects injected via `addJavaScript` method, but they are not re-injected on page reloads.

As for the need to use V8Objects, you are absolutely correct. This is handled by Gin's Wrapper objects, see gin/wrappable.h. 

Güliz Seray Tuncay

unread,
Apr 26, 2016, 2:49:33 PM4/26/16
to Mikhail Naganov, Paul Miller, android-webview-dev
Thanks so much for the great explanation Mikhail! It makes a lot of sense. For my purposes, I also need to understand what path the code takes from V8 to Gin. I was looking into where GinJavaBridgeObject::GetNamedProperty is called to be able to go deeper, but I couldn't quite figure it out. 

I can see that GinJavaBridgeObject inherits from NamedPropertyInterceptor and overrides GetNamedProperty, but I don't see where GinJavaBridgeObject::GetNamedProperty or NamedPropertyInterceptor::GetNamedProperty will be invoked. The only place where this method is invoked is in MessageChannel::GetNamedProperty on a PluginObject, but it seems that PluginObject does not inherit from GinJavaBridgeObject and is only a sibling. What am I missing?

Thanks a lot!

Mikhail Naganov

unread,
Apr 26, 2016, 4:38:40 PM4/26/16
to Güliz Seray Tuncay, Paul Miller, android-webview-dev
Not sure what is your method of figuring that out. Take a look inside gin/object_template_builder.cc. Gin installs a NamedPropertyGetterCallback which is defined in V8 API. The callback is called `NamedPropertyGetter` (in object_template_builder.cc). Upon calling, the callback looks up an instance of NamedPropertyInterceptor and calls GetNamedProperty on it.

But if you want to look deeper, you need to dive into V8 internals. There things may get really complicated as V8 generates machine code and executes it.

15562...@163.com

unread,
Nov 21, 2016, 8:54:35 PM11/21/16
to android-webview-dev, guliz...@gmail.com, paulm...@google.com
I'm working on the same thing as you, have you found anything helpful? If you did, would you please tell me about it. I'd very appreciate that. Thank you!! 

在 2016年3月25日星期五 UTC+8上午9:42:31,guliz...@gmail.com写道:

15562...@163.com

unread,
Dec 12, 2016, 2:20:06 AM12/12/16
to android-webview-dev, guliz...@gmail.com, paulm...@google.com, mnag...@chromium.org
I saw that part of code too, but I didn't find out how GinJavaBridgeDispatcher add the GinJavaBridgeObject into the layer of Gin. And in the source code, I didn't see any reference upon GinJavaBridgeObject in Gin package. So how can Gin get the namedProperty that injected from Java by addJavaScriptInterface?

在 2016年4月27日星期三 UTC+8上午4:38:40,Mikhail Naganov写道:
 
Thanks again! 

 

To unsubscribe from this group and stop receiving emails from it, send an email to android-webview-dev+unsub...@chromium.org.

To post to this group, send email to android-w...@chromium.org.
--
Guliz Seray Tuncay
Ph.D.candidate in Computer Science
University of Illinois. at Urbana-Champaign



--
Guliz Seray Tuncay
Ph.D.candidate in Computer Science
University of Illinois. at Urbana-Champaign
Message has been deleted

Z Gulser

unread,
Nov 2, 2023, 5:21:02 AM11/2/23
to android-webview-dev, 15562...@163.com, guliz...@gmail.com, paulm...@google.com, mnag...@chromium.org
This is a great thread. 

I though wonder why we have to return a Javascript function object (from the renderer process I believe) to the browser process if we do JNI there back to AWV. Isn't it redundant?

Best

Reply all
Reply to author
Forward
Message has been deleted
0 new messages