Android

Pro tip: Inject JavaScript into an Android web view for a more dynamic UX

Hardcore app developers usually prefer to stay away from web views. However, when the client requires it, injecting JavaScript at runtime provides a way to make the user experience more dynamic.
 
android_apps_090613.jpg

As someone who develops native apps for a living, I am not a big fan of web views. If you are not familiar with the concept, a web view is essentially an embedded browser that displays HTML within an app. It's not that I dislike HTML per se — HTML 5 can be quite impressive — but in my experience, web pages embedded within a native app usually look like…well, web pages embedded within an app. 

In particular, if you are working on an app where you don't have control of the HTML being displayed in the web view, you often run into an issue where the HTML served up from the external URL sticks out like a sore thumb. After all, chances are it wasn't designed specifically for your app. There is nothing more frustrating to a mobile developer than to spend months creating a brilliant user experience only to have to throw a web view into the middle of it.

I find that by injecting JavaScript into the web view at runtime I can make these fairly static web views more dynamic. This tutorial demonstrates how to seek out an element by id within a web view and replace its content after the page successfully loads. Follow the step-by-step walk-through or download and import the entire project directly into Eclipse.

1. Create a new Android project in Eclipse targeting Android 2.3 (Gingerbread) or better.

2. In the /assets folder, create a static file called index.html to simulate remote content served up from a web server.

 

index.html
<!doctype html>
<html>
<head>
	</head>
	<body>
		<center>
			<div id="msg">Hello World!</div>
		</center>
	</body>
</html>
 

3. In the /res/layout folder, create our layout. We want a simple linear layout with an edit text field, a button, and a web view. I've used a layout weight to flow the web view over the majority of the device display.

 

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:layout_gravity="center"
    android:orientation="vertical">

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/edit_text"
        android:hint="What is your name?" ></EditText>
    
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button"
        android:text="Update Web View"></Button>
    
    <WebView 
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
        android:layout_weight=".5"
       android:id="@+id/webview" ></WebView>

</LinearLayout>
 

4. Fill in our ActivityMain.java file in the /src folder. The on create override does most of the work and, in particular, the anonymous inner class that overrides on page finished in the web view client. As long as you remember to enable JavaScript on your web view client and set the web Chrome client, your custom web view client can insert and execute just about any JavaScript you can dream up.

 

MainAcitivity.java
package com.authorwjf.javascriptinjection;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.annotation.SuppressLint;
import android.app.Activity;

public class MainActivity extends Activity implements OnClickListener {
	
	private static final String URL = "file:///android_asset/index.html";
	private WebView mWebView;

	@SuppressLint("SetJavaScriptEnabled")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mWebView = (WebView) findViewById(R.id.webview); 
		mWebView.getSettings().setJavaScriptEnabled(true);
		mWebView.setWebChromeClient(new WebChromeClient());
		mWebView.setWebViewClient(new WebViewClient(){
			@Override
	        public void onPageFinished(WebView view, String url) {
				String user = ((EditText) findViewById(R.id.edit_text)).getText().toString();
				if (user.isEmpty()) {
					user = "World";
				}
	            String javascript="javascript: document.getElementById('msg').innerHTML='Hello "+user+"!';";
	            view.loadUrl(javascript);
	        }
		});
		refreshWebView();
		findViewById(R.id.button).setOnClickListener(this);
	}
	
	private void refreshWebView() {
		mWebView.loadUrl(URL);
	}

	@Override
	public void onClick(View v) {
		refreshWebView();
	}

}
  

In this example, the JavaScript will customize the "hello" message based on the contents of the edit text. Give it a try!

 

inject_js_1_032514.png
 
inject_js_2_032514.png
  

 




About

William J Francis began programming computers at age eleven. Specializing in embedded and mobile platforms, he has more than 20 years of professional software engineering under his belt, including a four year stint in the US Army's Military Intellige...

0 comments