Forum Xamarin.iOS

OpenUrlContexts in SceneDelegate not called when URL clicked on

CaptainXamtasticCaptainXamtastic GBUniversity ✭✭✭
edited February 16 in Xamarin.iOS

I have a deep link registered, and where iOS is 13 or greater, although clicking on the link opens the app, the OpenUrlContexts override does not fire, hence I am unable to filter then navigate, based upon the URL.

This is a Xamarin Forms app, however I've asked the question here in the iOS forum, because it involves the new iOS Version 13+ SceneDelegate with modified AppDelegate.

I've included the following code files:
1. SceneDelegate
2. AppDelegate
3. apple-app-site-association
4. Entitlements.plist
5. Info.plist extract
6. App.xaml.cs

Does anyone know why the OpenUrlContexts method is not being called?

SceneDelegate file

    [Register("SceneDelegate")]
    public class SceneDelegate : UIWindowSceneDelegate
    {
        [Export("scene:openURLContexts:")]
        public override void OpenUrlContexts(UIScene scene, NSSet<UIOpenUrlContext> urlContexts)
        {
            Debug.WriteLine("*** URL property =====" + urlContexts.AnyObject.Url);
            var urlString = urlContexts.AnyObject.Url;
            if (urlString.Equals("https://REDACTED"))
            {
                // Run code 
            }
        }


        public override UIWindow Window { get; set; }

        public override void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
        {
            var windowScene = scene as UIWindowScene;
            if (windowScene != null)
            {
                Window = new UIWindow(windowScene.CoordinateSpace.Bounds);
                if (Window != null)
                {
                    // This just creates a new App instance without creating a new AppDelegate
                    // In iether case I still see issues with navigation events going to the wrong window,
                    // i.e. I tap Add Item in one window, but the new item page launches in another window
                    // Or use the menu to go to the ABout page, and the About page opens in the other window
                    // This is in keeping with what I have seen in reagrds to embedding forms pages into native 
                    // projects. In this case, you need to use the platforms navigation APIs, not Xamarin.Forms
                    // navigation APIs
                    var fApp = new App();
                    try
                    {
                        // Set the scene's RootViewController from the one X.Forms created
                        Window.RootViewController = fApp.MainPage.CreateViewController();


                        //// This creates the Xamarin.Forms UI with a new app delegate
                        var ad = new AppDelegate();
                        ad.GetUI();
                        //
                        //// Set the scene's RootViewController from the one X.Forms created
                        Window.RootViewController = ad.Window.RootViewController;


                        // Set the WindowScene
                        Window.WindowScene = windowScene;
                    }
                    catch(Exception ex)
                    {

                    }


                }
            }
        }
    }

AppDelegate file

    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        public UIApplication application;
        public NSDictionary options;
        //
        // This method is invoked when the application has loaded and is ready to run. In this 
        // method you should instantiate the window, load the UI into it and then make the window
        // visible.
        //
        // You have 17 seconds to return from this method, or iOS will terminate your application.
        //
        [Export("application:didFinishLaunchingWithOptions:")]
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();

            if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
            {
                // only used when creating a new app delegate in the scene delegate in order to be able to call 
                // LoadApplication in GetUI method
                this.application = app;
                this.options = options;

                return true;
            }
            else
            {
                LoadApplication(new App());
                return base.FinishedLaunching(app, options);
            }
        }

        // only used when creating a new app delegate in the scene delegate
        public void GetUI()
        {
            LoadApplication(new App());

            // This call populates the Window property so it needs to be called after LoadApplication for every scene 
            base.FinishedLaunching(application, options);

        }
    }

apple-app-site-association file:

{
   "applinks": {
     "apps": [],
     "details": [
       {
         "appID": "REDACTED",
         "paths": [ "/", "/REDACTED/*"]
       }
     ]
   }
}

Entitlements.plist file

<?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:REDACTED</string>
    </array>
</dict>
</plist>

Registration of SceneDelegate in info.plist

<?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>
    <!-- other stuff not shown here -->
    <key>UIApplicationSceneManifest</key>
    <dict>
        <key>UIApplicationSupportsMultipleScenes</key>
        <true/>
        <key>UISceneConfigurations</key>
        <dict>
            <key>UIWindowSceneSessionRoleApplication</key>
            <array>
                <dict>
                    <key>UISceneConfigurationName</key>
                    <string>Default Configuration</string>
                    <key>UISceneDelegateClassName</key>
                    <string>SceneDelegate</string>
                    <key>UISceneStoryboardFile</key>
                    <string>EmptyStoryboard</string>
                </dict>
            </array>
        </dict>
    </dict>
</dict>

Xamarin.Forms App.xaml.cs

    public partial class App : Application
    {

        public App()
        {
            InitializeComponent();

            DependencyService.Register<MockDataStore>();
            MainPage = new MainPage();
        }

        protected override void OnStart()
        {
        }

        protected override void OnSleep()
        {
        }

        protected override void OnResume()
        {
        }

        protected override void OnAppLinkRequestReceived(Uri uri)
        {
        // DOES NOT FIRE EITHER
            base.OnAppLinkRequestReceived(uri);
        }
    }

Answers

  • ColeXColeX Member, Xamarin Team Xamurai
    edited February 17

    It seems that when the app is launched on a cold start the openURLContexts function WILL NOT get called , but WillConnect method triggers , so as a workaround you can check the url in WillConnect method .

    Check https://stackoverflow.com/a/59207558/8187800 .


    Xamarin forums are migrating to a new home on Microsoft Q&A!
    We invite you to post new questions in the Xamarin forums’ new home on Microsoft Q&A!
    For more information, please refer to this sticky post.

  • CaptainXamtasticCaptainXamtastic GBUniversity ✭✭✭

    Hi @ColeX !!!

    Thanks for trying to help but my preliminary excitement quickly faded because in WillConnect I'd have expected connectionOptions.UrlContexts.AnyObject.Url to show the URL however UrlContexts is null.

    Also, a proper solution has to provide the same functionality that existed before iOS 13 came out, and that is:

    1. If the app is closed, it will open and the developer can be advised of the url that was clicked to open it
    2. If the app is already open (whether in the background, or visual in multi-window mode), that when a link is clicked that the developer can be advised of the url

    Even if the URL could be identified in WillConnect, that would only cater for case 1 above, and not 2.

    Although I am very very thankful for the Xamarin staff who help out in these forums, I'm very disappointed that there is singularly no documentation of these patterns for Xamarin Forms, and that the Xamarin.Forms solution templates in Visual Studio have not been updated with SceneDelegate and associated files, yet iOS 13 was released on the 19th of September 2019.

    In that changeover from iOS 12 to 13, every single developer has been left stranded without documentation.

    Anyway, thanks again, I’ve raised the issue as a Xamarin.Forms issue here: https://github.com/xamarin/Xamarin.Forms/issues/13786

Sign In or Register to comment.