13

I have a situation where I'd like for some data to be passed from a mobile web site to a native Android app. A complication is that, in the normal case, the native Android app might not be installed when the mobile web site is loaded.

Here's an example:

I am a user of ExampleApp and I want to share a particular piece of data from ExampleApp with you, who has never installed ExampleApp.

I send you an email with a link to a mobile web page that knows what piece of data you want to see when you open the link. But, since the data is only available in the native app, not the mobile web, you're taken to a page that asks you to go to Android Market and install ExampleApp.

You install ExampleApp, and ideally, you'd be taken directly to the piece of data that I shared with you.

The big problem is in the disconnect between viewing the mobile web page and the installation of ExampleApp.

I've thought about a couple solutions, but neither have been successful (that said, I could just be implementing them incorrectly):

  1. Set a cookie on our domain that includes the data when the mobile web page is loaded. Then, when ExampleApp is opened, start a WebView to request a page on the same domain and check the value of the cookie. Use that to determine what piece of data to show in ExampleApp.
  2. Use JavaScript localStorage to store a reference to the piece of data and use a WebView to get a page on that domain and request the content of localStorage from within ExampleApp.

In both these situations, it seems as though the WebView and the Browser are sandbox'd away from each other, so you can't get at the cookies/localStorage between the two.

Is there any other way to "leave a crumbtrail" or set a message that an app installed later can access from the Browser?

EDIT: Given some of the responses, I should mention that I only want you to click once on the link, NOT have to click once, install the app, then click again to open the app to the right place.

iseff
  • 131
  • 1
  • 6
  • I'd be afraid of apps that get messages from my browser. Just seems like that "cool game" I bought would be paid for by marketing firms just farming data. I sure hope you can't do this! – corsiKa Feb 25 '11 at 23:49

4 Answers4

11

The solution is actually quite simple, I'm a bit astonished that nobody has been able to come up with it for over a year. So here it is:

The basic idea is to use cookies to store the information. The data flow is as follows:

open web page -> set cookie -> redirect to market -> install app -> launch browser with web page -> read cookie -> start custom intent with cookie data -> capture intent and read cookie data

The user visits a webpage (by scanning a QR Tag for example). The url of the webpage holds a reference to the data you want to pass, or holds the data itself. The website sets the data as a cookie and redirects to the Android market (http://market.android.com/details?id=com.yourapp). As soon as your app launches, you open a browser and load the same webpage again. This time however, it detects that the cookie is already set and redirects to a custom URL scheme like example://example.com/installed?id=DATA, instead of the market. Using an intent filter, you launch your activity and extract the information from the intent.

Here is the relevant Activity code:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Intent intent = getIntent();
    if(intent == null || intent.getData() == null || !"example".equals(intent.getData().getScheme())) {
        String url = "http://example.com/yourApp/index.php";
        Intent i = new Intent(Intent.ACTION_VIEW);
        i.setData(Uri.parse(url));
        startActivity(i);
        finish();
        return;
    }else {
        Uri uri = intent.getData();
        if("example".equals(uri.getScheme())) {
            id = uri.getQueryParameter("id");
        }
    }
    ... initialise your activity ...
}

A simple PHP file (the website) for easy demonstration:

<?php
$value = "123";
if(!isset($_COOKIE["TestCookie"])) {
    setcookie("TestCookie", $value, time()+3600);  /* expire in 1 hour */
    header("Location: http://market.android.com/details?id=com.yourapp");
    exit;
}else {
    header("Location: example://example.com/installed?id=".$_COOKIE["TestCookie"]);
    exit;
}
?>

And the intent filter:

<!-- Handle URLs like loyalty://example.com/merchant/123 -->
<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="example" android:host="example.com" />
</intent-filter>

BTW, I have decided to blog about the issue.

Florian
  • 3,069
  • 1
  • 26
  • 26
  • Have you passed tests with this? In the original question, iseff cites his Cookies as not working (sandboxed environments), so I am wondering if you were able to access the cookie `TestCookie` from the Browser in the App. Thanks – DougA Mar 16 '12 at 14:22
  • 1
    Sure, I've tested that it works! Please note that the website which sets the cookie and retrieves it an then launches the custom intent, is always opened in the stock Android browser, not in the WebView. Therefore the cookie will be available. – Florian Mar 19 '12 at 08:22
  • 1
    That's great! You mention "stock browser" but what about non-stock browser such as Firefox or SkyFire? I am hoping it works across all browsers, not just the default. (If you could be a dear and test those too... that would help many people I am sure!) – DougA Mar 19 '12 at 12:13
  • It does not matter which browser the user chooses to use, it's just important that the same browser is used for both requests (the one before and the one after installing the app). I.e. I just wanted to stress that the app does not use a WebView to open the URL after installation (where the cookie would not be available, as the WebView is sandboxed). – Florian Mar 20 '12 at 14:35
  • Simply brilliant, Florian. – Slawomir Feb 26 '17 at 22:29
  • Would there be any security concerns in adding a cookie to a URL path? – AbdullahC May 05 '17 at 11:54
4

Is there any other way to "leave a crumbtrail" or set a message that an app installed later can access from the Browser?

I think there is a simpler solution, a variation on the one employed by Barcode Scanner.

Step #1: Create a nice RESTful URL that contains the information you want. By RESTful I mean no ?, no #, none of that crap. It'll be a smidge simpler if this is on a distinct domain name, but this could just be something on your existing domain. For the purposes of this answer, I will assume that this URL looks like http://android.exampleapp.com/our/custom/data/goes/in/here/somewhere.

Step #2: For all URLs that could be created following the pattern of Step #1 (anything in http://android.exampleapp.com), your Web server should serve up a page saying "Hey! You don't have ExampleApp installed! If you click this link here, it will take you to the Android Market, where you can install ExampleApp! Then, try clicking the link that brought you to this page, and it will start up ExampleApp and give you...ummm...all this good data".

Step #3: Implement an activity in ExampleApp that has an <intent-filter> with the VIEW action, the BROWSEABLE category, and a <data> element identifying your scheme and domain (and, if needed, the base path, if that will be the same for all of these links).

What the user sees, if they do not have ExampleApp installed and click the link, is your Web page from step #2, from which they can go install ExampleApp.

What the user sees, if they do have ExampleApp installed and click the link, is your activity, which can grab the URL via getIntent().getData() and do something useful.


UPDATE

In a comment, you wrote:

mobile web page => store data => user installs app => user opens app => app retrieves data => app opens directly to the content retrieved

IMHO, you make too many assumptions about what the user is going to do. There may be days, weeks, or months of delay in between the arrows that I put in bold.

If you are going to distribute it yourself (e.g., off of your Web server), you always have the option of "burning" them a custom APK with the data inside of it, but then you have to deal with managing updates yourself.

Or, if you are going with an account-based system, have them create an account on your site before sending them to the Android Market. Store the data under that account, and when they connect back to that account from the app, you can match up the data with the app.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • This, too, is based on the two clicks by the user to make it happen. I'm hoping to reduce this to a single click on the URL they received. Then we can move them through the install process easily and they can immediately see the data. Thoughts on that? – iseff Feb 26 '11 at 00:22
  • @iseff: "This, too, is based on the two clicks by the user to make it happen." -- it's going to be way more than two clicks no matter how you accomplish it. Have you ever installed an app on Android before? There will be 2-3 clicks in the Market, plus using the notification to launch the app, irrespective of clicks before the Market or within the app. BTW, I added some more notes to my answer. – CommonsWare Feb 26 '11 at 00:51
  • Of course it'll be more than two clicks in its entirety; I mean two clicks on the *original* link (click once, sent to a "download app" page, install app, click again, sent to the app). I'm looking for a seamless flow. We've certainly thought about the registration process, but again, less friction is better. In terms of "days/hours/months" of delay between the arrow, well, we can minimize that by having the link to Market do the data store, and then, in most cases, it'll be pretty fast. There's obviously lots of ways to get around this issue, but I'm looking for the least friction. – iseff Feb 26 '11 at 01:17
  • No, stop looking for this. If there is a way for a web page to directly invoke another application without the user clicking something to confirm, this would be a security hole that needs to be fixed. – hackbod Feb 26 '11 at 04:34
0

See: https://stackoverflow.com/a/7577379/710284

You can use an INSTALL_REFERRER link like:
http://market.android.com/details?id=your.package.name&referrer=your_wanted_parameter

After a user clicks this link and installs the application your broadcast receiver will receive a broadcast com.android.vending.INSTALL_REFERRER with "your_wanted_parameter" value.

More info:
http://code.google.com/mobile/analytics/docs/android/#android-market-tracking
Get referrer after installing app from Android Market
Get Android Google Analytics referrer tag

Community
  • 1
  • 1
Oded Breiner
  • 28,523
  • 10
  • 105
  • 71
  • Referrer seems unreliable and doesn't work on some devices. Market apps such as "Referrer Test for Google Play" and "Install Referrer Test" don't show the referrer on my Galaxy S III. – Ilya Kogan Jul 01 '13 at 14:47
0

Use a GET parameter: http://exampleapps.com?token=mK7Fyt5 Think of the way the YouTube app works. You're sent to the link for a video. If you don't have the YouTube app, you see the mobile site (which in your case could be an install link). If you do, you get asked whether to open the YouTube link with the native app, and the native app is passed the URL from which it was invoked, from which it can parse out the parameter for the video to show.

Use the following intent filter:

<intent-filter>
    <data android:scheme="http" android:host="exampleapps.com"/>
    <action android:name="android.intent.action.VIEW" />
</intent-filter>
fredley
  • 32,953
  • 42
  • 145
  • 236
  • Sorry, I guess my question should have been more clear. The idea is to get folks to install the app as that is the ONLY way they can see the content. So it is: mobile web page => store data => user installs app => user opens app => app retrieves data => app opens directly to the content retrieved – iseff Feb 26 '11 at 00:11
  • 1
    Ah that's a bit clearer. I don't think that's possible, and anyway it's not expected behaviour, users will be ok with the idea of going back to the link they were sent once they've installed the app. – fredley Feb 26 '11 at 00:13