Frustration over Ionic Deeplinking

Hello everyone,

I write this post in sheer frustration with Ionic deeplinks, deeplinks plugins and configurations.
This is going to be a long(-ish) rant and a cry for help, but I believe this will be useful to everyone in the future if solved, as confusion around this subject is tremendous.

Yeah, sorry to the Ionic devs but your docs also don’t help there and if something, only aggravate the confusion.

Let’s try to make what I want to achieve clear and go from there.

So, I have an application that runs on the browser and also as a mobile application, being that the “primary” usage would be the app.

To run on the browser, I use the Hash Location Strategy (which is the default setting, even on ionic serve) as well as the Ionic 2 API Deeplinker to allow navigation directly to certain pages, which happens on https://app.mysite.com/#/login/:paramName style links (notice the hash).
This works flawlessly.

Now, when on a mobile phone, I want to be able to have my app those same links, e.g., https://app.mysite.com or https://app.mysite.com/#/login/:paramName links rather than going to the browser.
To do that, I use the Ionic Native Deeplinks Plugin, which, as a bonus, also allows me to open myscheme://myapp style links (which I don’t really plan to use, but it’s there).
But this is where the frustration starts.

The app does respond to http://app.mysite.com links without a issue, however, links with a hash (and then the path and parameters) ALWAYS fail to match.

I WANT and NEED to have this working. I’ve tried a bunch of different configurations but nothing seems to work.

I’ve read posts like this one (a search gets you more results) and opened 1 or 2 threads about it.
Also on the Native Plugin Github issues, like this one, this one or this other one.
It goes without saying that I’ve read the Android (1, 2) and iOS docs on Universal App Links. I’ve read the blog posts about it. Still nothing

Now, as for my configurations:
The Ionic API Deeplink in app.module.ts:

export const deepLinkConfig: DeepLinkConfig = {
	links: [
		{ component: Login, name: 'Login', segment: 'login/:name', defaultHistory: [LoginSocialNetworks] },
		{ component: LoginSocialNetworks, name: 'LoginSocialNetworks', segment: 'login-sn/:name' },
		{ component: ConfirmEmail, name: 'ConfirmEmail', segment: 'confirmation/:hash' },
		{ component: ResetPassword, name: 'ResetPassword', segment: 'reset-password/:hash/:pwdToken' }
	]
};

