Note that there are some explanatory texts on larger screens.

plurals
  1. POAndroid webview doesn't execute javascript from script src
    primarykey
    data
    text
    <h1>The Problem</h1> <p>The webview doesn't actually execute the scripts loaded through src from a remote location</p> <h1>Checked and double checked</h1> <ul> <li><p>The permission: <code>&lt;uses-permission android:name="android.permission.INTERNET" /&gt;</code></p></li> <li><p>That the file <code>http://localhost/android/test.js</code> exists</p></li> <li><p>That it called <code>view.getSettings().setJavaScriptEnabled(true);</code> before loading an URL</p></li> </ul> <h1>The code</h1> <p>Given a <code>WebView view</code> and a <code>Context context</code></p> <h2>Building a document</h2> <p>It will need cookies so need to dynamically build it. file:// urls don't allow for cookies. Either way, this 'should' work just fine.</p> <pre><code>String html = "&lt;html&gt;\n" + "&lt;head&gt;\n" + "&lt;/head&gt;\n" + "&lt;body&gt;\n" + "&lt;script src=\"http://localhost/android/test.js\" type=\"text/javascript\"&gt;&lt;/script&gt;\n" + "&lt;/body&gt;\n" + "&lt;/html&gt;"; String mime = "text/html"; String encoding = "utf-8"; </code></pre> <h2>Cookies enabled</h2> <p>Simple functions to make sure the device retains cookies. </p> <pre><code>CookieSyncManager.createInstance(context); CookieSyncManager.getInstance().sync(); </code></pre> <h2>Creating a chrome client for logging</h2> <p>Logging all messages [twice] and when the page is done loading execute a function. This actually works well. Adding more [remote] script tags delays the execution.</p> <pre><code>WebChromeClient client = new WebChromeClient ( ) { @Override public boolean onConsoleMessage(ConsoleMessage consoleMessage) { Log.e( "JSINTERFACE", consoleMessage.message() ); return super.onConsoleMessage(consoleMessage); } @Override public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); loadingFinished = ( newProgress == 100 ); Log.d( "JSINTERFACE", "Progress is:" + newProgress ); if ( loadingFinished ) { Log.i( "JSINTERFACE", "Finished loading webclient" ); execute(); } } }; </code></pre> <h2>Loading the view</h2> <p>Attach the chrome client, enable javascript, add the interface and start loading!</p> <pre><code>view.setWebChromeClient( client ); view.getSettings().setJavaScriptEnabled(true); view.addJavascriptInterface( new JSInterface(), "bridge" ); view.loadDataWithBaseURL( "http://localhost/android/", html, mime, encoding, null ); </code></pre> <h1>The Interface</h1> <p>The interface looks as follows</p> <pre><code>public class JSInterface{ @JavascriptInterface public void result( int success, String message ) { Log.i( "JSINTERFACE", message ); // TODO handler } } </code></pre> <p>I can actually test javascript AND the interface by calling </p> <pre><code>view.loadUrl("javascript:bridge.result( 0, 'TESTING INTERFACE' );"); </code></pre> <p>As long as this is postponed until after loading has completed (for example in the <code>execute function</code> this works fine. And the message is logged.</p> <h1>Inside the <code>test.js</code> script</h1> <p>A very simple script</p> <pre><code>console.log( 'test loaded' ); var test = function() { console.log( 'test' ); bridge.result( 1, 'res' ); } </code></pre> <h1>Why doesn't it work?</h1> <ul> <li><p>I don't see the <code>test loaded</code> log, should be captured by the client</p></li> <li><p>When I call <code>view.loadUrl("javascript:console.log(test)</code> I get <code>test is not defined</code></p></li> </ul>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload