56

So I want to create an Android app so it would be registered somewhere in android OS (or just would start on system start) and when phone user clicks on special button on a web page inside a web browser a la:

 <a href="myapp://mysettings">Foo</a> 

my app would pop up and run using the params sent in that URL.

So how do I do such thing?

I need a tutorial with code!

Michael Petrotta
  • 59,888
  • 27
  • 145
  • 179
Rella
  • 65,003
  • 109
  • 363
  • 636
  • 1
    This is quite possibly a duplicate of http://stackoverflow.com/questions/525063/android-respond-to-url-in-intent – Casebash May 11 '10 at 04:54
  • 1
    There's a great answer to this question at http://stackoverflow.com/questions/2448213/how-to-implement-my-very-own-uri-schema-on-android/2448531#2448531 – neu242 Jun 24 '10 at 06:10

4 Answers4

58

First, to be able to start your app from link with custom scheme 'myapp' in browser / mail, set intent filter as follows.

<intent-filter> 
  <action android:name="android.intent.action.VIEW"/> 
  <category android:name="android.intent.category.DEFAULT"/> 
  <category android:name="android.intent.category.BROWSABLE"/> 
  <data android:scheme="myapp"/> 
</intent-filter>

and to parse queries in your link myapp://someaction/?var=str&varr=string
(the code is over simplified and has no error checking.)

Intent intent = getIntent();
// check if this intent is started via custom scheme link
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
  Uri uri = intent.getData();
  // may be some test here with your custom uri
  String var = uri.getQueryParameter("var"); // "str" is set
  String varr = uri.getQueryParameter("varr"); // "string" is set
}

[edit] if you use custom scheme to launch your app, one of the problem is that: The WebView in another apps may not understand your custom scheme. This could lead to show 404 page for those browser for the link with custom scheme.

9re
  • 2,408
  • 27
  • 27
49

You need to follow the standard rules for URIs via the W3C and such, which basically means: do not do this.

Android defines a Uri syntax for describing a generic Intent. There are methods on Intent for converting to and from this representation, such as: http://developer.android.com/reference/android/content/Intent.html#toUri(int)

So the way to do this is to use the normal facilities to describe an in your manifest for the kinds of intents you are going to handle with a particular component, especially defining an action name in your own namespace (com.mycompany.myapp.action.DO_SOMETHING or whatever). You can then make an Intent that matches your component, and use Intent.toUri() to get the URI representation of this. This can be placed in your link, and will then when pressed look for something that handles and and thus find your app. Note to be launched from the browser like this, the component's must handle the BROWSABLE category. (You don't need to have this in the Intent you put in the link, the browser will automatically add this in for you.)

Finally, you may want to set the package of the intent to your app with this: http://developer.android.com/reference/android/content/Intent.html#setPackage(java.lang.String)

This is a newer feature in the platform, which allows you to direct link intents to only your app so that other applications can not intercept and handle them.

In summary: read the regular documentation on intents and intent filters (such as the NotePad tutorial, though you won't be using content: URIs here, probably just custom actions) and get your app working that way. Then you can make a browser link to launch your app in the same way, provided your intent-filter handles the BROWSABLE category.

Will
  • 6,601
  • 3
  • 31
  • 42
hackbod
  • 90,665
  • 16
  • 140
  • 154
  • 3
    At first I thought that you didn't explain how ignoring the standard rules for URIs is bad, but then I found your [other answer here](http://stackoverflow.com/questions/2448213/how-to-implement-my-very-own-uri-schema-on-android/2449500#2449500). – Casebash May 11 '10 at 04:07
  • Those URLS don't quite appear properly (the bracket on the end is excluded) – Casebash May 11 '10 at 04:56
  • I can't get this to work. Are the URIs meant to be of the following form? `intent:#Intent;action=android.intent.action.VIEW;component=com.mycompany.project/.InitActivity;end` – Casebash May 12 '10 at 05:50
  • 2
    @hackbod: Like Casebash, I am having problems with your instructions. Given an activity, I dump `getIntent().toUri(Intent.URI_INTENT_SCHEME).toString()`, paste that in a Web page (http://commonsware.com/sample), try opening it in a browser on the emulator, and I get choices of opening the page in Browser, Contacts, or Phone, but not my activity. That seems strange, considering that the `intent:` URI from `toUri()` has the `component` clause, so I'm not sure how those other apps can get it. I have the `BROWSABLE` category on the intent filter. If you have any thoughts, please @ me back. Thanks! – CommonsWare Jun 25 '10 at 23:25
  • The browser strips the component part. Because that allows you to launch any component (that you have permission for) regardless of what else is in the intent, it would be a security risk to blindly launch such a link. If you want to launch a specific activity in an .apk, starting in 2.1 you can set a package on an intent, which limits its matching to the activities in that package. So you can build an intent with action="com.mycompany.myaction" and package="com.mycompant"; your package's activity that supporting the "com.mycompany.myaction" action and the DEFAULT and BROWSABLE catergories. – hackbod Jun 26 '10 at 00:56
  • 4
    Don't bother trying this method if you want your URIs to reliably work; using intent URIs requires cooperation from the app taking the URI. zxing (Barcode Scanner) doesn't accept them (by deliberate design decision, apparently), so if you want to be able to scan barcodes to talk to your app (or take URI input from any other method you don't completely control), you either need to overload http:// (which requires a user choice between browser and your app) or just go with a custom scheme, which as far as I can tell passes transparently into the system and doesn't get caught up anywhere). – womble Mar 08 '11 at 02:42
  • Exspecially the part about "defining an action name in your own namespace" doesnt make sense to me. – Pascal Klein Apr 01 '11 at 15:45
  • 4
    @hackbod can you please point me to w3c documentation which suggests to not implement new URI schemes? I have only found rfc2718 which seems to support that. – guido Apr 21 '12 at 08:37
  • I'm getting "Unknown URL Scheme" error (HTTP 302) on Chrome for Android. I've tried @CommonsWare link and got the same error. And I wrote an e-mail with an href referencing this URI, and it didn't appear as a link on the e-mail body (either on browser or android Gmail) – Leaudro Mar 21 '13 at 19:26
  • @CommonsWare Were you able to make the intent scheme link to work ? I tried the following : intent:#Intent;action=com.android.test2.app.testAction;end, but no activity comes up. – Jake Jun 29 '14 at 09:06
  • @Jake: It won't be reliable in browsers, as not all may recognize that URL pattern. That being said, [this project](https://github.com/commonsguy/cw-omnibus/tree/master/Introspection/URLHandler) demonstrates one using an action. – CommonsWare Jun 29 '14 at 10:46
  • @CommonsWare what about Android's default browser ? – Jake Jun 29 '14 at 14:18
  • @CommonsWare I tested it again on the default browser, it works fine, thanks. – Jake Jun 29 '14 at 14:32
  • Can you please give an example? – Juampa Aug 01 '14 at 02:35
  • 4
    @hackbod - It appears this would not work with iOS though. It seems registering a unique scheme is the most cross-platform compatible implementation although I agree with you that it pollutes the namespace... https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html#//apple_ref/doc/uid/TP40007072-CH6-SW1 – runamok Oct 08 '15 at 19:43
47

Here is my cut to the chase contribution.

Create an intent filter in the activity you want to load in the manifest like this:

<intent-filter>
    <action android:name="com.bubblebeats.MY_CUSTOM_ACTION" />
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>

Your web page URL for this will look like this:

intent:#Intent;action=com.bubblebeats.MY_CUSTOM_ACTION;end

The most basic HTML code to launch your apk from a browser would look like this:

<body>
    <a href="intent:#Intent;action=com.bubblebeats.MY_CUSTOM_ACTION;end">click to load apk</a>
</body>

To add variables to your intent

You can generate the URI from within your Android code like this:

Intent i = new Intent();

i.setAction("com.bubblebeats.MY_CUSTOM_ACTION");
i.putExtra("some_variable", "123456");

Log.d("ezpz", i.toUri(Intent.URI_INTENT_SCHEME));

This will produce this:

04-13 09:47:30.742: DEBUG/ezpz(9098): intent:#Intent;action=com.bubblebeats.MY_CUSTOM_ACTION;S.some_variable=123456;end

You just want this part:

intent:#Intent;action=com.bubblebeats.MY_CUSTOM_ACTION;S.some_variable=123456;end

Take a good look at what occurred here and you can see how you can skip the code step and manually create these URIs yourself.

Especially this part:

S.some_variable=123456
Jason Van Anden
  • 879
  • 8
  • 18
  • What does the package (from `intent.setPackage(..)` serialize out to? – nmr Dec 14 '11 at 23:05
  • 1
    Looks like the package is appended like `package=com.bubblebeats;` (Also, while not evident in this example, the package is URI encoded) – nmr Dec 14 '11 at 23:09
  • 3
    @Jason, were you able to get this to work? Launching the intent via "adb shell am start 'intent:#Intent..." works for me. However, from a browser, clicking on the linnk intent doesn't trigger the app launching. – hopia Sep 20 '12 at 16:12
  • Where does the `S.` syntax is documented? Just relying on the output of `toUri()` doesn't seem a good idea. – cYrus Feb 16 '14 at 18:06
  • That's a great answer. Just wondering whether the same would work from within the SMS too? I mean in sms we cannot create a hyperlink which sends the following call on being clicked: `intent:#Intent;action=com.bubblebeats.MY_CUSTOM_ACTION;end`. Even if I directly put it in sms, I think it won't be clickable or will it be ? – Shobhit Puri Feb 24 '14 at 17:42
  • @cYrus https://code.google.com/p/android-source-browsing/source/browse/core/java/android/content/Intent.java?repo=platform--frameworks--base#3719 – domen Aug 14 '14 at 10:13
  • @domen Thanks, but the code does not provide any contract, I cannot rely on it. – cYrus Aug 14 '14 at 14:10
  • Agreed, but can't find anything official. :( Best I could find is https://developer.chrome.com/multidevice/android/intents which then references the source. – domen Aug 14 '14 at 15:49
  • What if you want an array with strings for example? I don't see them in the url anymore. – Roel Sep 07 '15 at 12:17
  • How to make a webview open such a link? It only works in Chrome. – Roel Sep 07 '15 at 13:19
10

Because hackbod never gave us code-examples, I just want to share mine, after I got this to work.

First of all, you need to define a custom action in your manifest file:

<activity
    android:name=".activity.MainActivity"
    android:label="@string/app_name_full">
    <intent-filter>
        <action android:name="com.yourpackage.action.OPEN_VIEW"></action>
        <category android:name="android.intent.category.DEFAULT"></category>
        <category android:name="android.intent.category.BROWSABLE"></category>
    </intent-filter>
</activity>

Then, for the content on your website, you need to generate the URI from an intent. Put following code in your Activity (This code could be removed, once the link is generated):

Intent i = new Intent();
        i.setAction("com.yourpackage.action.OPEN_VIEW");
        i.setPackage("com.yourpackage");
        i.putExtra("myextra","anystring");
        Log.d(getClass().getSimpleName(), i.toUri(Intent.URI_INTENT_SCHEME));

To receive the Extras, put following in your activity, that is able to recieve the custom action (as defined in manifest):

final Intent intent = getIntent();
final String action = intent.getAction();

        if ("com.yourpackage.action.OPEN_VIEW".equals(action)) {
           Log.i(getClass().getSimpleName(), "EXTRA: "+intent.getExtras().getString("myextra"));
        }

On your website (this is the previously generated link):

<a href="intent:#Intent;action=com.yourpackage.action.OPEN_VIEW;package=com.yourpackage;S.myextra=anystring;end">Open App with extra</a>

Hope that helps someone for better understanding. Please correct me, if I got something wrong.

AlbAtNf
  • 3,859
  • 3
  • 25
  • 29