And my Native Deeplinker configuration in app.component.ts

    this.platform.ready().then(() => {
                (...)
		let routes = {
			'/login/:name': Login,
			'/login-sn/:name': LoginSocialNetworks,
			'/confirmation/:hash': ConfirmEmail,
			'/reset-password/:hash/:pwdToken': ResetPassword,
			'/mission/:id': MissionExpanded,
			'/brand/:id': BrandDetails
		}

		Deeplinks.route(routes).subscribe(
			match => {
				this.nav.push(match.$route, match.$args, { animate: false, animation: "none" });
			}, (nomatch) => {
				// nomatch.$link - the full link data
					console.error('Got a deeplink that didn\'t match', JSON.stringify(nomatch));
			}, () => {
				// nomatch.$link - the full link data
				console.error('Got a deeplink completed');
			});
       (...)
}

My config.xml goes like this:

  <plugin name="ionic-plugin-deeplinks" spec="~1.0.8">
    <variable name="URL_SCHEME" value="myscheme"/>
    <variable name="DEEPLINK_SCHEME" value="https"/>
    <variable name="DEEPLINK_HOST" value="devapp.mysite.com"/>
    <variable name="DEEPLINK_2_SCHEME" value="https"/>
    <variable name="DEEPLINK_2_HOST" value="app.mysite.com"/>
    <variable name="DEEPLINK_3_SCHEME" value="https"/>
    <variable name="DEEPLINK_3_HOST" value="stgapp.mysite.com"/>
  </plugin>

Yes, I’ve noticed I’m not including an ANDROID_PATH_PREFIX. I’m pretty sure I don’t need it but if you can convince me otherwise, I will.

Another thing that p***** me off is that, not matter what I do, my AndroidManifest.xml always ends up with stupid stuff that I didn’t ask to get in there related to the plugins, namely, adding 5 hosts and the ANDROID_PATH_PREFIX which I explicitly told it to remove, and if I edit it manually, the next build is going to add even more junk to the file (notice the “repeated” 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="myscheme" />
            </intent-filter>
            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:host="devapp.mysite.com" android:scheme="https" />
                <data android:host="app.mysite.com" android:scheme="https" />
                <data android:host="stgapp.mysite.com" android:scheme="https" />
            </intent-filter>
            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:host="devapp.mysite.com" android:pathPrefix="$ANDROID_PATH_PREFIX" android:scheme="https" />
                <data android:host="app.mysite.com" android:pathPrefix="$ANDROID_2_PATH_PREFIX" android:scheme="https" />
                <data android:host="stgapp.mysite.com" android:pathPrefix="$ANDROID_3_PATH_PREFIX" android:scheme="https" />
                <data android:host="$DEEPLINK_4_HOST" android:pathPrefix="$ANDROID_4_PATH_PREFIX" android:scheme="$DEEPLINK_4_SCHEME" />
                <data android:host="$DEEPLINK_5_HOST" android:pathPrefix="$ANDROID_5_PATH_PREFIX" android:scheme="$DEEPLINK_5_SCHEME" />
            </intent-filter>

So, what gives? How the hell are we supposed to handle this sort of behaviour? Wasn’t it all supposed to work without conflicts?
I need some help here folks.

Sorry for the long post.

EDIT:

So, I eventually went ahead and debugged the deeplinks plugin code and found out that when we are passing a hash in the url, the first character on the match path will be removed. This provided me with a solution. When I went over to github to file an issue I eventually found this post with an exact description of the issue and the same solution I came to found. Since github doesn’t look for the # symbol this never came up in the search results.

For anyone troubled by the same issue the solution is to remove the first forward slash from the deeplinks routes, like this:

let routes = {
	'login/:name': Login,
	'login-sn/:name': LoginSocialNetworks,
	'confirmation/:hash': ConfirmEmail,
	'reset-password/:hash/:pwdToken': ResetPassword,
	'mission/:id': MissionExpanded,
	'brand/:id': BrandDetails
}

This magically makes it work. Doesn’t solve other problems though (like the repeated intent-filter or the placeholders or the number of hosts/schemes) but at least it works.

However, I suspect (because I haven’t tested and won’t test) this will break mycheme://app links, unless we add the forward slashed paths again, possibly “duplicating” those entries.

Best Regards,
Celso Santos

I just don’t think Deeplink is ready for prime time. If you do a search on this forum or on GitHub, there are a lot of weird issues. Hopefully someone will come along and prove me wrong, but I’ve seen a lot of frustration and few solutions. It seems to me that we’re still a couple steps away from Ionic being a desktop framework, and the issues with the Deeplinker are one reason I say that.

5 Likes

Hi @AaronSterling I eventually came up with a solution (which apparently someone else had already found) which works, at least for me.

what’s the solution?

@appgod

See the EDIT section on the original post. If you still have any problems, feel free to get back :slight_smile:

1 Like

do i need to buy a domain to use deep-linking ?
because when i click on the link, the app will open on browser instead of app itself.

That is actually a very good question, but I believe you might away with just using IP address, as long as everything is properly configured a the json files are served from within the expected address, namely:

http://PublicIP/.well-know/<android_or_apple_file>

Hi thanks for the reply, however it still cannot work, below is my code, i am using ionic 3.
config.xml file
<plugin name="ionic-plugin-deeplinks" spec="^1.0.15"> <variable name="URL_SCHEME" value="myapp" /> <variable name="DEEPLINK_SCHEME" value="https" /> <variable name="DEEPLINK_HOST" value="example.com" /> <variable name="ANDROID_PATH_PREFIX" value="/" /> <variable name="ANDROID_2_PATH_PREFIX" value="/" /> <variable name="ANDROID_3_PATH_PREFIX" value="/" /> <variable name="ANDROID_4_PATH_PREFIX" value="/" /> <variable name="ANDROID_5_PATH_PREFIX" value="/" /> <variable name="DEEPLINK_2_SCHEME" value=" " /> <variable name="DEEPLINK_2_HOST" value=" " /> <variable name="DEEPLINK_3_SCHEME" value=" " /> <variable name="DEEPLINK_3_HOST" value=" " /> <variable name="DEEPLINK_4_SCHEME" value=" " /> <variable name="DEEPLINK_4_HOST" value=" " /> <variable name="DEEPLINK_5_SCHEME" value=" " /> <variable name="DEEPLINK_5_HOST" value=" " /> </plugin>
and this is the function
deeplinking(){ this.deeplinks.routeWithNavController(this.nav, { '/h': HomePage, // '/p/4': NewroosterPage }).subscribe((match) => { // match.$route - the route we matched, which is the matched entry from the arguments to route() // match.$args - the args passed in the link // match.$link - the full link data console.log('Successfully matched route', match); }, (nomatch) => { // nomatch.$link - the full link data console.error('Got a deeplink that didn\'t match', nomatch); }); }
so when click on link https://example.com, it does not open my apps.

how should i fill the link according to this format http://PublicIP/.well-know/<android_or_apple_file>.
Please help me !!

Well, I don’t know how you are exposing your IP address “to the world”, but assuming a scenario where you are hosting your API/Server under a publicly accessible IP address, I see one issue with your configuration:

<plugin name="ionic-plugin-deeplinks" spec="^1.0.15">
<variable name="URL_SCHEME" value="myapp" />
<variable name="DEEPLINK_SCHEME" value="https" /> ==> I you use http, update this. if ssl, leave it 
<variable name="DEEPLINK_HOST" value="example.com" /> ==> Should be your public IP address
<variable name="ANDROID_PATH_PREFIX" value="/" />
<variable name="ANDROID_2_PATH_PREFIX" value="/" />
<variable name="ANDROID_3_PATH_PREFIX" value="/" />
<variable name="ANDROID_4_PATH_PREFIX" value="/" />
<variable name="ANDROID_5_PATH_PREFIX" value="/" />
<variable name="DEEPLINK_2_SCHEME" value=" " />
<variable name="DEEPLINK_2_HOST" value=" " />
<variable name="DEEPLINK_3_SCHEME" value=" " />
<variable name="DEEPLINK_3_HOST" value=" " />
<variable name="DEEPLINK_4_SCHEME" value=" " />
<variable name="DEEPLINK_4_HOST" value=" " />
<variable name="DEEPLINK_5_SCHEME" value=" " />
<variable name="DEEPLINK_5_HOST" value=" " />

The rest you can leave as is. Now, this is talking about using URLs to open you application directly. Please also note the following: Ionic usually adds a # when open on the browser (ionic serve for instance).
If you want to have the app open in reply to those kinds of URLs, you are gonna have to drop the forward-slash on the deeplink paths, namely, /h becomes h and /p/4 becomes p/4.

(Actually, disregard this statement, that function does deal with deeplinks)
Then, I believe that the deeplink function you are using does NOT deal with Universal App Links (also called deeplinks) but I’m not sure of that because you don’t list which import you are using to refer to deeplinks.
(Go check the docs on DeepLinkConfig [ionic-angular package] and Deeplinks [ionic-native]). Configuration is similar but they are for different purposes.

Finally, I’ve come to notice of when my implementation that routeWithNavController() doesn’t really work. Why? I don’t know but I’ve had much better results using route(routes).subscribe() where routes is a JSON object:

	let routes = {
			'login': Login,
			'login/:name': Login,
			'invite/:type/:referral': Login,
			'login-sn': LoginSocialNetworks,
			'reset-password/:hash/:pwdToken': ResetPassword,
			'brand/:id': BrandDetails
		}

A post was split to a new topic: Need help with deeplinks

@celsosantos can we check from browser inside mobile or emulator
Like I write myapp://home and it should open my app which is in my mobile or emulator.
correct me If I am wrong.