Collegamenti universali Apple

Spesso è consigliabile connettere un sito Web e un'app per dispositivi mobili in modo che i collegamenti in un sito Web avviino l'app per dispositivi mobili e visualizzino il contenuto nell'app per dispositivi mobili. Il collegamento delle app, noto anche come deep linking, è una tecnica che consente a un dispositivo mobile di rispondere a un URL e avviare contenuto in un'app per dispositivi mobili rappresentata dall'URL.

Nelle piattaforme Apple, i collegamenti diretti sono noti come collegamenti universali. Quando un utente tocca un collegamento universale, il sistema reindirizza il collegamento direttamente all'app senza instradare attraverso Safari o il sito Web. Questi collegamenti possono essere basati su uno schema personalizzato, ad esempio myappname://, oppure possono usare lo schema HTTP o HTTPS. Ad esempio, facendo clic su un collegamento in un sito Web della ricetta si aprirà un'app per dispositivi mobili associata al sito Web e quindi viene visualizzata una ricetta specifica per l'utente. Gli utenti che non hanno installato l'app vengono portati al contenuto nel sito Web. Questo articolo è incentrato sui collegamenti universali che usano lo schema HTTPS.

Le app .NET MAUI iOS supportano collegamenti universali. Ciò richiede l'hosting di un file JSON di collegamenti di asset digitali nel dominio, che descrive la relazione con l'app. Ciò consente ad Apple di verificare che l'app che tenta di gestire un URL abbia la proprietà del dominio URL per impedire alle app dannose di intercettare i collegamenti dell'app.

Il processo di gestione dei collegamenti universali Apple in un'app .NET MAUI iOS o Mac Catalyst è il seguente:

Per altre informazioni, vedere Consentire alle app e ai siti Web di collegarsi al contenuto in developer.apple.com. Per informazioni sulla definizione di uno schema URL personalizzato per la tua app, vedi Definizione di uno schema URL personalizzato per la tua app in developer.apple.com.

Creare e ospitare un file di domini associato

Per associare un sito Web alla tua app, dovrai ospitare un file di dominio associato nel tuo sito Web. Il file di dominio associato è un file JSON che deve essere ospitato nel dominio nel percorso seguente: https://domain.name/.well-known/apple-app-site-association.

Il codice JSON seguente mostra il contenuto di un tipico file di domini associati:

{
    "activitycontinuation": {
        "apps": [ "85HMA3YHJX.com.companyname.myrecipeapp" ]
    },
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "85HMA3YHJX.com.companyname.myrecipeapp",
                "paths": [ "*", "/*" ]
            }
        ]
    }
}

Le apps chiavi e appID devono specificare gli identificatori dell'app per le app disponibili per l'uso nel sito Web. I valori per queste chiavi sono costituiti dal prefisso dell'identificatore dell'app e dall'identificatore del bundle.

Importante

Il file di dominio associato deve essere ospitato usando https con un certificato valido e senza reindirizzamenti.

Per altre informazioni, vedere Supporto dei domini associati in developer.apple.com.

Aggiungere il diritto ai domini associati all'app

Dopo aver risolto un file di dominio associato nel dominio, dovrai aggiungere il diritto ai domini associati alla tua app. Quando un utente installa l'app, iOS tenta di scaricare il file di dominio associato e verificare i domini nel diritto.

L'entitlement dei domini associati specifica un elenco di domini a cui è associata l'app. Questo diritto deve essere aggiunto al file Entitlements.plist nell'app. Per altre informazioni sull'aggiunta di un diritto in iOS, vedere Entitlement. Per altre informazioni sull'aggiunta di un diritto in Mac Catalyst, vedere Entitlement.

Il diritto viene definito usando la com.apple.developer.associated-domains chiave , di tipo ArrayString:

<key>com.apple.developer.associated-domains</key>
<array>
  <string>applinks:recipe-app.com</string>
</array>

Per altre informazioni su questo diritto, vedere Entitlement dei domini associati in developer.apple.com.

In alternativa, è possibile modificare il file di progetto (con estensione csproj) per aggiungere il diritto in un <ItemGroup> elemento:

