AdaCore Blog

Android application with Ada and WebAssembly

by Maxim Reznik

Having previously shown how to create a Web application in Ada, it's not so difficult to create an Android application in Ada. Perhaps the simplest way is to install Android Studio. Then just create a new project and choose "Empty Activity". Open the layout, delete TextView and put WebView instead.

In onCreate function write the initialization code:

WebView webView = (WebView)findViewById(R.id.webView);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);

To make WebView work offline, you need to provide content. One way to do this is just to put content in the asset folder and open it as a URL in WebView. When a user starts the application, WebView will load HTML and corresponding JavaScript. Then JavaScript loads WebAssembly and so, actually, launches Ada code. But it can't use a file:/// schema to load JavaScript and WebAssembly files because of the default security settings. So we trick WebView by intercepting requests and also provide correct MIME types for them. We do this using the shouldInterceptRequest method of WebViewClient class to intercept any request to HTML/WASM/JS/JPEG resources and load the corresponding file from the asset folder:

public WebResourceResponse shouldInterceptRequest(WebView view,
                                                  WebResourceRequest request) {
    String path = request.getUrl().getLastPathSegment();

    try {
        String mime;
        AssetManager assetManager = getAssets();

        if (path.endsWith(".html")) mime = "text/html";
        else if (path.endsWith(".wasm")) mime = "application/wasm";
        else if (path.endsWith(".mjs")) mime = "text/javascript";
        else if (path.endsWith(".jpg")) mime = "image/jpeg";
        else
            return super.shouldInterceptRequest(view, request);

        InputStream input = assetManager.open("www/" + path);

        return new WebResourceResponse(mime, "utf-8", input);
    } catch (IOException e) {
        e.printStackTrace();
        ByteArrayInputStream result = new ByteArrayInputStream
                (("X:" + path + " E:" + e.toString()).getBytes());
        return new WebResourceResponse("text/plain", "utf-8", result);
    }
}

Now connect this code to WebView, like this:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view,
....
});

For debug purposes, let's connect the WebView console to Android log. We just add this function below the code for shouldInterceptRequest:

public boolean onConsoleMessage(ConsoleMessage cm) {
    Log.d("MyApplication", cm.message() + " -- From line "
            + cm.lineNumber() + " of "
            + cm.sourceId() );
    return true;
}

Now we're able to build and run an Android Package. Here is how it looks like on Android Studio emulator (it's been tested on my phone too!):

If you need the complete code, there's a repository on github!

PS: This article doesn't discuss how we produced WebAssembly from Ada code for running with WebGL integration. We will write a follow-up post about that soon!

Posted in #WebAssembly    #web    #android   

About Maxim Reznik

Maxim Reznik

Maxim Reznik is a Software Engineer and Consultant at AdaCore. At AdaCore, he works on the GNAT Studio, the Ada VS Code extension and the Language Server Protocol implementation.