I'm in a real pickle and desperately need some help with a critical problem I'm having.
I've spent months writing a HTML5 app/website along with a native Android application that is simply a WebView wrapper for the HTML5 website. One of the core features of the application is that users can share app specific URLs to Facebook and Twitter etc so that their friends can follow the shared URLs which will open up either the HTML5 version of my app in their browser OR MOST IMPORTANTLY if they are on Android and they have my native Android app installed they are PROMPTED TO OPEN IN MY APP.
This is a rather long complicated issue so to simplify I'll use some certain terms consistently through-out this post:
My AndroidManifest.xml contains the following...
<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="http" android:host="myapp.com" android:pathPrefix="/" />
</intent-filter>
When tested this WORKS PERFECTLY in any normal scenario. For example if a "MyApp user" follows a direct link to http://myapp.com/sharedpage, the "choose app dialog" appears. Great, I've definitely configured my AndroidManifest.xml correctly.
However things do NOT ALWAYS WORK in the critical Facebook sharing scenerio. It does not always work because both Facebook's native Android app and Facebook's mobile website (http://m.facebook.com) DO NOT LINK DIRECTLY to the shared URLs but instead link via a Facebook redirect page. For example if http://myapp.com/sharedpage is shared, Facebook will ultimately deliver the following URL:
http://m.facebook.com/l.php?u=http%3A%2F%2Fmyapp.com%2Fsharedpage&h=EAQGpLtuF&enc=AZMXYZg7XwQ39zlWkKSGnLw62lEbtbMeWFmRwRZINoOcg0UgZe3fUVPgqQzV1nuTipSVnquV3a3ovqu7HQFUf3bb3ZJ1gYG8dEOJXzPf6RJGflf9_x8w-6CCXu8G2VZqgfD7lx6EbLTSKLnF56_o5khHybycPUlhpdfLsk6M9muer4jMOmPK6_kfjTq2gvnYNNpStcF0ilJD6nacPqx_1xsdYkUMpKYWbJfSo7qqv1S5xT5KRaLPxl8zmAkYc0FhwyTdn-tUGwRBbbdM4QCd2Z75Tb_VeJG3LvbDwFAbp6G3kH3LOSxVtTd5MST4pUW8xmhNeTUVBVXV16OD27QcsSWOlEfL72fxn11PDE5s4WWsXMnwhDJLUAWOAna7lziBnWzjZdlQK_amI9nhcegaOLDLNFCp125rZS3jxFXf7gtF9g0BsmnPZ2Gjxkc6UgQXhEYldllq9nwpShGbnZDlSg0_&s=1
If a "MyApp user" follows one of these Facebook links one of two things might happen depending on the browser they are using...
MyApp Stock Browser User:
If the user has stock Android installed and uses the stock Android browser then things work FINE because the following events occur...
MyApp Non-Stock Browser User:
HOWEVER if the user...
... then here's the MAJOR ISSUE because the following events occur...
Client Side Redirect
In order to confirm its the redirect that was causing the problem, I created a very simple HTML page named "clientSideRedirector.htm"
<html><body><script>
window.location.href = "http://myapp.com/sharedpage";
</script></body></html>
If My-App/non-stock browser user opens http://myapp.com/clientSideRedirector.htm the "app choice dialog" does NOT appear. FAIL.
If My-App/stock browser user opens http://myapp.com/clientSideRedirector.htm the "app choice dialog" DOES appear.
This would seem to tally up with what we're seeing with the Facebook share/redirect.
Server Side (302) Redirect
I also thought I'd try a server side redirect so I created a .NET dotNetRedirect.ashx page:
public class ShareRedirect : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.Redirect("http://myapp.com/sharedpage");
}
public bool IsReusable { get { return false; } }
}
This has a very interesting and different result to the client redirect.
If My-App user opens the http://myapp.com/dotNetRedirect.htm the "app choice dialog" DOES appear REGARDLESS of the users browser.
So this type of redirect seems to work!
Attempted Solution A
(Double redirect: Facebook l.php redirect to server-side redirect to app URL)
I thought this could be the solution to my Facebook sharing problems. If I shared http://myapp.com/dotNetRedirect.ashx URL to Facebook then maybe Facebook would redirect to the dotNetRedirect.htm page and then the server side redirect would force the "choose app dialog" prompt to open.
Unfortunately this DOES NOT work, in a non-stock browser it would appear if the first redirect doesn't trigger the intent/"choose app dialog" further redirects won't either. Massively gutting.
Attempted Solution B
(Using a custom scheme)
Having exhausted the server-side idea I thought I'd investigate using a custom URI scheme to trigger the "app choice dialog".
AndroidManifest.xml:
<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>
redirect.htm
<html><body><script>
window.location.href = "myapp.com://sharedpage";
</script></body></html>
This does actually work, the "choose app dialog" appears via the DB l.php URL even when using a non-stock browser. However it isn't really a feasible solution as it stands because "non MyApp users" are left with a "Webpage not available" page when redirected to the myapp.com://sharedpage URL. ]
Does anyone else have any other bright ideas or suggestions?
I made some further developments in my search and found that performing a "fake click" was the solution that worked in the majority of scenarios (but not all).
If the user wishes to share URL http://myapp.com/sharedpage, then I actually post the following URL to Facebook http://myapp.com/share.htm?redirectUrl=sharedpage
share.htm is just a javascript redirect page that immediately redirects to the appropriate page. It is clever though as on Android instead of just using window.location.replace
it uses a fake click of a button with the link which can force an intent to be triggered on some devices/some browsers. Code looks like below.
<!DOCTYPE HTML>
<html>
<body>
<script type="text/javascript">
var redirectUrlRelativeToThisPage = ""; // Read off the querystring here
var isAndroidDevice = (/android/gi).test(navigator.userAgent);
if (isAndroidDevice) {
// Android device. If the user isn't using a stock browser then window.location.redirect() doesn't always
// trigger an Intent (and prompt to open Native app) so instead attempt to fake click a hyperlink with the
// URL as this works more reliably (but not always).
var linkToFakeClick = document.createElement("a");
linkToFakeClick.href = redirectUrlRelativeToThisPage;
var fakeMouseClickEvent = document.createEvent("MouseEvents");
fakeMouseClickEvent.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
linkToFakeClick.dispatchEvent(fakeMouseClickEvent);
}
// If we got here either we're not on an Android device or the fake click didn't work so just redirect normally
window.location.replace(redirectUrlRelativeToThisPage);
</script>
</body>
</html>
In addition to the example code above and if it suited your scenario, you could also incorporate (in the event the fake click didn't work) two different "I do/don't have the app installed" buttons which link to the custom scheme URL (to force an intent) and the usual URL.
A very dirty workaround would be to put an intent filter on http://m.facebook.com/l.php:
<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="http"
android:host="m.facebook.com"
android:path="/l.php" />
</intent-filter>
Then parse the query string and relay the actual URL through another intent if it was not meant for your app.
Wouldn't recommend it though, since it might look a bit odd, seeing your app as a choice for a link not at all related to your app. Also, it will cause users to be prompted to select an app twice if they've chosen your app the first time. The only time this would work nicely (in the case where the link is not meant for your app) is if phone has your app set as default for all http://m.facebook.com/l.php requests. Still you would be messing with the inner workings of facebook.
Hopefully android browsers will work more with implicit intents in the future, here is a start: https://code.google.com/p/chromium/issues/detail?id=235060
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With