<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios' Or $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">

    <!-- For debugging, use '?mode=developer' for debug to bypass apple's CDN cache -->
    <CustomEntitlements
        Condition="$(Configuration) == 'Debug'"
        Include="com.apple.developer.associated-domains"
        Type="StringArray"
        Value="applinks:recipe-app.com?mode=developer" />

    <!-- Non-debugging, use normal applinks:url value -->
    <CustomEntitlements
        Condition="$(Configuration) != 'Debug'"
        Include="com.apple.developer.associated-domains"
        Type="StringArray"
        Value="applinks:recipe-app.com" />

</ItemGroup>

In questo esempio sostituire con applinks:recipe-app.com il valore corretto per il dominio. Assicurarsi di includere solo il sottodominio desiderato e il dominio di primo livello. Non includere i componenti di percorso e di query o una barra finale (/).

Nota

In iOS 14+ e macOS 11+, le app non inviano più richieste di apple-app-site-association file direttamente al server Web. Invece, inviano richieste a una rete di distribuzione di contenuti gestita da Apple (rete CDN) dedicata ai domini associati.

Aggiungere la funzionalità domini associati all'ID app

Dopo aver aggiunto il diritto ai domini associati all'app, dovrai aggiungere la funzionalità domini associati all'ID app per la tua app nell'account Apple Developer. Questo è necessario perché tutti i diritti definiti nella tua app devono anche essere aggiunti come funzionalità all'ID app per la tua app nell'account per sviluppatore Apple.

Per aggiungere la funzionalità domini associati all'ID app:

  1. In un Web browser accedere all'account apple developer e passare alla pagina Certificati, ID e profili.

  2. Nella pagina Certificati, Identificatori e profili selezionare la scheda Identificatori .

  3. Nella pagina Identificatori selezionare l'ID app corrispondente all'app.

  4. Nella pagina Modifica configurazione ID app abilitare la funzionalità Domini associati e quindi selezionare il pulsante Salva :

    Screenshot of enabling the associated domains capability in the Apple Developer Portal.

  5. Nella finestra di dialogo Modifica funzionalità app selezionare il pulsante Conferma .

Dopo aver aggiornato l'ID app dell'app, dovrai generare e scaricare un profilo di provisioning aggiornato.

Nota

Se in un secondo momento si rimuove il diritto ai domini associati dall'app, sarà necessario aggiornare la configurazione dell'ID app nell'account Apple Developer.

Quando un utente attiva un collegamento universale, iOS e Mac Catalyst avviano l'app e lo inviano un NSUserActivity oggetto. Questo oggetto può essere sottoposto a query per determinare la modalità di avvio dell'app e determinare l'azione da intraprendere. Questa operazione deve essere eseguita nei delegati del FinishedLaunching ciclo di vita e ContinueUserActivity . Il FinishedLaunching delegato viene richiamato all'avvio dell'app e il ContinueUserActivity delegato viene richiamato quando l'app è in esecuzione o sospesa. Per altre informazioni sui delegati del ciclo di vita, vedere Eventi del ciclo di vita della piattaforma.

Per rispondere a un delegato del ciclo di vita iOS richiamato, chiamare il ConfigureLifecycleEvents metodo sull'oggetto MauiAppBuilder nel CreateMauiapp metodo della MauiProgram classe. Quindi, nell'oggetto ILifecycleBuilder chiamare il AddiOS metodo e specificare che Action registra un gestore per il delegato richiesto:

using Microsoft.Maui.LifecycleEvents;
using Microsoft.Extensions.Logging;

namespace MyNamespace;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            })
            .ConfigureLifecycleEvents(lifecycle =>
            {
#if IOS || MACCATALYST
                lifecycle.AddiOS(ios =>
                {
                    // Universal link delivered to FinishedLaunching after app launch.
                    ios.FinishedLaunching((app, data) => HandleAppLink(app.UserActivity));

                    // Universal link delivered to ContinueUserActivity when the app is running or suspended.
                    ios.ContinueUserActivity((app, userActivity, handler) => HandleAppLink(userActivity));

                    // Only required if using Scenes for multi-window support.
                    if (OperatingSystem.IsIOSVersionAtLeast(13) || OperatingSystem.IsMacCatalystVersionAtLeast(13))
                    {
                        // Universal link delivered to SceneWillConnect after app launch
                        ios.SceneWillConnect((scene, sceneSession, sceneConnectionOptions)
                            => HandleAppLink(sceneConnectionOptions.UserActivities.ToArray()
                                .FirstOrDefault(a => a.ActivityType == Foundation.NSUserActivityType.BrowsingWeb)));

                        // Universal link delivered to SceneContinueUserActivity when the app is running or suspended
                        ios.SceneContinueUserActivity((scene, userActivity) => HandleAppLink(userActivity));
                    }
                });
#endif
            });

