I use deeplinking with branch.io in my app. App generates url and open it with custom scheme. It goes ok on native android brawser, firefox and opera-mini, but it fails on chrome-android with ERR_UNKNOWN_URL_SCHEME
code below:
manifest
<activity
android:launchMode="singleTask"
android:name=".ui.activity.ShareActivity"
android:screenOrientation="portrait">
<intent-filter>
<data android:scheme="myapp" android:host="open" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Code that generates url (doc: https://dev.branch.io/getting-started/creating-links-in-apps/guide/android/):
public static void generateShortUrl(#NonNull Context aContext,
#Nullable String aMediaId,
#Nullable String aCollectionId,
#NonNull CanonicalIdentifier aCanonicalIdentifier,
#NonNull String aDesktopUrl,
#NonNull Branch.BranchLinkCreateListener aListener){
BranchUniversalObject branchUniversalObject = new BranchUniversalObject()
.setCanonicalIdentifier(String.valueOf(aCanonicalIdentifier.ordinal() + 1))
.setContentIndexingMode(BranchUniversalObject.CONTENT_INDEX_MODE.PUBLIC)
.addContentMetadata(SHARE_MEDIA_ID, aMediaId);
if(BuildConfig.DEBUG){
Log.e("BranchConfigTest","share date:"+branchUniversalObject.convertToJson().toString());
}
if(!TextUtils.isEmpty(aCollectionId))
branchUniversalObject.addContentMetadata(SHARE_COLLECTION_ID,aCollectionId);
if(!TextUtils.isEmpty(aMediaId))
branchUniversalObject.addContentMetadata(SHARE_MEDIA_ID,aMediaId);
LinkProperties linkProperties = new LinkProperties()
.setFeature("sharing")
.addControlParameter("$desktop_url", aDesktopUrl);
branchUniversalObject.generateShortUrl(aContext,linkProperties,aListener);
}
Alex with Branch here: unfortunately this is a known issue with Chrome. Basically, in some release of Chrome 40, it was decided that typed and pasted URLs should prevent automated redirects like the one Branch uses to open the Play Store or launch your app. We worked on a solution with the Chromium team last summer, but it came to our attention a few weeks ago that the issue was only fixed for typed-in URLs, and not for URLs that users paste directly into Chrome's address bar.
The good news is that in the wild, this is extremely, extremely rare. It is usually only triggered by developers in the testing stages of a Branch integration — the vast majority of your users will only click links (rather than pasting URLs) and therefore will never encounter this. Obviously this is still a less than ideal solution, so if you'd like, feel free to file a radar with Chromium. We can get behind it and ask our team to provide examples as well.
Related
I am working on adding an OAuth flow to a Trello integration within my app. The idea is using deep linking to consume the response within the app itself (there is no server between the app and the database - I am using room).
I have everything working up to this point except the callback redirect portion, and it works on my real device, rather than the emulator.
This is the code that begins the OAuth flow.
val connection = object:CustomTabsServiceConnection() {
override fun onCustomTabsServiceConnected(name: ComponentName, client: CustomTabsClient) {
val builder = CustomTabsIntent.Builder()
val customTabsIntent = builder.build()
client.warmup(0)
var authUrl = "$TOKEN_URL?key=$API_KEY&scope=read&callback_method=fragment&return_url=${AuthenticationManager.HTTPS_REDIRECT_URL}&expiration=never&name=$NAME&integration=${integration.id}"
customTabsIntent.launchUrl(context, Uri.parse(authUrl))
}
override fun onServiceDisconnected(name: ComponentName?) {
}
}
bindCustomTabsService(context, "com.android.chrome", connection);
Manifest
<activity
android:name="com.myapp.MainActivity"
android:screenOrientation="sensor"
android:windowSoftInputMode="adjustPan"
android:launchMode="singleTop"
android:configChanges="uiMode">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="pomodoro" android:host="oauth.myapp.com"/>
<data android:scheme="https" android:host="myapp.com"/>
</intent-filter>
</activity>
At this point it is redirected to my webpage, which I verified on my real device redirects to my app (so it can consume the intent and get the necessary token). I am wondering if when I selected Always use for the chrome browser (when initially opening a webpage in the emulator), that this basically overrides my deep link? Is that possible? Also using a different scheme isn't possible, as Trello forces uses to use https/http as the trusted redirect/callback urls?
This is related to my misunderstanding of deeplinks vs AppLinks. I want to treat this more as an AppLink vs a deeplink, meaning the verification has already happened that this URL belongs to my app (via a file on my domain). For this verification to happen I need the verification file at the appropriate url, if it is not there - the verification cannot happen. Which happens for each host/scheme, and must verify all match.
The solution was to remove the scheme/host that isn't associated with the app/domain, to allow AutoVerify.
"Only if the system finds a matching Digital Asset Links file for all hosts in the manifest does it then establish your app as the default handler for the specified URL patterns." https://developer.android.com/training/app-links/verify-site-associations
After updating my manifest to the below it worked as expected, and redirected the OAuth flow as expected.
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="https" android:host="myapp.com"/>
</intent-filter>
The deeplinking works fine from WhatsApp, Slack and even Facebook Messenger but doesn't work from the Facebook App itself.
In the branch.io Link Settings I did enable:
✓ Always try to open app
✓ Enable App Links + SHA256 Cert Fingerprints
Changed to custom Link Domain: sharing.kptncook.com
successfully authenticated the "Facebook Install Ads"
Facebook developer settings:
Packagename, class name and hashes are correct(Facebook login also works fine)
✓ SSO is activated
✓ Deep-Link is activated
Android App Versions:
Facebook Messenger: 126.0.0.9.84
Facebook: 133.0.0.19.83
Example link: sharing.kptncook.com/pIbQ/FKktug85TE
Activity part of Manifest:
<activity android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<data android:scheme="kptncook" android:host="open" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="sharing.kptncook.com" />
<data android:scheme="http" android:host="sharing.kptncook.com" />
</intent-filter>
</activity>
<receiver android:name="io.branch.referral.InstallListener" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
Activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void onStart() {
super.onStart();
Branch branch = Branch.getInstance();
branch.initSession(new Branch.BranchReferralInitListener(){
#Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
}
}, this.getIntent().getData(), this);
}
#Override
public void onNewIntent(Intent intent) {
this.setIntent(intent);
}
}
Additional info: In the emulator some links won't open and some does. If I send a link that doesn't work from the emulator to a real device it works on the real device.
What am I doing wrong?
Update:
New shared links work now on the Real device in both Facebook Messenger and Main App. But if I open the exact same link in the messenger on an emulator it redirects to "r31v.test-app.link..." and doesn't show anything except a toast "Can't load page". It's so frustrating. Any ideas how to debug it?
Alex from Branch.io here:
Facebook deep linking is one of the hardest things to debug — they intentionally don't want users to leave their app, wherever possible.
A few notes for debugging:
The domain r31v.test-app.link is your original link domain. You customized this to sharing.kptncook.com, but there are times when Branch needs to use both to handle certain edge cases. You need to add the following lines to your Manifest:
<data android:scheme="https" android:host="r31v.test-app.link" />
<data android:scheme="https" android:host="r31v-alternate.test-app.link" />
Other than the above, your in-app configuration implementation looks fine.
It's possible something is funky with your Dashboard configuration. Branch has separate Test and Live environments, and you're currently using the Test one. It's important to make sure you haven't split your implementation between values from both sides.
Deep linking behavior frequently doesn't work correctly in the emulators. It's always best to test with real devices, because results from emulators are usually not reliable.
Facebook sometimes caches the App Links tags, which means you may get unpredictable results when opening a URL that has just been shared, or when re-sharing a URL that has been posted before with different data.
Feel free to reach out to our Integrations team any time with questions!
Is it possible to make a link such as:
click me!
cause my Anton app to start up?
I know that this works for the Android Market app with the market protocol, but can something similar be done with other apps?
Here is an example of a link that will start up the Android Market:
click me!
Update:
The answer I accepted provided by eldarerathis works great, but I just want to mention that I had some trouble with the order of the subelements of the <intent-filter> tag. I suggest you simply make another <intent-filter> with the new subelements in that tag to avoid the problems I had. For instance my AndroidManifest.xml looks like this:
<activity android:name=".AntonWorld"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data android:scheme="anton" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Please DO NOT use your own custom scheme like that!!! URI schemes are a network global namespace. Do you own the "anton:" scheme world-wide? No? Then DON'T use it.
One option is to have a web site, and have an intent-filter for a particular URI on that web site. For example, this is what Market does to intercept URIs on its web site:
<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="market.android.com"
android:path="/search" />
</intent-filter>
Alternatively, there is the "intent:" scheme. This allows you to describe nearly any Intent as a URI, which the browser will try to launch when clicked. To build such a scheme, the best way is to just write the code to construct the Intent you want launched, and then print the result of intent.toUri(Intent.URI_INTENT_SCHEME).
You can use an action with this intent for to find any activity supporting that action. The browser will automatically add the BROWSABLE category to the intent before launching it, for security reasons; it also will strip any explicit component you have supplied for the same reason.
The best way to use this, if you want to ensure it launches only your app, is with your own scoped action and using Intent.setPackage() to say the Intent will only match your app package.
Trade-offs between the two:
http URIs require you have a domain you own. The user will always get the option to show the URI in the browser. It has very nice fall-back properties where if your app is not installed, they will simply land on your web site.
intent URIs require that your app already be installed and only on Android phones. The allow nearly any intent (but always have the BROWSABLE category included and not supporting explicit components). They allow you to direct the launch to only your app without the user having the option of instead going to the browser or any other app.
I think you'll want to look at the <intent-filter> element of your Manifest file. Specifically, take a look at the documentation for the <data> sub-element.
Basically, what you'll need to do is define your own scheme. Something along the lines of:
<intent-filter>
<data android:scheme="anton" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <--Not positive if this one is needed
...
</intent-filter>
Then you should be able to launch your app with links that begin with the anton: URI scheme.
I have a jQuery plugin to launch native apps from web links: https://github.com/eusonlito/jquery.applink
You can use it easily:
<script>
$('a[data-applink]').applink();
</script>
My Facebook Profile
I also faced this issue and see many absurd pages. I've learned that to make your app browsable, change the order of the XML elements, this this:
<activity
android:name="com.example.MianActivityName"
android:label="#string/title_activity_launcher">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data android:scheme="http" />
<!-- or you can use deep linking like -->
<data android:scheme="http" android:host="xyz.abc.com"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
This worked for me and might help you.
Here's my recipe:
Create a static HTML that redirects to your requested app URL, put that page on the web.
That way, the links you share are 'real' links as far as Android is concerned ( they will be 'clickable').
You 'share' a regular HTTP link, www.your.server.com/foo/bar.html
This URL returns a simple 8 line HTML that redirects to your app's URI (window.location = "blah://kuku") (note that 'blah' doesn't have to be HTTP or HTTPS any more).
Once you get this up and running, you can augment the HTML with all the fancy capabilities as suggested above.
This works with the built-in browser, Opera, and Firefox (haven't tested any other browser). Firefox asks 'This link needs to be opened with an application' (ok, cancel). Other browsers apparently don't worry about security that much, they just open the app, no questions asked.
This method doesn't call the disambiguation dialog asking you to open either your app or a browser.
If you register the following in your Manifest
<manifest package="com.myApp" .. >
<application ...>
<activity ...>
<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:host="gallery"
android:scheme="myApp" />
</intent-filter>
</activity>
..
and click this url from an email on your phone for example
<a href="intent://gallery?directLink=true#Intent;scheme=myApp;package=com.myApp;end">
Click me
</a>
then android will try to find an app with the package com.myApp that responds to your gallery intent and has a myApp scheme. In case it can't, it will take you to the store, looking for com.myApp, which should be your app.
Once you have the intent and custom url scheme for your app set up, this javascript code at the top of a receiving page has worked for me on both iOS and Android:
<script type="text/javascript">
// if iPod / iPhone, display install app prompt
if (navigator.userAgent.match(/(iPhone|iPod|iPad);?/i) ||
navigator.userAgent.match(/android/i)) {
var store_loc = "itms://itunes.com/apps/raditaz";
var href = "/iphone/";
var is_android = false;
if (navigator.userAgent.match(/android/i)) {
store_loc = "https://play.google.com/store/apps/details?id=com.raditaz";
href = "/android/";
is_android = true;
}
if (location.hash) {
var app_loc = "raditaz://" + location.hash.substring(2);
if (is_android) {
var w = null;
try {
w = window.open(app_loc, '_blank');
} catch (e) {
// no exception
}
if (w) { window.close(); }
else { window.location = store_loc; }
} else {
var loadDateTime = new Date();
window.setTimeout(function() {
var timeOutDateTime = new Date();
if (timeOutDateTime - loadDateTime < 5000) {
window.location = store_loc;
} else { window.close(); }
},
25);
window.location = app_loc;
}
} else {
location.href = href;
}
}
</script>
This has only been tested on the Android browser. I am not sure about Firefox or Opera. The key is even though the Android browser will not throw a nice exception for you on window.open(custom_url, '_blank'), it will fail and return null which you can test later.
Update: using store_loc = "https://play.google.com/store/apps/details?id=com.raditaz"; to link to Google Play on Android.
You may want to consider a library to handle the deep link to your app:
https://github.com/airbnb/DeepLinkDispatch
You can add the intent filter on an annotated Activity like people suggested above. It will handle the routing and parsing of parameters for all of your deep links. For example, your MainActivity might have something like this:
#DeepLink("somePath/{useful_info_for_anton_app}")
public class MainActivity extends Activity {
...
}
It can also handle query parameters as well.
Try my simple trick:
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if(url.startsWith("classRegister:")) {
Intent MnRegister = new Intent(getApplicationContext(), register.class); startActivity(MnRegister);
}
view.loadUrl(url);
return true;
}
and my html link:
Go to register.java
or you can make < a href="classRegister:true" > <- "true" value for class filename
however this script work for mailto link :)
if (url.startsWith("mailto:")) {
String[] blah_email = url.split(":");
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("text/plain");
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{blah_email[1]});
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, what_ever_you_want_the_subject_to_be)");
Log.v("NOTICE", "Sending Email to: " + blah_email[1] + " with subject: " + what_ever_you_want_the_subject_to_be);
startActivity(emailIntent);
}
Just want to open the app through browser? You can achieve it using below code:
HTML:
Click here
Manifest:
<intent-filter>
<action android:name="packageName" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
This intent filter should be in Launcher Activity.
If you want to pass the data on click of browser link, just refer this link.
We are trying to implement Google's App Indexing feature. We've added the deep links to our website with the rel-alternate tag in the following format:
android-app://id.of.the.app/scheme/?screen=Product&product=123456
Now we get content mismatch crawling errors. If I use the QR code for testing from here everything works fine. But if I open a crawling error, click on "Open App Page" and use the adb command for testing I can see that everything starting from the ampersand doesn't get passed to the app and therefore my product data cannot be loaded. I suspect that's how the crawler checks the content of the app and that's why we get Content Mismatch Errors.
Also if I use the "Fetch as Google" from the Search Console it looks like everything from the ampersand gets cut off.
I checked on eBay as it is working with their app and that's the link they are using:
android-app://com.ebay.mobile/ebay/link/?nav=item.view&id=221559043026&referrer=http%3A%2F%2Frover.ebay.com%2Froverns%2F1%2F711-13271-9788-0%3Fmpcl%3Dhttp%253A%252F%252Fwww.ebay.com%252Fitm%252FRoxy-Fairness-Backpack-Womens-Red-RPM6-%252F221559043026%253Fpt%253DLH_DefaultDomain_0
They have encoded the ampersand with & but if I do that and test it with the "Fetch as Google" function it doesn't work either.
These users seem to have the same issue, but they didn't share a solution (if they found one):
https://productforums.google.com/forum/#!msg/webmasters/5r7KdetlECY/enYknTVkYU4J
https://productforums.google.com/forum/#!topic/webmasters/lswyXKlS-Ik
I'm thankful for any ideas.
Update 1
That's how I'm interpreting the deep link inside the Android app:
Uri data = getIntent().getData();
String scheme = data.getScheme();
if (scheme.equals("scheme")) {
String screen = data.getQueryParameter("screen");
if (screen.equals("Product")) {
String product = data.getQueryParameter("product");
// Open Product and give it product number as intent data
}
}
Update 2
Here's the relevant part of our Manifest.xml:
<activity
android:name="id.of.the.app.StartActivity"
android:configChanges="orientation|screenSize"
android:label="#string/app_title"
android:windowSoftInputMode="adjustPan|stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data android:scheme="scheme" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
Update 3
I'm still trying to understand if it's is possible to avoid a change to the manifest and resubmit the app. With the AndroidManifest you have published, have you tried to change just the rel-alternate tag to include a host (event if it's not included inside the manifest)? For example have you tried with android-app://id.of.the.app/scheme/fakehost/?screen=Product&product=123456 where fakehost is a string? I guess that the syntax of the tag must be android-app://{package_name}/{scheme}/{host_path}so it's neccessary to have an host in the web site (but probably not on the app).
Update 2
After you published the Manifest, I guess you're missing the mandatory 'host' in the data tag of your Intent-Filter.
Get this as reference:
<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" android:host="link"/>
<data android:scheme="myapp" android:host="link/"/>
</intent-filter>
and the meta in html should be (android-app://package-name/scheme/host)
<html>
<head>
<link rel="alternate"
href="android-app://it.test.testdeeplink/myapp/link/?p1=1&p2=2" />
...
</head>
You probably need to update your app, since your Manifest will have to be fixed.
First, thanks for all clarifications. I guess there is some confusion about deep link (the feature you're implementing) and Chrome Intent (the link that you provided as comment). So, I decided to implement a small project that you can download by my dropbox folder. The project is very simple and has a single activity that prints a line for every parameter received by Intent data (of course if you launch the app by the app launcher you won't see anything). The Activity supports two intent-filter schemas (my-android-app and http), and at the end of MainActivity.java you can find (as comment)
A line to test deep linking against adb and the first schema
A line to test deep linking against adb and the second schema
A simple html page to test the deep link using a browser - the last two href are Intent properly managed by Chrome.
Since I don't have access to your code, and I cannot see if there is any issue, I guess this is the best way to help you and to get my answer accepted :)
App indexing with query params in the Uri works fine for me. Please check if you followed all steps correctly:
Declare the scheme for the id.of.the.app.StartActivity in the AndroidManifest.xml
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<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="my_custom_scheme"/>
</intent-filter>
Parse deeplink
Let's assume we have following deeplink my_custom_scheme://test_authority/product_screen/?product=123456&test_param=0000&utm_source=google&utm_medium=organic&utm_campaign=appindexing
public void parseDeeplikUrl(Uri uri) {
if (uri == null) {
// fallback: open home screen
}
String autority = uri.getAuthority();
String path = uri.getPath();
String query = uri.getQuery();
// authority = "test_authority"
// path = "products_screen"
// query = "product=123456&test_param=0000&utm_source=google&utm_medium=organic&utm_campaign=appindexing"
}
Test app indexing from command line:
adb shell 'am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "my_custom_scheme://test_authority/product_screen/?product=123456&test_param=0000&utm_source=google&utm_medium=organic&utm_campaign=appindexing" -e android.intent.extra.REFERRER_NAME android-app://com.google.appcrawler/https/www.google.com id.of.the.app'
Using this adb command we simulate GoogleBot call.
Go to "Fetch as Google" in Search console and check if GoogleBot works fine too and renders correct application screen.
android-app://id.of.the.app/my_custom_scheme/test_authority/product_screen/?product=123456&test_param=0000&utm_source=google&utm_medium=organic&utm_campaign=appindexing
P.S.: Sometimes GoogleBot isn't rendering screens correctly. I got few empty screens with correct the deeplinks. In that case try to execute the same deeplinks again. It worked for me.
Is it possible to make a link such as:
click me!
cause my Anton app to start up?
I know that this works for the Android Market app with the market protocol, but can something similar be done with other apps?
Here is an example of a link that will start up the Android Market:
click me!
Update:
The answer I accepted provided by eldarerathis works great, but I just want to mention that I had some trouble with the order of the subelements of the <intent-filter> tag. I suggest you simply make another <intent-filter> with the new subelements in that tag to avoid the problems I had. For instance my AndroidManifest.xml looks like this:
<activity android:name=".AntonWorld"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data android:scheme="anton" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Please DO NOT use your own custom scheme like that!!! URI schemes are a network global namespace. Do you own the "anton:" scheme world-wide? No? Then DON'T use it.
One option is to have a web site, and have an intent-filter for a particular URI on that web site. For example, this is what Market does to intercept URIs on its web site:
<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="market.android.com"
android:path="/search" />
</intent-filter>
Alternatively, there is the "intent:" scheme. This allows you to describe nearly any Intent as a URI, which the browser will try to launch when clicked. To build such a scheme, the best way is to just write the code to construct the Intent you want launched, and then print the result of intent.toUri(Intent.URI_INTENT_SCHEME).
You can use an action with this intent for to find any activity supporting that action. The browser will automatically add the BROWSABLE category to the intent before launching it, for security reasons; it also will strip any explicit component you have supplied for the same reason.
The best way to use this, if you want to ensure it launches only your app, is with your own scoped action and using Intent.setPackage() to say the Intent will only match your app package.
Trade-offs between the two:
http URIs require you have a domain you own. The user will always get the option to show the URI in the browser. It has very nice fall-back properties where if your app is not installed, they will simply land on your web site.
intent URIs require that your app already be installed and only on Android phones. The allow nearly any intent (but always have the BROWSABLE category included and not supporting explicit components). They allow you to direct the launch to only your app without the user having the option of instead going to the browser or any other app.
I think you'll want to look at the <intent-filter> element of your Manifest file. Specifically, take a look at the documentation for the <data> sub-element.
Basically, what you'll need to do is define your own scheme. Something along the lines of:
<intent-filter>
<data android:scheme="anton" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <--Not positive if this one is needed
...
</intent-filter>
Then you should be able to launch your app with links that begin with the anton: URI scheme.
I have a jQuery plugin to launch native apps from web links: https://github.com/eusonlito/jquery.applink
You can use it easily:
<script>
$('a[data-applink]').applink();
</script>
My Facebook Profile
I also faced this issue and see many absurd pages. I've learned that to make your app browsable, change the order of the XML elements, this this:
<activity
android:name="com.example.MianActivityName"
android:label="#string/title_activity_launcher">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data android:scheme="http" />
<!-- or you can use deep linking like -->
<data android:scheme="http" android:host="xyz.abc.com"/>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
This worked for me and might help you.
Here's my recipe:
Create a static HTML that redirects to your requested app URL, put that page on the web.
That way, the links you share are 'real' links as far as Android is concerned ( they will be 'clickable').
You 'share' a regular HTTP link, www.your.server.com/foo/bar.html
This URL returns a simple 8 line HTML that redirects to your app's URI (window.location = "blah://kuku") (note that 'blah' doesn't have to be HTTP or HTTPS any more).
Once you get this up and running, you can augment the HTML with all the fancy capabilities as suggested above.
This works with the built-in browser, Opera, and Firefox (haven't tested any other browser). Firefox asks 'This link needs to be opened with an application' (ok, cancel). Other browsers apparently don't worry about security that much, they just open the app, no questions asked.
This method doesn't call the disambiguation dialog asking you to open either your app or a browser.
If you register the following in your Manifest
<manifest package="com.myApp" .. >
<application ...>
<activity ...>
<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:host="gallery"
android:scheme="myApp" />
</intent-filter>
</activity>
..
and click this url from an email on your phone for example
<a href="intent://gallery?directLink=true#Intent;scheme=myApp;package=com.myApp;end">
Click me
</a>
then android will try to find an app with the package com.myApp that responds to your gallery intent and has a myApp scheme. In case it can't, it will take you to the store, looking for com.myApp, which should be your app.
Once you have the intent and custom url scheme for your app set up, this javascript code at the top of a receiving page has worked for me on both iOS and Android:
<script type="text/javascript">
// if iPod / iPhone, display install app prompt
if (navigator.userAgent.match(/(iPhone|iPod|iPad);?/i) ||
navigator.userAgent.match(/android/i)) {
var store_loc = "itms://itunes.com/apps/raditaz";
var href = "/iphone/";
var is_android = false;
if (navigator.userAgent.match(/android/i)) {
store_loc = "https://play.google.com/store/apps/details?id=com.raditaz";
href = "/android/";
is_android = true;
}
if (location.hash) {
var app_loc = "raditaz://" + location.hash.substring(2);
if (is_android) {
var w = null;
try {
w = window.open(app_loc, '_blank');
} catch (e) {
// no exception
}
if (w) { window.close(); }
else { window.location = store_loc; }
} else {
var loadDateTime = new Date();
window.setTimeout(function() {
var timeOutDateTime = new Date();
if (timeOutDateTime - loadDateTime < 5000) {
window.location = store_loc;
} else { window.close(); }
},
25);
window.location = app_loc;
}
} else {
location.href = href;
}
}
</script>
This has only been tested on the Android browser. I am not sure about Firefox or Opera. The key is even though the Android browser will not throw a nice exception for you on window.open(custom_url, '_blank'), it will fail and return null which you can test later.
Update: using store_loc = "https://play.google.com/store/apps/details?id=com.raditaz"; to link to Google Play on Android.
You may want to consider a library to handle the deep link to your app:
https://github.com/airbnb/DeepLinkDispatch
You can add the intent filter on an annotated Activity like people suggested above. It will handle the routing and parsing of parameters for all of your deep links. For example, your MainActivity might have something like this:
#DeepLink("somePath/{useful_info_for_anton_app}")
public class MainActivity extends Activity {
...
}
It can also handle query parameters as well.
Try my simple trick:
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if(url.startsWith("classRegister:")) {
Intent MnRegister = new Intent(getApplicationContext(), register.class); startActivity(MnRegister);
}
view.loadUrl(url);
return true;
}
and my html link:
Go to register.java
or you can make < a href="classRegister:true" > <- "true" value for class filename
however this script work for mailto link :)
if (url.startsWith("mailto:")) {
String[] blah_email = url.split(":");
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("text/plain");
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{blah_email[1]});
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, what_ever_you_want_the_subject_to_be)");
Log.v("NOTICE", "Sending Email to: " + blah_email[1] + " with subject: " + what_ever_you_want_the_subject_to_be);
startActivity(emailIntent);
}
Just want to open the app through browser? You can achieve it using below code:
HTML:
Click here
Manifest:
<intent-filter>
<action android:name="packageName" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
This intent filter should be in Launcher Activity.
If you want to pass the data on click of browser link, just refer this link.