0

I'm developing an application with Xamarin.Forms for Android and iOS. When I enter into an url that's like http://app.myapp.io/user/reset-password/{some_hash} I open the app in a special screen that allows the user to set a new password for his account.

In Android I achieve this by using custom intent filters, setting the scheme to http and the host to app.myapp.io. I want to do the same in iOS. But AFAIK when you register the app linking in iOS the way to do it is registering in your Info.plist file, the custom scheme. This is my custom scheme in my Info.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>UIDeviceFamily</key>
    <array>
        <integer>1</integer>
        <integer>2</integer>
    </array>
    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>UISupportedInterfaceOrientations~ipad</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationPortraitUpsideDown</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    <key>MinimumOSVersion</key>
    <string>6.0</string>
    <key>CFBundleDisplayName</key>
    <string>MyApp</string>
    <key>CFBundleIdentifier</key>
    <string>com.company.app</string>
    <key>CFBundleVersion</key>
    <string>1.0</string>
    <key>CFBundleIconFiles</key>
    <array>
        <string>Icon-60@2x</string>
        <string>Icon-60@3x</string>
        <string>Icon-76</string>
        <string>Icon-76@2x</string>
        <string>Default</string>
        <string>Default@2x</string>
        <string>Default-568h@2x</string>
        <string>Default-Portrait</string>
        <string>Default-Portrait@2x</string>
        <string>Icon-Small-40</string>
        <string>Icon-Small-40@2x</string>
        <string>Icon-Small-40@3x</string>
        <string>Icon-Small</string>
        <string>Icon-Small@2x</string>
        <string>Icon-Small@3x</string>
    </array>
    <key>UILaunchStoryboardName</key>
    <string>LaunchScreen</string>
    <key>CFBundleName</key>
    <string>Halligan</string>
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>com.company.app</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>http</string>
            </array>
        </dict>
    </array>
</dict>
</plist>

Here's my AppDelegate.cs

{
    // The UIApplicationDelegate for the application. This class is responsible for launching the 
    // User Interface of the application, as well as listening (and optionally responding) to 
    // application events from iOS.
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IDeviceStorage
    {
        const string HOCKEYAPP_APPID = "ef71d53e56044baa813c2381b291c355";

        #region IDeviceStorage implementation
        public string LoadString(string key, string def = null)
        {
            string value = NSUserDefaults.StandardUserDefaults.StringForKey(key);
            if (value == null)
                return def;
            else
                return value;
        }

        public void SaveString(string key, string value)
        {
            NSUserDefaults.StandardUserDefaults.SetString(value, key);
            NSUserDefaults.StandardUserDefaults.Synchronize();
        }
        #endregion

        //
        // 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.
        //
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            if (!Resolver.IsSet) SetIoc();

            global::Xamarin.Forms.Forms.Init();
            SvgImageRenderer.Init ();
            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }

        public override bool OpenUrl (UIApplication app, NSUrl url, string sourceApp, NSObject annotation)
        {
            var resetLinkHash = string.Empty;
            if (url.BaseUrl.Host.Equals ("app.myapp.io")) {
                    if (!Resolver.IsSet) SetIoc();

                    global::Xamarin.Forms.Forms.Init();

                    LoadApplication(new App(url.LastPathComponent));
                    return true;

            }
            LoadApplication(new App(url.LastPathComponent));
            return true;
        }

        private void SetIoc()
        {
            TinyIoCContainer.Current.AutoRegister ();
            var container = TinyIoCContainer.Current;
            container.Register<IDeviceStorage>(this);
            container.Register<IXFormsApp> (new XFormsAppiOS ());
            container.Register<ISecureStorage, SecureStorage> ();
            Resolver.SetResolver(new XLabs.Ioc.TinyIOC.TinyResolver(container));
        }
    }
}

And here's my Main.cs

{
    public class Application
    {
        // This is the main entry point of the application.
        static void Main(string[] args)
        {
            // if you want to use a different Application Delegate class from "AppDelegate"
            // you can specify it here.
            UIApplication.Main(args, null, "AppDelegate");
        }
    }
}

And well, for now this doesn't work on iOS, trying with or without http at the begining.

If someone can point me out in the right direction, I'd appreciate it. It's very important to me launching the app by matching the url, doing something like adding some <meta/> tags to the page html will not work because I don't have any access to the server.

4gus71n
  • 3,717
  • 3
  • 39
  • 66

1 Answers1

0

Unlike Android, URL schemes on iOS can only be registered to a single app. The reason this doesn't work for you is because http isn't an available URL scheme that your app can register itself to use on iOS.

The way to get this working is Universal Links, which is a new iOS 9+ feature. This allows you to register your app for http/https URLs on a specific domain only. However, you'll need access to the server for this, because you need to make some server-side changes to prove that you control the domain in question. If this is impossible, consider using a free service like Branch.io (full disclosure: I'm the team) to handle your links.

Alex Bauer
  • 13,147
  • 1
  • 27
  • 44