- Kotlin Android – Open URL separately in Browser Activity
- Open URL from Android Application in Default Browser
- Open URL from Android Application in Default Browser
- Example – Android Application to Open URL in Default Browser
- Conclusion
- Open Mobile Application From The Browser
- Table Of Contents
- Deep Linking Types
- Creating A Deep Link
- The Complete Example
- Summary
- How to Open an Android App from the Browser
- Alex Austin
- Overview of Changes
- Adding Support for URI Schemes to Your App
- Adding Javascript to Your Website to Open Your App
- Android Intents with Chrome
- # Syntax
- # Examples
- # Considerations
- # See also
- Universal links for Android and iOS
- Making them work (almost) every time
- Table of Contents
- What a universal link is, and why you need it
- How we implemented the deep links
- Branch.io
- AppsFlyer
- How deep links work, the very beginning
- How we added support for universal links to an iOS app
- How we minified universal links
- How deferred deep links work
- How nothing works in SafariViewController
- What the system looks like with web preview
- How we encountered mysterious bugs and solved them
- How to version deep links
- How we tamed Facebook
- When we still use old-style links
- How to do universal links, tl;dr
Kotlin Android – Open URL separately in Browser Activity
Open URL from Android Application in Default Browser
In an Android Application, it may be necessary to open a URL separately in a browser. The task of opening a URL can be triggered by any action performed on Views using Action Listeners.
In this tutorial, we shall look into an application, where we click a button, and a URL is opened in a browser window.
From the following screenshot, when user clicks on the button, a new Browser Activity is displayed over this Android Application, with the URL specified for that page.
Open URL from Android Application in Default Browser
To open an URI in a browser window separately, use android.content.Intent.ACTION_VIEW . ACTION_VIEW is used to display data to the user using the most reasonable presentation. For example, when used on a mailto, ACTION_VIEW opens a mail compose window; and when used on tel: , ACTION_VIEW displays call dialer.
Following are the detailed steps to create ACTION_VIEW for opening a URL.
Step 1: Create an Intent for ACTION_VIEW.
Step 2: Set Uri as data for the intent.
Step 3: Start Activity with the intent.
Example – Android Application to Open URL in Default Browser
Create an Android Project and replace the following layout file, activity_main.xml, and MainActivity.kt file.
activity_main.xml
MainActivity.kt
Run this Android Application, and click on any of the buttons, to open the respective URL separately in default Browser activity.
Your browser doesn’t support HTML5 video.
Conclusion
In this Kotlin Android Tutorial, we learned how to open URL from Android Application in default browser.
Источник
Open Mobile Application From The Browser
Table Of Contents
Launching the mobile application of the specific page from the browser is called Mobile App Deep Linking.
It is very useful if you have both web and mobile applications and want to easily navigate between them.
You can launch an email campaign that contains a link that users can click to read more about your products in your mobile app.
There are many use cases, but the general purpose is to optimize user experience and increase conversion rates.
Deep Linking Types
There are two main types of Deep Links:
The link opens an application if it is installed, otherwise an error message will be displayed.
The link opens an application if it is installed, otherwise the user is redirected to Play or App Store (or another chosen location).
Besides these, you may have heard of Contextual Deep Linking.
Contextual Deep Links are usually default or deferred with some additional parameters added to collect more information about users.
Creating A Deep Link
Let’s create a Deferred Deep Link to our mobile app that will open it if it’s installed, otherwise redirect to the Store where the user can download it.
Important note: This solution may not work in all browsers or older Android/iOS versions. However, it should work fine with Chrome and Safari.
ANDROID
For Android, Google provides the Intent URL:
Be sure to replace APP_NAME and APP_PACKAGE with the values that belong to your mobile app, APP_HOST is an optional host value that may not be needed (but is required to open the instagram app in the next example).
Example code for Instagram:
IOS
On iOS, try opening the mobile app and set the timeout to a few seconds, which only runs when an app is not installed:
Be sure to replace APP_NAME and APPSTOREURL with the values that belong to your mobile application.
Example code for Instagram:
The Complete Example
To put all the code together, let’s create a simple React application:
npx create-react-app deep-linking
Install the react-device-detect library, which would help us detect the user’s operating system:
yarn add react-device-detect
Open the App component and replace it with the following code:
Important note: Do not try to test it on either iOS or Android by manually typing the url into the browser, as it will not work. Create a link somewhere that points to your React app and test by clicking on it.
Summary
Mobile App Deep Linking is a very complicated subject.
It is very hard to prepare a solution that works for every scenario.
Fortunately, you do not always have to take care of it yourself — there are a lot of paid services that would generate links for you and do all the redirect logic under the hood.
Источник
How to Open an Android App from the Browser
Alex Austin
January 8th, 2018
Opening an installed app from a browser is often referred to as “deep linking”, and with this guide you’ll learn how to deep link into your Android app for yourself. We’ll focus exclusively on how to trigger an app open from a website page, rather than from the click of a link inside other apps. For a more detailed look at all of the different deep linking standards required for complete Android coverage, please see our Android deep linking series: Part 1 , Part 2 , Part 3 , and Part 4 .
Android is, by far, one of the most fragmented platforms that developers have ever had to manage, due to Google’s decision to force device manufacturers to be responsible for porting the OS, which requires backwards compatibility and support of a multitude of devices. In this ecosystem, we, the app developers, are left to pick up the pieces. Deep linking on Android is unfortunately no different—over the years, we’ve seen a plethora of technical requirements that must be used depending on the circumstance and context of the user.
Note that Branch will implement all of this complexity for you, host the deep links, and even give you robust analytics behind clicks, app opens, and down funnel events. You can play around with Branch links for free by signing up here . We highly recommend using our tools instead of trying to rebuild them from scratch, since we give them all away for free.
Overview of Changes
There are two places where changes will need to be made in order to successfully open your Android app: your website and your Android app. You can find the details of each change in the corresponding sections below.
Adding Support for URI Schemes to Your App
A URI scheme can be any string without special characters, such as http , pinterest , fb or myapp . Once registered, if you append :// to the end (e.g. pinterest://) and click this link, the Pinterest app will open up. If the Pinterest app is not installed, you’ll see a ‘Page Not Found’ error.
It is simple to configure your app for a URI scheme. To start, you need to pick an Activity within your app that you’d like to open when the URI scheme is triggered, and register an intent filter for it. Add the following code within the tag within your manifest that corresponds to the Activity you want to open.
You can change your_uri_scheme to the URI scheme that you’d like. Ideally, you want this to be unique. If it overlaps with another app’s URI scheme, the user will see an Android chooser when clicking on the link. You see this often when you have multiple browsers installed, as they all register for the http URI.
Next, you’ll want to confirm that your app was opened from the URI scheme. To handle the deep link in the app, you simply need to grab the intent data string in the Activity that was opened via the click. Below is an example:
From here, you’ll need to do string parsing to read the values appended the URI scheme that will be very specific to your use case and implementation.
Adding Javascript to Your Website to Open Your App
Now that your Android app is ready to be triggered from a URI scheme, the next part is simple. You merely need to add some Javascript to your website that will auto trigger your app open. The function below, triggerAppOpen , will attempt to open your app’s URI scheme once you replace your_uri_scheme with the one you added in the manifest above.
You could call triggerAppOpen into window.onload if you wanted to do it on page load, or you could make it the onclick of a link somewhere on your site. Either works and the you’ll get the intended results.
Android is incredibly complicated, and there are edge cases everywhere. You’ll think everything is going well until you get that one user complaining that his links aren’t working on Facebook while running Android 4.4.4. That’s why you should use a tool like Branch—to save you this nightmare and ensure that your links work everywhere. Be sure to request a Branch demo if you’re interested in learning more.
Источник
Android Intents with Chrome
Published on Friday, February 28, 2014
A little known feature in Android lets you launch apps directly from a web page via an Android Intent. One scenario is launching an app when the user lands on a page, which you can achieve by embedding an iframe in the page with a custom URI-scheme set as the src , as follows: . This works in the Chrome for Android browser, version 18 and earlier. It also works in the Android browser, of course.
The functionality has changed slightly in Chrome for Android, versions 25 and later. It is no longer possible to launch an Android app by setting an iframe’s src attribute. For example, navigating an iframe to a URI with a custom scheme such as paulsawesomeapp:// will not work even if the user has the appropriate app installed. Instead, you should implement a user gesture to launch the app via a custom scheme, or use the «intent:» syntax described in this article.
# Syntax
The best practice is to construct an intent anchor and embed that into the page so the user can launch the app. This gives you a lot more flexibility in controlling how apps are launched, including the ability to pass extra information into the app via Intent Extras.
The basic syntax for an intent-based URI is as follows:
See the Android source for parsing details.
Also, you may choose to specify fallback URL by adding the following string extra:
When an intent could not be resolved, or an external application could not be launched, then the user will be redirected to the fallback URL if it was given.
Some example cases where Chrome does not launch an external application are as follows:
- The intent could not be resolved, i.e., no app can handle the intent.
- JavaScript timer tried to open an application without user gesture.
Note that S. is a way to define string extras. S.browser_fallback_url was chosen for backward compatibility, but the target app won’t see browser_fallback_url value as Chrome removes it.
# Examples
Here’s an intent that launches the Zxing barcode scanner app. It follows the syntax thus:
To launch the Zxing barcode scanner app, you encode your href on the anchor as follows:
See the Android Zxing Manifest, which defines the package and the host.
Also, if fallback URL is specified, the full URL will look like this:
Now the URL will get you to zxing.org if the app could not be found, or the link was triggered from JavaScript without user gesture (or for other cases where we don’t launch an external application.)
# Considerations
If the activity you invoke via an intent contains extras, you can include these as well.
Only activities that have the category filter, android.intent.category.BROWSABLE are able to be invoked using this method as it indicates that the application is safe to open from the Browser.
# See also
And Chrome doesn’t launch an external app for a given Intent URI in the following cases.
- When the Intent URI is redirected from a typed in URL.
- When the Intent URI is initiated without user gesture.
Last updated: Friday, February 28, 2014 • Improve article
Источник
Universal links for Android and iOS
Making them work (almost) every time
Mobile apps have given a huge amount of good things to the human race, but at the same time, they have broken the internet. Instead of easy-to-understand links to sites which can be copied and shared, now you have to tell people what app to use to access which content.
Theoretically this was fixed by both Google and Apple, several times. The marketing description says that if everything is set up properly, when your user taps a link, it’s opened exactly where it’s intended to open, be it a website or an app. You just need to set up your websites and apps in a few easy steps.
If you are a developer, you are probably guessing that making it just right would be somewhat tedious. In practice, you have no idea. There are dragons lurking around that are undocumented and yet pretty fire-breathing. At Badoo we’ve encountered, tagged and catalogued most of them and are prepared to share the knowledge with you.
I coordinated Badoo’s deep linking efforts on Android, iOS and web. This article is based on a talk I gave in Russian at Mobius conference. If you understand Russian, you can watch the video or read a similar article in Russian. I will mostly talk about iOS because that’s where you’re going to encounter most of the problems and weird shenanigans, but a few of our Android hacks are mentioned as well.
This article is very long. If you feel you just want to jump straight to action, just go directly to the tl;dr part at the end.
Table of Contents
What a universal link is, and why you need it
What are universal links in the first place? The story is quite straightforward.
You are using an application, let’s say Badoo. Say you see a beautiful person there. You immediately want to show their awesomeness to your friend. So you press a button and share a link:
You send your friend the link. It displays nicely in the message, your friend clicks on it and they open up the page with the same girl:
When the link opens content inside an application, this is traditionally referred to as deep linking, and the link as a deep link. However, this is an ideal scenario, assuming your friend has the app already installed and is using iOS.
If that’s not the case, we might want this same link to have other features as well, e. g.:
- Opening the app on other platforms with the same content (e. g. on android)
- Opening the app store if the app is not installed
- Showing the web version if we don’t want to force installation of the app or if the link is opened on an unsupported platform (e. g. on windows/mac)
If a link has all these features, or at least some of them, it is called a universal link. The thorny path of creating and fine-tuning these beasts is what I want to tell you about.
This is what it looks like step-by-step. If a link is opened from the desktop, we open the desktop web. If it’s opened from a smartphone, we look to see whether the app in question has been installed and, depending on the answer, we either open the link in the app or we direct the user to the app store. If the user is directed to the app store, we’d love to open the originally requested content after the installation.
Why would you need to do any of this? We found out there are millions of scenarios. Let me show you a few examples.
Suppose you want to send a message to a user, saying, “Look, you’ve got a new ‘like’.” It would be great if, by clicking on ‘Take a look’, you could open up that exact ‘like’.
Another example: the pop band ‘Serebro’ registered an account in your application. You want them to be able to publish a link under their videos which would also open up this profile.
Other useful use case is ads in Facebook. Facebook is very sensitive about ensuring that, if something specific is displayed in an ad, the link in question directs the user to that ‘something’. So, if in an ad you see the profile for a guy, they insist that you should be able to see that same guy in the app.
But the coolest example is typically the ‘share’ button.
The great thing about this button is that users actually want to spread some information related to your application. It is even more common for applications other than dating.
Let’s say you have a travel application. Users will voluntarily and happily share their tickets or hotels with their companions. They will send links to their friends, thus advertising your application at no cost to you. Ideally, this leads to new installs and organic growth — and the only thing you have to pay for is the one-time implementation of deep links.
How we implemented the deep links
We realised this was great and we were keen to have it. So, we got together and started to think about how we could do it.
There are several options available:
- branch.io (a staple name, everyone knows them),
- AppsFlyer (a marketing juggernaut),
- some other small weird services (we didn’t actually look into them and Firebase Deep linking didn’t exist back then), or
- you can make your own (reinventing the wheel, as it were).
In the end we decided to reinvent the wheel, but let me tell you how it came to that.
Branch.io
The first thing we did was to look at branch.io. Without exception, everything they do is related to deep links: right at the centre of the site are the words ‘deep linking’. The two points on either side basically also pretty much mean deep linking.
They have loads of well known clients; our dearly beloved rival, Tinder, uses them. And, for some use cases, they are free-of-charge. However, in our case they turned out to be not quite so free-of-charge.
They are, there’s no question about it, experts in the field. They write a million blog posts in which they tell you about the very same problems which I am going to tell you about. However, once their posts go from describing the problem to talking about the solution, they fudge the issue somewhat and say, “Use our service; we know how it’s done.” Which is a boring non-answer. Luckily, now you have me, and I have the non-boring right answers!
AppsFlyer
AppsFlyer is a marketing service intended first and foremost for tracking installations with a specific focus on finding the origin where the user has come from. This means measuring the effectiveness of advertising campaigns and things like that. When we started working on universal links, Badoo was already their client and our marketing people simply adored it. If you were to corner one of our marketing people and ask them whether AppsFlyer is good, this is the answer you would get, “Very good; all other services are far worse. And please don’t corner me. Thank you.”
AppsFlyer also has lots of well known clients; Tinder also uses AppsFlyer for everything but deep linking, but at the time this didn’t put us off.
We went onto the site and saw the notice, “The world’s most powerful deep linking platform.” Okay, based on our thorough assessment of this incredibly detailed marketing copy, it looked like that was exactly what we needed.
What’s more, at the time for us it was free-of-charge, because it was part and parcel of another product for which we were already paying (unlike branch.io which can become very expensive, depending on how you use them).
We went onto their site. At the time, they had this diagram which isn’t on the site anymore. Basically, it is what I showed earlier. You follow the link. If the app is installed, it runs. If it isn’t installed, you go to the App Store. But…
It turned out that in the case where the application is not installed, we go to the App Store and, having installed it, we open the content — and it works. And that makes sense; those guys do install tracking, it’s their job.
However, in the case where the application is already installed, for some reason instead of opening the content, it again displays the question, “Open this page in App Store?”
That is when we stopped blindly following SDK instructions and sat down to figure out how it works under the hood. And, in order to work out why they have this error and what we could do about it, we had to start at the very beginning.
How deep links work, the very beginning
Here is a deep link that you probably would consider a totally standard one:
Here we have the custom scheme badoo:// , a reference to something we want to open ( user in that case) and the ID of the content in question ( 1234567 ).
Obviously, you can’t use this link in its ‘raw’ form for a very simple reason. If the application is installed, it works as a link, but if the application is not installed, it leads to the error message such as “Safari cannot open the page.” That makes sense: Safari has no idea how to work with it.
Until recently this could be fixed by a pretty simple hack. We made a typical HTML page that looked similar to this:
There is an iframe, which receives parameters from the URL and which contains the deep link as source. And there is a javascript snippet which redirects to the App Store. The idea is that if you have the app installed, iframe will run first and take you to the app, and if you don’t, the redirect kicks in and everyone is happy and you see no errors.
Besides that, you can attach Open Graph tags to the HTML page, which will allow the link to look attractive, just as I showed you: it has an image, a preview and everything.
Right, so starting from about iOS 9, this simple approach simply stopped working.
What do I mean by ‘stopped working’? I mean that it started working as if you were simply dealing with the badoo:// link. If the application was installed, it worked. If it was not installed, it showed an error (basically, on top of the redirect). In other words, if the user follows the link and they don’t have the application installed, an error occurs. And at Apple they ‘broke’ this deliberately.
Why? Because they came up with something they claimed was fundamentally new and fantastic, namely universal links.
Their idea was that you would simply register the entire link, the whole domain, as a universal link. And when I say that this was a fundamentally new and fantastic approach, I in fact mean ‘almost fundamentally new’ because Android has had it for a number of years already.
So this way http://example.com/user/1234567 becomes a link registered with the application (both iOS and Android)
Why did Apple make this change?
- Verification. Any app can claim to support badoo:// . The domain however is confirmed by the DNS.
- Privacy. The application no longer has access to cookies from the original website and its partners. This is what Apple has been focusing on more and more with every passing year: to separate knowledge about the user in Safari from knowledge about the user in the application.
- Simplicity. In theory, this will remove the need for iframe hacks.
- Versatility. This approach is supposed to work better across all possible platforms.
Unfortunately, the ‘Simplicity’ part didn’t hold up for us one bit. Once we had got rid of iframe hacks, we were forced to add lots of other hacks — but more about that later.
For now, let’s go back to AppsFlyer. Remember, it all started with the fact that they didn’t support universal links.
In fact, as we learned from the documentation, they did support universal links, but they only supported them with a third-level domain of their own.
At Badoo we really don’t like to take such risks. Theoretically AppsFlyer could increase their price tenfold or simply close down the shop, and the links are already distributed all around the internet. We wanted to be able to support the links forever, regardless of our partners’ behaviour.
But we know how to solve these problems in the web, right? We’ll just do a redirect. After all, redirects already work on the web, right?
https://badoo.com/link/user/1234567
redirects to
https://badoo.onelink.me/user/1234567
And we started testing. Okay, onelink.me works; everything is integrated fine. SDK runs, opens Badoo and opens content. Our link, which is a totally standard redirect… opens Safari. “No way,” we thought.
https://badoo.com/link/user/1234567 — opens Safari
https://badoo.onelink.me/user/1234567 — opens Badoo
We started investigating and found out the reason. Also, at this point we started keeping a list which was destined to grow longer and longer as our investigation progressed. The list is called, ‘When universal links don’t open the application even though you’d reasonably expect them to.’
And here is the first point on the list:
Redirects to universal links generally do not work. This really bummed us and we decided to completely give up on AppsFlyer (for this reason — and some others) and do everything ourselves. We particularly liked that idea because we already had https-links that we used with Android:
It consisted of a weird legacy URL and two parameters: page id (i. e. which screen to open, here it’s 9) and content id (e. g. user id, here it’s 1234567).
How we added support for universal links to an iOS app
Adding support for a universal link on iOS isn’t particularly complicated. There are instructions on the Apple site, which literally take three pages if printed and basically tell you to do three things.
Firstly, you need to add an apple-app-site-association JSON file with your appID and the paths the application should open to the universal links. Here’s how it looked for us:
(You can see more stuff if you actually hit the URL but the idea is the same)
Secondly, you need to add domains to your entitlements:
And thirdly, you need to write some code which basically verifies that the ActivityType is BrowsingWeb and that there is a URL.
We did this and tested a little bit. Everything worked fine, and we went off to argue about what the links should look like going forward.
Here’s what the argument was about. We had our initial approach that I described, which worked using page id. Typically (e. g. by AppsFlyer and branch.io) a different approach is used. Usually, it works like this. You don’t have a concrete screen identifier, but rather just some sort of ref for the link. When the app launches, it sends the ref to the server, obtains an answer as to where to land and lands there.
https://m.badoo.com/aa/landto/?page=9&user_id=1234567
vs
https://m.badoo.com/aa/landto/?ref=abcdef
The problem with the second option is that, while the application is obtaining content, we’d want to display some sort of a skeleton preview before the whole page is loaded, and the second approach doesn’t allow us to do so (in particular, AppsFlyer doesn’t allow you to do so at all).
What did we decide to go for? Both. We just used both approaches and got something like this:
Basically, this is a decent solution: we can use ref both for statistics and for controlling extra server behaviour, depending on what kind of link it was (for example, we have links which give credits). At the same time page id and user id can be used to launch, immediately show skeleton of the user’s profile page and happily perform ‘get user’. In a parallel request the ref is reported to the server.
However, another problem arose. Managers came to us and said, “Guys, we have a really long link. How are people going to deal with it?”
Once again, the solution is quite clear and has been on the web for a really long time. It’s link minifiers!
How we minified universal links
Basically, we retain all the properties in a short link. There will be a page identifier, and a content identifier — so it can be done.
Then we remembered that redirects don’t work with universal links and got sad. What do we do?
After some experimentation, it turned out that you can actually redirect, but to do so you need a little hack. It’s pretty simple. Your minifier (it has to be your own minifier on a separate domain) is also registered as a deep link domain in the app, with its own apple-app-site-association for it. Then you write code for it, and, correspondingly, both domains are deep links.
This way both https://bdo.to/u/abcdef and https://m.badoo.com/aa/landto/?ref=abcdef&page=9&user_id=1234567 are registered as a universal link in the app.
Moreover, it is quite easy to implement. Quite simply, the app, when opened from a minifier, performs an http request, gets a URL to redirect to and uses that link with the existing logic for long links.
How deferred deep links work
You might remember that I started the AppsFlyer story with how accessing the content in the deep link worked if you need to install the app first. That’s called deferred deep linking (because you defer the landing until after the app is installed).
This is the only bit which we didn’t do ourselves and still used AppsFlyer to help us with this. In principle, you could do it yourselves — we just didn’t want or need to.
What is the idea behind it? The user opens an AppsFlyer http link, the user is fingerprinted with everything you can grab from Safari (i.e. IP address, iPhone model, clock delay etc.), and redirected to the App Store. The user installs the app and launches it. After that, the AppsFlyer SDK reports the same data (IP address, phone model etc.) to their server. The server then correlates whatever they got from the SDK with people who recently followed links associated with this app and draws the conclusion as to which link needs to be opened.
Here’s how it all works together. The minifier redirects to our link. If the app is not opened by this point, it means that the app is not installed, and so it’s reasonable to redirect to AppsFlyer. AppsFlyer redirects to the App Store with tracking and does what it needs to do as described above.
How nothing works in SafariViewController
While we were busy doing all this stuff, someone from QA came to us and said, “Guys, I am sending a link to myself via Telegram, Skype and HipChat and nothing is working when I tap on them” And we answer, “Hang on, it’s working on our machines.”
It turned out the problem was related to SafariViewController .
The story with SafariViewController is totally tragic. Here’s the deal. Apple’s idea was that if a user opens Safari, enters a universal link and presses Enter, it will not open an application. That makes sense; if you are a user, you do not expect, when you press Enter in the browser, that you will suddenly be thrown into a different app.
It’s the second bit which doesn’t make sense. When the application opens SafariViewController , exactly the same thing happens, as if the user had entered the link into the window and had pressed Enter. There is no way to open a universal link when the app uses SafariViewController.
So, we add to our list:
If the user entered the link into Safari themselves or opened SafariViewController — nothing works. You are forced to display a web page or redirect to App Store. We thought about this for a while and then came up with a solution.
Here’s our idea: since we’re forced to open a web page, we will open the web page. Universal links do work when opened from SafariViewController , so we’ll just have a button that link to the very same page. In principle, that should trigger the universal link.
Except of course it didn’t.
That didn’t take too long to figure out, and here’s a new entry to our list:
If the user clicked on a link in the same domain in which they are currently located, it does not open the application.
What can we do? What else can we do?
It’s going to be another hack, of course.
It is all quite simple: we create two domains and register them both as a universal link. This is what it looks like.
The user opens m.badoo.com , but the link on the button will lead you to mlink.badoo.com . You can even copy this link and send it; it works both ways. Both these domains work for us as equivalents. Correspondingly, if a user opens mlink.badoo.com , the link on the button will be to m.badoo.com .
And that finally worked!
What the system looks like with web preview
In general terms things have got even better.
Now, the minifier redirects to the full link. The full link on m.badoo.com shows a preview which directs to mlink.badoo.com via the button. The alternative link on mlink.badoo.com redirects to AppsFlyer, and from there the user is redirected to the App Store with tracking.
Despite the complexity, things were starting to work somewhat better. At least people were more or less able to open content in Safari and Telegram.
How we encountered mysterious bugs and solved them
That’s when our good old QA person came to us again with a very sad face and said, “You know what, you have got some very strange things happening.”
(Cue mysterious music here)
On some devices (only on some) for some reason, universal links in our app did not work. At all. Other apps worked perfectly fine.
We worked out why. When following a universal link and launching an app, the following button appeared in the top right-hand corner of the screen:
And this button does two things. Firstly, it opens Safari. Secondly, it ‘breaks’ deep links once and for all for your application!
And now the only way to ‘unbreak’ the deep links is to long-tap the link, to click ‘open in Badoo’, and then everything will work fine again. But, as far as I can remember, not a single end user ever did that. They just lived without deep links for the app from that point onwards. And there’s nothing you, as a developer, can do. The only point for you is: don’t touch this button yourself.
Fortunately, in its infinite wisdom last autumn, Apple gave us a fantastic present and removed this button from iOS 11.
However, if you support iOS 9 and 10, remember about this button. And, if you happen to support iOS 9, remember that apple-app-site-association should not be disallowed to robots in robots.txt . That’s another mysterious bug we’ve spent way too much time on. Here’s the full list:
How to version deep links
We had already made a lot of painful mistakes. And then a new feature made us make a few more.
Badoo decided to create a new, cool function called ‘Lookalikes’.
The idea was very simple. You take someone’s photo with your phone’s camera or use an existing photo and we will find people on our service who look like that person. You can search for celebrities, friends or even for yourself, looking for your own doppelgangers. Great idea, good for marketing.
It was so great that our managers said that we had to change our approach for that feature specifically. The existing one looked like this:
We were really keen that, when our users share lookalikes with one another, the recipients can see them. Whatever happens, nothing should stand in the way of that. So, if the given app is not installed, we no longer send them to the App Store; we simply open the content on mobile web. The new approach looked like this:
That didn’t seem like much at first. We say, “Right, if the address has another page id, we will use that to redirect to mobile web.”:
This wasn’t complicated; we implemented and tested it in a couple of days. However, then we realised that this is a new functionality that we had never had in our apps before.
And that means that even if an app is installed, it still isn’t certain that we need to open it. Actually the approach should look more like this:
If an app is installed, you need to check whether it supports the new functionality. And only if it supports the new functionality, should you open the content in the app. Otherwise, you should direct to the mobile web.
By the time we released the feature, it was only available on the web, but we wanted to bring it to all platforms gradually. And that brings us to the subject of versioning the links. Particularly, versioning of minified links.
Once again, ideally everything is very simple. We have an old version and a new version. The idea is that the old version only opens /u paths, and the new version opens /u paths and, let’s say, /l/a paths from ‘lookalikes’.
We rolled up our sleeves and thought, “Right, let’s get this done.” But it turned out to be impossible to do it right.
Remember how at the beginning I told you about how to set up links? You might remember that the paths that are supported by the app are specified in the apple-app-site-association file. It turned out, that’s the only place where the paths are specified.
Consequently, as soon as we add a new path, it starts opening all versions of the app, including the old one which knows nothing about it:
In practice, the new link crashed our old app completely, because we forgot to take that into account. And there was nothing more we could do about that. The only thing that we did was to wait for the new app to accumulate a sufficient number of users and, only then, did we switch it on on the server side.
You however, can live a better, healthier life than me and think about all this in advance. When the app starts from a URL, check whether you can open such a URL and, where necessary, return a ‘false’ response:
In this case, if a user’s outdated version of an app attempts to open something it doesn’t support, then Safari will open instead. And, as soon as the new version supports it, canOpenUrl of this version will return a ‘true’ response and the new version will open.
How we tamed Facebook
When everything became more or less stable, our marketing team wanted to advertise with universal links on Facebook. Go ahead, I told them, it should work everywhere.
It turned out that Facebook doesn’t care one bit about new technologies and advancements in universal linking. They still live in the age where deep links look like the original badoo://user/1234567 and actually require the link in that format from advertisers. The only alternative is their weird proprietary standard.
It’s called Facebook App Links. It’s pretty much a continuation of the OpenGraph idea: you add some meta tags to your html for Facebook. They look like this:
You’ll need to serve those tags with your html or at least to the facebookexternalhit/ User Agent.
The links in the meta tags still need to be in badoo://something format. So as you see, we decided we would just reuse our typical scheme here.
Note that this approach only works if you are buying ads from Facebook with this link. If the link is shared in Facebook by your own users, it will still open the in-app browser. The html preview we used to fight against SafariViewController is still your friend here.
When we still use old-style links
Do you remember how earlier, starting with iOS 9, we got a Safari error, if a given user had not installed an app? That doesn’t look good; we don’t want users to see error messages. And do you remember this email?
Buttons in this kind of emails will log the user in (using a temporary token), and redirect them to the particular “like”.
So these messages are individualised for specific users. And we actually keep the stats for each one of our users: which version of an app are they using and on which device. That means that for this kind of email specifically, we can sometimes use the old approach.
Here’s how it works. We know that Ben has our app installed on his iPhone X with iOS 11.1 and logs in regularly, the last time being 4 hours ago. If he opens the email from an iPhone X with iOS 11.1, we simply redirect him to badoo://landto/
. The probability that he will see an error is very low. The only case in which that might happen is if he’s just deleted the app.
The upside of that risky approach is that it completely bypasses all SafariViewControllers and similar. Gmail app on iOS notoriously uses one, so using that approach is a big win for its users.
How to do universal links, tl;dr
I’ve told you our story in so many kilobytes, now let me give you a shorter takeaway on how to implement great universal links without outsourcing it to someone.
Источник