Shaunebu.MAUI.AppLinks
1.0.1
dotnet add package Shaunebu.MAUI.AppLinks --version 1.0.1
NuGet\Install-Package Shaunebu.MAUI.AppLinks -Version 1.0.1
<PackageReference Include="Shaunebu.MAUI.AppLinks" Version="1.0.1" />
<PackageVersion Include="Shaunebu.MAUI.AppLinks" Version="1.0.1" />
<PackageReference Include="Shaunebu.MAUI.AppLinks" />
paket add Shaunebu.MAUI.AppLinks --version 1.0.1
#r "nuget: Shaunebu.MAUI.AppLinks, 1.0.1"
#:package Shaunebu.MAUI.AppLinks@1.0.1
#addin nuget:?package=Shaunebu.MAUI.AppLinks&version=1.0.1
#tool nuget:?package=Shaunebu.MAUI.AppLinks&version=1.0.1
Shaunebu.MAUI.AppLinks 🌐✨
Shaunebu.MAUI.AppLinks provides a streamlined solution for handling Universal Links (iOS) and App Links (Android), enabling seamless deep linking across platforms.
It also supports Custom URI Schemes (myapp://home) for app-only navigation.
🚀 Installation
Install via NuGet:
PM> Install-Package Shaunebu.MAUI.AppLinks
NuGet Link: Saunebu.MAUI.AppLinks Compatible with .NET MAUI 8+ projects.
🔗 What Are Deep Links?
Universal / App Links (https)
https://yourdomain.com/...→ opens app if installed, otherwise navigates to the website.Requires domain verification (host JSON files in
.well-known).
Custom URI Schemes (app-only)
myapp://home→ opens app when installed.No server verification; use for prototypes or internal shortcuts.
⚙ Setup Summary
MAUI Integration (MauiProgram.cs)
using Shaunebu.MAUI.AppLinks;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseAppLinks(); // Enable Shaunebu.MAUI.AppLinks
return builder.Build();
}
}
⚡ Android: App Links + Custom Scheme
MainActivity.cs (App Link example)
[IntentFilter(
new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataScheme = "https",
DataHost = "shaunebu.com",
DataPathPrefix = "/",
AutoVerify = true)]
public class MainActivity : MauiAppCompatActivity { }
MainActivity.cs (Custom scheme example)
[IntentFilter(
new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataScheme = "miapp")] // miapp://...
public class MainActivity : MauiAppCompatActivity { }
assetlinks.json (host at https://shaunebu.com/.well-known/assetlinks.json)
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.shaunebu.myapp",
"sha256_cert_fingerprints": [
"AA:BB:CC:...:ZZ"
]
}
}
]
Verify with ADB:
adb shell pm verify-app-links --re-verify com.shaunebu.myapp
adb shell pm get-app-links com.shaunebu.myapp
🍏 iOS: Universal Links + Custom Scheme
Enable Associated Domains in Apple Developer portal and provisioning profile.
Entitlements.plist (add under Platforms/iOS)
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:shaunebu.com</string>
</array>
apple-app-site-association (host at https://shaunebu.com/.well-known/apple-app-site-association)
{
"applinks": {
"apps": [],
"details": [
{
"appID": "ABCDE12345.com.shaunebu.myapp",
"paths": [ "/home", "/products/*", "/profile/*" ]
}
]
}
}
Info.plist (register custom scheme)
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key><string>com.shaunebu.myapp</string>
<key>CFBundleURLSchemes</key>
<array>
<string>miapp</string>
</array>
</dict>
</array>
🧩 Sample Configuration Files
Android (assetlinks.json) — https://shaunebu.com/.well-known/assetlinks.json
iOS (apple-app-site-association) — https://shaunebu.com/.well-known/apple-app-site-association
Replace
package_name,sha256fingerprint,Team IDand bundle IDs with your real values.
🛠 API Usage (Rules, Callbacks, Events)
Shaunebu.MAUI.AppLinks gives two complementary ways to react to links:
Global event —
IAppLinkHandler.Current.AppLinkReceived(catches any app link).Rule-based callbacks — register rules with
IAppLinkRuleManagerand attach callbacks viaIAppLinkProcessor.
1) Global event (simple)
using Shaunebu.MAUI.AppLinks.Abstractions;
IAppLinkHandler.Current.AppLinkReceived += (sender, e) =>
{
MainThread.BeginInvokeOnMainThread(async () =>
{
// e.Uri is the incoming URI
await Application.Current.MainPage.DisplayAlert("AppLink", e.Uri?.ToString(), "OK");
});
};
- Use this when you want to handle all incoming links in one place.
2) Rule-based (recommended for structured routing)
Define rules
You can define AppLinkRule by pattern (URI) or by predicate.
// Example 1 — pattern-based rule
public static class StaticAppLinkRules
{
public static AppLinkRule HomeRule => new AppLinkRule("home_rule", new Uri("/home", UriKind.Relative));
}
// Example 2 — predicate-based rule
public static AppLinkRule ProductRule = new AppLinkRule("product_rule", uri =>
uri.Scheme == "https" && uri.Host == "shaunebu.com" && uri.AbsolutePath.StartsWith("/product"));
Register rules and callbacks
// Add the rule so the manager knows about it
IAppLinkRuleManager.Current.Add(StaticAppLinkRules.HomeRule);
// Register a callback for that rule
IAppLinkProcessor.Current.RegisterCallback(this, StaticAppLinkRules.HomeRule, async uri =>
{
await MainThread.InvokeOnMainThreadAsync(async () =>
{
// navigate inside the app or show UI
await Shell.Current.GoToAsync("//home");
});
});
RegisterCallbacktypically takes: a subscriber object (oftenthis), the rule, and anFunc<Uri, Task>callback.Keep a reference if you later need to unregister.
3) Reset / Cache behavior
If a link arrives before your handlers are subscribed, the library caches it.
You can clear the cached queue:
IAppLinkHandler.Current.ResetCache();
4) Tips
Always call
IAppLinkRuleManager.Current.Add(rule)beforeRegisterCallback(...). If the rule isn't added, callbacks won't be invoked.Use rule-based approach for complex apps — it lets you route links to specific pages cleanly.
For quick testing, the global event is the fastest route.
📌 Example: Full Flow (Universal + Custom)
// MauiProgram.cs
builder.UseAppLinks();
// MainPage.cs
IAppLinkHandler.Current.AppLinkReceived += (s,e) => Console.WriteLine($"Received: {e.Uri}");
// Register rule + callback
IAppLinkRuleManager.Current.Add(StaticAppLinkRules.HomeRule);
IAppLinkProcessor.Current.RegisterCallback(this, StaticAppLinkRules.HomeRule, async uri =>
{
await Shell.Current.GoToAsync("//home");
});
Test URLs:
Universal Link:
https://shaunebu.com/homeCustom Scheme:
miapp://home
🔍 Universal Links vs Custom Schemes (Comparison)
| Feature | Universal/App Links (https://) | Custom URI Schemes (miapp://) |
|---|---|---|
| Requires Domain | ✅ Yes (assetlinks / aasa) | ❌ No |
| Works if App not installed | ✅ Yes (opens website fallback) | ❌ No |
| Recommended for Production | ✅ Yes | ⚠️ For dev/prototype/internal |
| Security | ✅ Domain-verified | ❌ Can be claimed by any app |
| Setup Complexity | ⚠️ Medium (server + JSON) | ✅ Simple (app config only) |
| Example | https://shaunebu.com/home |
miapp://home |
🔗 References & Further Reading
Apple: Supporting Associated Domains — https://developer.apple.com/documentation/xcode/supporting-associated-domains
Android App Links — https://developer.android.com/training/app-links
Digital Asset Links Generator — https://developers.google.com/digital-asset-links/tools/generator
.NET MAUI docs (App Links / Universal Links) — https://learn.microsoft.com/dotnet/maui/android/app-links & https://learn.microsoft.com/dotnet/maui/macios/universal-links
Branch AASA Validator — https://branch.io/resources/aasa-validator
Helpful article: How Android App Linking works — https://chris.orr.me.uk/article/android-app-linking-how-it-works/
💡 Recommendations
Use Universal / App Links for production, marketing links and cross-platform UX.
Use Custom Schemes for quick testing, dev tooling or internal shortcuts.
Always validate URI parameters in your callbacks to avoid injection/spoofing attacks.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0-android35.0 is compatible. net9.0-ios18.0 is compatible. net9.0-maccatalyst18.0 is compatible. net9.0-windows10.0.19041 is compatible. net10.0-android was computed. net10.0-android36.0 is compatible. net10.0-ios was computed. net10.0-ios26.0 is compatible. net10.0-maccatalyst was computed. net10.0-maccatalyst26.0 is compatible. net10.0-windows was computed. net10.0-windows10.0.19041 is compatible. |
-
net10.0-android36.0
- No dependencies.
-
net10.0-ios26.0
- No dependencies.
-
net10.0-maccatalyst26.0
- No dependencies.
-
net10.0-windows10.0.19041
- No dependencies.
-
net9.0-android35.0
- No dependencies.
-
net9.0-ios18.0
- No dependencies.
-
net9.0-maccatalyst18.0
- No dependencies.
-
net9.0-windows10.0.19041
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.