
Deep Linking for iOS and Android using MAUI
- By Nate Zaugg
- CEO | CIO
Introduction
Recently, I was building an app using .NET MAUI and the customer needed the ability to send users a link in email or text that would open this mobile app on iOS and Android.
This is also known as Deep Linking.
There are 2 different ways to accomplish this: One, is at a high level there is a method also known as Universal Links. The other way, that I am more used to, is where you use a custom HTTP schema.
The high-level difference is that Universal Links use the http://
or https://
format of URL, whereas the custom schema method uses your own schema as in myschema://
.
The downside of using the Universal Link method is that you need to have a website running that can accept incoming requests for a configuration file. I didn’t want that requirement for this particular app, so I decided to use the custom schema method.
When I started searching for how to implement this method, I found so many articles that it was overwhelming, and in the end, I was able to get it to work, but only after much blog reading, video watching, and trial and error.
This is why I have decided to write this blog post, hoping to help you not need to go through nearly as many hoops as I did. Here are the most simple steps to getting Deep Linking using the custom schema method in .NET MAUI for iOS and Android:
Android
Add the following method to your MainActivity.cs
file:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
var uri = Intent?.Data;
if (uri != null)
{
var parameters = uri.GetQueryParameters(null);
if (parameters != null && parameters.Count > 0)
{
}
}
}
This will detect that the app was started or resumed using a custom url schema. The uri value is the URL used to launch the app. The parameters variable will contain any query parameters on the URL that you can use to do specific things.
Add the following attribute just above your MainActivity.cs
file declaration of your MainActivity class:
[IntentFilter(new[] { Intent.ActionView },
Categories = new[]
{
Intent.ActionView,
Intent.CategoryDefault,
Intent.CategoryBrowsable,
},
DataScheme = "mycustomschema", DataHost = "", DataPathPrefix = "/")]
NOTE: The DataSchema must match what will be the beginning part of the URL used to launch the app. In the above code, the URL would be mycustomschema://
. The DataPathPrefix
can require something after the //
in order to match and launch your app.
iOS
Add the following method override to your AppDelegate.cs
file:
[Export("application:continueUserActivity:restorationHandler:")]
public override bool ContinueUserActivity(UIKit.UIApplication application, NSUserActivity userActivity, UIKit.UIApplicationRestorationHandler completionHandler)
{
if (userActivity != null)
{
string url = userActivity.WebPageUrl?.ToString();
// use the url to extract any query parameters with values if needed
}
return true;
}
Create an Entitlements.plist
file in the Platforms/iOS
folder with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:mycustomschema://example.test.com</string>
</array>
</dict>
</plist>
Lastly, add the following lines to your info.plist
file:
<key>com.apple.developer.associated-domains</key>
<string>CustomDomainHere.com</string>
<string>com.exampleapp.test</string>
<key>CFBundleURLSchemes</key>
<array>
<string>mycustomschema</string>
</array>
NOTE: The com.exampleapp.test
bundle Id
used in this example must be changed to match your app’s actual bundle Id, and the domain used must be changed to match your custom domain.
That’s all you have to do. I still can’t believe how much time I spent searching and trying things to end up with such a simple result. Every site or tutorial I found had different parts of the puzzle, forcing me to stitch it together piece by piece. Here it all is in one place- and I hope it will help you to avoid the same headaches I had to go through to get here.
Hope this helps save you time, effort, and frustration!