"Chrome Apps" webview.executeScript access guest global varibles

4.5k views Asked by At

I can access a Chrome App Webview HTML with:

webview.executeScript(
    {code: 'document.documentElement.innerHTML'},
    function(results) {
      // results[0] would have the webview's innerHTML.
    });

But I would like to get the value of global variables in the Guest like so:

webview.executeScript(
   {code: 'window.globalVar'},
   function(results) {
   // results[0] should have the webview's value of "globalVar".
   });

How can I do this?

2

There are 2 answers

5
Xan On

An answer to summarize the steps required.

1) You inject a content script with webview.executeScript() into the embedded page.

2) Since the page's real window is isolated, you need a page-level script to access it. You inject it with a <script> tag as discussed here.

3) The page-level script can access the window object, but cannot talk to the app script. However, it can fire a custom DOM event, that the content script can catch. Discussed here.

4) Finally, from the content script you need to send a message to your app script. The content script calls chrome.runtime.sendMessage, while the app script listens with chrome.runtime.onMessage. chrome.runtime.sendMessage does not seem to be available to webview content scripts injected with webview.executeScript(). A workaround is to use postMessage as described here.

It's a bit of an onion structure, that's why you need 2 steps "in" and 2 steps "out". You can't really do it in the return value that's passed to the executeScript callback, since at least one of the "out" steps will be asynchronous.

2
marlar On

You can inject a script that inserts a DOM node with the global variable's value. Then you return that node's innerHTML and you have your value right away without using a callback:

var code = "script = document.createElement('script'); script.text=\"var n=document.createElement('span');n.style.display='none';n.id='my-id';n.innerHTML=window.globalVar;document.body.appendChild(n)\"; document.head.appendChild(script);document.getElementById('my-id').innerHTML"

webview.executeScript(
    {code: code},
    function(results) {
      console.log(results[0]);
    });

Just use an ID for the DOM node that is not used and you should be fine. It works for me.