When Grass Was Greener

Rants on programming, photography, life, universe and everything

Starting Android application from browser URI

| 8 Comments

Recently, when playing with adding OpenID support to one of Android programs – namely Tracks – I have faced a simple problem.

When using OpenID, one has to delegate authentication to some 3rd party website. This is OpenID Provider. Thanks to this our application (the Relaying Party) does not have to know identifier/password and user authenticates himself on a page he knows. Nor do we have to maintain the security of these in application.

So I’ve started looking at JOpenID.

The very first lines in JOpenID QuickStart say:

1
2
OpenIdManager manager = new OpenIdManager();
manager.setReturnTo("http://www.openid-example.com/openId");

After successful login OpenProvider service will redirect browser to this return address together with OpenID Identifier, encrypted association handler.

Question is: **how can we provide return address so we can start our application and *with resulting URL from browser*?**

The answer lies in [intent filters](http://developer.android.com/guide/topics/manifest/intent-filter-element.html) of the `AndroidManifest.xml`. The [Intents](http://developer.android.com/guide/topics/intents/intents-filters.html) are the glue that cement the Android system, the juice that runs it. Intent system is responsible for starting Activities, interacting between applications and system services.

For each Activity one can declare which [intents](http://developer.android.com/reference/android/content/Intent.html) it shall interact with – that is, say which intents will activate it. This information is stored during application install and browsed by system when an intent is sent.

To *declare* what intents an activity will interact with, one needs to specify an [intent filter](http://developer.android.com/guide/topics/manifest/intent-filter-element.html). Such intent filter contains *action* and possibly *category* and *data* fields.

For example the main activity of application has a filter with *action* `android.intent.action.MAIN` and *category* `android.intent.category.LAUNCHER`. Thanks to this, Android system knows that application should appear in the menu (*category* = `launcher`) and is an entry point into application (*action* = `main`).

So I want to start my application from the browser using a URI. A URI looks like (in short) `scheme://host/path/?query#fragment`. Let’s have a closer look at [*data* field of intent filter](http://developer.android.com/guide/topics/manifest/data-element.html):

1
2
3
4
5
6
7
<data android:host="string"
         android:mimeType="string"
         android:path="string"
         android:pathPattern="string"
         android:pathPrefix="string"
         android:port="string"
         android:scheme="string" />

Looks similar.. And for starting app from browser it is sufficient to define only `scheme` part. Of course an action is needed for the filter: `android.intent.action.VIEW` is ok. But these two elements are not enough, categories are needed.

First of them is `CATEGORY_BROWSABLE`:

Activities that can be safely invoked from a browser must support this category. For example, if the user is viewing a web page or an e-mail and clicks on a link in the text, the Intent generated execute that link will require the BROWSABLE category, so that only activities supporting this category will be considered as possible actions. By supporting this category, you are promising that there is nothing damaging (without user intervention) that can happen by invoking any matching Intent.

and `CATEGORY_DEFAULT`:

Set if the activity should be an option for the default action (center press) to perform on a piece of data. Setting this will hide from the user any activities without it set when performing an action on some data. Note that this is normal -not- set in the Intent when initiating an action — it is for use in intent filters specified in packages.

Bringing all this info together the `StartOnUri` activity is declared and intent-filter defined in the manifest:

1
2
3
4
5
6
7
8
9
        <activity android:name=".StartOnUri"
                 android:label="@string/app_name">
            <intent-filter>
                <data android:scheme="startonuri" />
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT"></category>
                <category android:name="android.intent.category.BROWSABLE"></category>
            </intent-filter>
        </activity>

To test it, it is sufficient to create a simple html file:

1
2
3
4
5
<html>
<body>
  <a href="startonuri://dummy">Click here</a>
</body>
</html>

and click on the Click here link!

Remember to have INTERNET permission enabled for app.

Update

As quite a few people have mailed me for help here’s some sample code. Just build and install this simple application, drop `index.html` to SD card or phone memory and open it in browser.

Sample application: UriStart

8 Comments

  1. Hello,

    I tried it, but Google does not seem to accept non-http scheme. Any idea what I might do ?

  2. The exact example has startonuri:// scheme.. So this is non-http.
    Eg. look also that any link with market:// scheme, launches Android Market when opened in Android’s browser.

  3. Hi,

    I could not get this to work. When i type startonuri:// on my browser (am using an emulator), it does not work. Is there any change I need to make apart from this? Please help.

    Thanks,
    Jayram

  4. Hi Jayram!

    Did you put appropriate intent filters on your activity?

  5. Android browser somehow filters any non-http links unless officially registered (I’d assume the market:// and similar are since they do work ) so all of these nice write ups do not work … there might some hidden trick which I’ve been digging for a good while still with no solution. I saw somebody suggesting using a Java MimeSession I’m about to give that a shot but it is throwing darts in the dark now.

  6. I just re-checked this 10min ago building against JellyBean 4.1.2. Put index.html on sd card, opened this in browser via file explorer, clicked “Click here”. Works like a charm.

    Remember about INTERNET permission. (Maybe I just add this to post).

  7. Is there a way to come back to the browser and to give it some data obtained by the android app?

  8. Dunno. Never had a need for this.

Leave a Reply

Required fields are marked *.