android – .NET MAUI App Hyperlinks not opening app, as an alternative opening browser


I’m making an attempt to arrange deep linking/common linking for my .NET MAUI app. Every little thing seems on the floor to be arrange in accordance with the MS documentation, nevertheless when accessing hyperlinks it merely makes use of the browser. This occurs in each Android and Google.

The specified behaviour is in order that any site visitors to https://app.rackemapp.com (which is able to usually be by a QR code) will set off the app to open.

In Android I examined it with a customized scheme of rackemapp:// which labored, so I do know the bottom logic works, I simply can’t get the units to grasp that app.rackemapp.com site visitors ought to open the app.

The curl testing to achieve my AASA file works okay (no redirects or 40x errors) and the diagnostics instrument on the system detects it as a sound common hyperlink.

How do I make it open my app?

MauiProgram.cs

public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp()
                .UseMauiCommunityToolkit()
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Common.ttf", "OpenSansRegular");
                    fonts.AddFont("bootstrap-icons.ttf", "Bootstrap");
                })
                .ConfigureLifecycleEvents(lifecycle =>
                {
#if IOS
                    lifecycle.AddiOS(ios =>
                    {
                        // Common hyperlink delivered to FinishedLaunching after app launch.
                        ios.FinishedLaunching((app, information) => HandleAppLink(app.UserActivity));

                        // Common hyperlink delivered to ContinueUserActivity when the app is working or suspended.
                        ios.ContinueUserActivity((app, userActivity, handler) => HandleAppLink(userActivity));

                        // Solely required if utilizing Scenes for multi-window assist.
                        if (OperatingSystem.IsIOSVersionAtLeast(13) || OperatingSystem.IsMacCatalystVersionAtLeast(13))
                        {
                            // Common hyperlink delivered to SceneWillConnect after app launch
                            ios.SceneWillConnect((scene, sceneSession, sceneConnectionOptions)
                                => HandleAppLink(sceneConnectionOptions.UserActivities.ToArray()
                                    .FirstOrDefault(a => a.ActivityType == Basis.NSUserActivityType.BrowsingWeb)));

                            // Common hyperlink delivered to SceneContinueUserActivity when the app is working or suspended
                            ios.SceneContinueUserActivity((scene, userActivity) => HandleAppLink(userActivity));
                        }
                    });
#endif
#if ANDROID
                    lifecycle.AddAndroid(android =>
                    {
                        android.OnCreate((exercise, bundle) =>
                        {
                            var motion = exercise.Intent?.Motion;
                            var information = exercise.Intent?.Information?.ToString();

                            if (motion == Android.Content material.Intent.ActionView && information just isn't null)
                            {
                                Activity.Run(() => HandleAppLink(information));
                            }
                        });
                    });
#endif

                });

            //Pointless code omitted

            var app = builder.Construct();

            ServiceHelper.Initialize(app.Providers);

            return app;
        }

#if IOS
        static bool HandleAppLink(Basis.NSUserActivity? userActivity)
        {
            if (userActivity just isn't null && userActivity.ActivityType == Basis.NSUserActivityType.BrowsingWeb && userActivity.WebPageUrl just isn't null)
            {
                HandleAppLink(userActivity.WebPageUrl.ToString());
                return true;
            }
            return false;
        }
#endif

        static void HandleAppLink(string url)
        {
            if (Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out var uri))
                App.Present?.SendOnAppLinkRequestReceived(uri);
        }

App.xaml.cs

public App()
        {

            InitializeComponent();           

            MainPage = new MainPage();
        }

        protected override async void OnAppLinkRequestReceived(Uri uri)
        {
            base.OnAppLinkRequestReceived(uri);

            var theurl = uri.ToString();

            // Present an alert to check that the app hyperlink was acquired.
            await Dispatcher.DispatchAsync(async () =>
            {
                //await Home windows[0].Web page!.DisplayAlert("App hyperlink acquired", uri.ToString(), "OK");
                var encodedString = theurl.Break up("/")[4];

                byte[] information = Convert.FromBase64String(encodedString);
                string decodedString = System.Textual content.Encoding.UTF8.GetString(information);

                var api = "https://mobileapi.rackemapp.com";
#if DEBUG
                api = "https://g7c7crrc-44357.uks1.devtunnels.ms";
#endif
                var shopper = new RestClient(api);
                var request = new RestRequest("/cell/getmatchfromtable/" + decodedString, Technique.Get);

                var execute = shopper.Execute(request);

                string rawResponse = execute.Content material;
                var choices = new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true
                };

                var response = new TableMatchResponse();

                if (rawResponse == null || rawResponse == "")
                {
                    response.MatchCode = "OFFLINE";
                }
                else
                {
                    response = System.Textual content.Json.JsonSerializer.Deserialize(rawResponse, choices);
                }

                if (response.MatchCode == null || response.MatchCode == "")
                {
                    // error situation
                }
                else
                {
                    App.Present.MainPage.Navigation.PushModalAsync(new Scoreboard(response.MatchCode));
                }

            });
        }