#if DEBUG
        builder.Logging.AddDebug();
#endif

        return builder.Build();
    }

#if IOS || MACCATALYST
    static bool HandleAppLink(Foundation.NSUserActivity? userActivity)
    {
        if (userActivity is not null && userActivity.ActivityType == Foundation.NSUserActivityType.BrowsingWeb && userActivity.WebPageUrl is not 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.Current?.SendOnAppLinkRequestReceived(uri);
    }
}

Quando iOS apre l'app come risultato di un collegamento universale, l'oggetto NSUserActivity avrà una ActivityType proprietà con un valore .BrowsingWeb La proprietà dell'oggetto WebPageUrl attività conterrà l'URL a cui l'utente vuole accedere. L'URL può essere passato alla App classe con il SendOnAppLinkRequestReceived metodo .

Nota

Se non usi Scene nell'app per il supporto multi-finestra, puoi omettere i gestori del ciclo di vita per i metodi Scene.

App Nella classe eseguire l'override del OnAppLinkRequestReceived metodo per ricevere ed elaborare l'URL:

namespace MyNamespace;

public partial class App : Application
{
    public App()
    {
        InitializeComponent();

        MainPage = new AppShell();
    }

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

        // Show an alert to test that the app link was received.
        await Dispatcher.DispatchAsync(async () =>
        {
            await Windows[0].Page!.DisplayAlert("App link received", uri.ToString(), "OK");
        });

        Console.WriteLine("App link: " + uri.ToString());
    }
}

Nell'esempio precedente, l'override OnAppLinkRequestReceived visualizza l'URL del collegamento dell'app. In pratica, il collegamento all'app deve portare gli utenti direttamente al contenuto rappresentato dall'URL, senza richieste, account di accesso o altre interruzioni. Di conseguenza, l'override OnAppLinkRequestReceived è la posizione da cui richiamare lo spostamento al contenuto rappresentato dall'URL.

Avviso

I collegamenti universali offrono un potenziale vettore di attacco nella tua app, quindi assicurati di convalidare tutti i parametri URL e rimuovere eventuali URL in formato non valido.

Per altre informazioni, vedi Supporto dei collegamenti universali nella tua app in developer.apple.com.

Importante

In iOS i collegamenti universali devono essere testati in un dispositivo anziché in un simulatore.

Per testare un collegamento universale, incollare un collegamento nell'app Note e premerelo a lungo (su iOS) o fare clic su di esso (su macOS) per individuare le scelte disponibili per seguire il collegamento. A condizione che i collegamenti universali siano stati configurati correttamente, la scelta di aprirla nell'app e in Safari verrà visualizzata. La scelta imposta il comportamento predefinito nel dispositivo quando si seguono collegamenti universali da questo dominio. Per modificare questa scelta predefinita, ripetere i passaggi e fare una scelta diversa.

Nota

L'immissione dell'URL in Safari non aprirà mai l'app. Safari accetterà invece questa azione come navigazione diretta. A condizione che un utente si trova nel dominio dopo l'esplorazione diretta, il sito visualizzerà un banner per aprire l'app.

In iOS è possibile testare i collegamenti universali con i test di diagnostica dei domini associati nelle impostazioni di sviluppo:

  1. Abilitare la modalità sviluppatore in Impostazioni. Per altre informazioni, vedere Abilitazione della modalità sviluppatore in un dispositivo in developer.apple.com.
  2. In Impostazioni > Sviluppatore scorrere fino ai collegamenti universali e abilitare Sviluppo domini associati.
  3. Aprire Diagnostica e digitare l'URL. Si riceverà quindi un feedback su se il collegamento è valido per un'app installata.

Spesso, i collegamenti universali non validi sono il risultato della applinks configurazione non corretta.

Per consigli sulla risoluzione dei problemi, vedere Debug di collegamenti universali in developer.apple.com.