How to Create a Custom Browser for Android Using Crosswalk

  Programming

The Crosswalk project lets you embed the latest version of Chromium in your Android apps, and use it as an alternative to the usual WebView widget. In this tutorial, I’ll show you how to use it to create your very own custom browser. If you are wondering why you would want a custom browser, well, here are some reasons I could think of:

  • You might want to block or redirect certain URLs
  • You might want to make a kid-friendly browser with a fancy UI
  • You might want to intercept some URLs and process them in the background

You could argue that creating an extension for Google Chrome or Mozilla Firefox is easier. You’d even be right. But, you can’t publish browser extensions on Google Play, can you? In any case, I believe that creating a custom browser sounds a lot more fun than creating an extension.

Prerequisites

To be able to follow this tutorial, you’ll need the following:

  • An Android device or emulator that runs API level 15 or higher
  • Android Studio 2.2 or newer

Configure Your Project

To be able to use Crosswalk in your project, add the following compile dependency to your app module’s build.gradle file:

compile 'org.xwalk:xwalk_core_library_beta:18.48.477.13'

The above dependency is not available on jcenter. Instead, it is hosted on Intel’s Open Source Technology Center. Therefore, add the following repository:

repositories {
    maven {
        url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'
    }
}

Finally, press Sync Now to update the project.

Create the Browser’s Layout

At this point, you can add the Crosswalk webview component to your activity’s layout using the <XWalkView> tag:

<org.xwalk.core.XWalkView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/my_browser">
</org.xwalk.core.XWalkView>

For now, that’s all we’ll have in our layout.

All the browser’s controls, such as the forward and back buttons, the address bar, and the stop/refresh buttons, shall be available as menu items. Therefore, create a menu file called browser_controls.xml and add the following to it:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/control_address" android:title="Visit URL"
        app:showAsAction="never"/>
    <item android:id="@+id/control_forward" android:title="Forward"
        app:showAsAction="never"/>
    <item android:id="@+id/control_back" android:title="Back"
        app:showAsAction="never"/>
    <item android:id="@+id/control_refresh" android:title="Refresh"
        app:showAsAction="never"/>
    <item android:id="@+id/control_stop" android:title="Stop"
        app:showAsAction="always"/>
</menu>

Of course, to be able to use your new menu, you must have the following code in your activity:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.browser_controls, menu);
    return true;
}

Initialize the Crosswalk Component

Inside the onCreate() method of your activity, initialize the XWalkView widget using the findViewById() method.

myBrowser = (XWalkView)findViewById(R.id.my_browser);

Furthermore, I’m sure you’d want your own unique user-agent string. You can specify it using the setUserAgentString() method.

myBrowser.setUserAgentString("My Custom Browser/1.0 Android");

A blank browser window isn’t very interesting. Therefore, use the load() method now to navigate to any URL of your choice.

myBrowser.load("http://m.reddit.com", null);

If you run the app now, you should be able to see the XWalkView widget working correctly.

XWalkView widget in action

It is worth mentioning that your APK will be quite large, about 45 MB, which is why you might have to clear up some internal storage space on your device beforehand.

Make the Controls Work

It’s time to make all those controls we mentioned in the menu file functional. Shouldn’t take us more than a few minutes.

First, override the onOptionsItemSelected() method.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // More code goes here
    return true;
}

To go back and forward, we can use the XWalkNavigationHistory object. Additionally, there are appropriately named methods for stop and refresh.

switch (item.getItemId()) {
    case R.id.control_back:
        if(myBrowser.getNavigationHistory().canGoBack())
            myBrowser.getNavigationHistory()
                    .navigate(XWalkNavigationHistory.Direction.BACKWARD, 1);
        break;
    case R.id.control_forward:
        if(myBrowser.getNavigationHistory().canGoForward())
            myBrowser.getNavigationHistory()
                    .navigate(XWalkNavigationHistory.Direction.FORWARD, 1);
        break;
    case R.id.control_stop:
        myBrowser.stopLoading();
        break;
    case R.id.control_refresh:
        myBrowser.reload(XWalkView.RELOAD_NORMAL);
        break;
    case R.id.control_address:
        showAddressDialog();
        break;
}

In the above code, you can see that we are calling the showAddressDialog() method when the user chooses to visit a new URL. The method doesn’t exist yet, so we must create it now.

private void showAddressDialog() {

}

Inside the method, use the AlertDialog.Builder class to create a new dialog that prompts the user to enter the required URL.

// Create a simple address bar
final EditText input = new EditText(this);
input.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
input.setText("https://");

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Enter URL")
        .setTitle("Navigate")
        .setCancelable(true)
        .setView(input)
        .setNeutralButton("Go", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                myBrowser.load(input.getText().toString(), null);
            }
        });
builder.create().show();

You can run your app now, and use your custom browser. It should behave very much like any other browser.

Intercept URLs

Let me now quickly show you how you can intercept a specific URL and display a message of your choice.

To be able to intercept URLs, you must add a XWalkResourceClient to your XWalkView widget. Additionally, you must override the shouldInterceptLoadRequest() method of the resource client object.

myBrowser.setResourceClient(new XWalkResourceClient(myBrowser) {
    @Override
    public XWalkWebResourceResponse shouldInterceptLoadRequest(
                    XWalkView view, XWalkWebResourceRequest request) {
        // More code goes here
    }
});

If you return null in the shouldInterceptLoadRequest() method, it means you don’t intend to change the response at all. However, if you return a XWalkWebResourceResponse object, the XWalkView widget will render that instead of the original response.

For now, let’s just intercept youtube.com and stop the user from visiting it. To create the XWalkWebResourceResponse, you can use the createXWalkWebResourceResponse() method.

if(request.getUrl().getHost().equals("youtube.com")) {
    ByteArrayInputStream bis =
            new ByteArrayInputStream(
                    "You are not allowed to visit Youtube".getBytes());
    return createXWalkWebResourceResponse("text/plain", "UTF-8", bis);
} else
    return null;

Run your app and try visiting Youtube now. You won’t be able to.

Conclusion

In this tutorial, you learned how to create a custom browser for Android using the Crosswalk project. You also learned how to intercept requests. We didn’t focus much on the user interface, however. Therefore, I suggest you spend some time now improving the looks of your browser.

If you found this article useful, please share it with your friends and colleagues!