** curl to AASA**

curl -v https://app.rackemapp.com/.well-known/apple-app-site-association
* Host app.rackemapp.com:443 was resolved.
* IPv6: (none)
* IPv4: 104.21.50.101, 172.67.204.183
*   Attempting 104.21.50.101:443...
* Linked to app.rackemapp.com (104.21.50.101) port 443
* ALPN: curl gives h2,http/1.1
* (304) (OUT), TLS handshake, Consumer whats up (1):
*  CAfile: /and so forth/ssl/cert.pem
*  CApath: none
* (304) (IN), TLS handshake, Server whats up (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificates (11):
* (304) (IN), TLS handshake, CERT confirm (15):
* (304) (IN), TLS handshake, Completed (20):
* (304) (OUT), TLS handshake, Completed (20):
* SSL connection utilizing TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificates:
*  topic: CN=rackemapp.com
*  begin date: Dec 27 10:10:42 2024 GMT
*  expire date: Mar 27 11:08:16 2025 GMT
*  subjectAltName: host "app.rackemapp.com" matched cert's "*.rackemapp.com"
*  issuer: C=US; O=Google Belief Providers; CN=WE1
*  SSL certificates confirm okay.
* utilizing HTTP/2
* [HTTP/2] [1] OPENED stream for https://app.rackemapp.com/.well-known/apple-app-site-association
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: app.rackemapp.com]
* [HTTP/2] [1] [:path: /.well-known/apple-app-site-association]
* [HTTP/2] [1] [user-agent: curl/8.7.1]
* [HTTP/2] [1] [accept: */*]
> GET /.well-known/apple-app-site-association HTTP/2
> Host: app.rackemapp.com
> Consumer-Agent: curl/8.7.1
> Settle for: */*
> 
* Request utterly despatched off
< HTTP/2 200 
< date: Sat, 28 Dec 2024 21:57:37 GMT
< content-type: software/json
< content-length: 315
< last-modified: Tue, 24 Dec 2024 22:39:41 GMT
< accept-ranges: bytes
< etag: "589c11b95456db1:0"
< x-powered-by: ASP.NET
< cf-cache-status: DYNAMIC
< report-to: {"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=oe3dB4x1fALVNQ6f%2FDzDNWMBUj772yNTdc7RsseLGWDPbOWJ4hgLRn3%2FitA%2BY4vBR4KN5juDa4x9wxu9z0CGbK4jXP5m0n6f0VTyKamvPIGlvEJl6VobT6dMJOdHMuiCqkMtMA%3D%3D"}],"group":"cf-nel","max_age":604800}
< nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
< strict-transport-security: max-age=0; includeSubDomains; preload
< x-content-type-options: nosniff
< x-cloudflare-enabled: true
< server: cloudflare
< cf-ray: 8f94ce9b09d271f2-LHR
< alt-svc: h3=":443"; ma=86400
< server-timing: cfL4;desc="?proto=TCP&rtt=41458&min_rtt=36685&rtt_var=18592&despatched=5&recv=9&misplaced=0&retrans=0&sent_bytes=2911&recv_bytes=585&delivery_rate=50756&cwnd=227&unsent_bytes=0&cid=15096d52c33a80ae&ts=100&x=0"
< 
{
    "activitycontinuation": {
        "apps": [ "[Teamid].com.rackemapp.mobileapp" ]
    },
    "applinks": {
        "apps": [],
        "particulars": [
            {
                "appID": "[Teamid].com.rackemapp.mobileapp",
                "paths": [ "*", "/*" ]
            }
        ]
    }
* Connection #0 to host app.rackemapp.com left intact

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles