Compartilhar via


Links universais da Apple

É comum querer conectar um site e um aplicativo móvel para que os links em um site abram o aplicativo móvel e mostrem conteúdo diretamente nele. A vinculação de aplicativo, que também é conhecida como vinculação profunda, é uma técnica que permite que um dispositivo móvel responda a um URL e abra o conteúdo dentro de um aplicativo móvel representado pelo URL.

Nas plataformas da Apple, esses links profundos são chamados de links universais. Quando um usuário toca em um link universal, o sistema redireciona o link diretamente para o aplicativo, sem passar pelo Safari ou pelo site. Esses links podem ser baseados em um esquema personalizado, como myappname://, ou podem usar os esquemas HTTP ou HTTPS. Por exemplo, clicar em um link em um site de receitas abriria um aplicativo móvel associado a esse site e, em seguida, mostraria uma receita específica para o usuário. Os usuários que não têm o aplicativo instalado são levados para o conteúdo no site. Este artigo se concentra nos links universais que usam o esquema HTTPS.

Os aplicativos .NET MAUI para iOS são compatíveis com links universais. Para isso, é necessário hospedar um arquivo JSON de links de ativos digitais no domínio, descrevendo a relação com o aplicativo. Isso permite que a Apple verifique se o aplicativo que está tentando manipular uma URL é realmente proprietário do domínio das URLs para prevenir que aplicativos mal-intencionados interceptem seus links.

O processo para manipular links universais da Apple em um aplicativo .NET MAUI para iOS ou Mac Catalyst é o seguinte:

Para mais informações, confira artigo Permitir que aplicativos e sites se vinculem ao seu conteúdo disponível no site developer.apple.com. Para saber como definir um esquema de URL personalizado para o seu aplicativo, veja o artigo Definir um esquema de URL personalizado para o seu app disponível no site no developer.apple.com.

Criar e hospedar um arquivo de domínios associados

Para associar um site ao seu aplicativo, você precisará hospedar um arquivo de domínio associado em seu site. Esse arquivo de domínio associado é um arquivo JSON que deve estar hospedado em seu domínio no seguinte local: https://domain.name/.well-known/apple-app-site-association.

A seguir, o JSON mostra os conteúdos de um arquivo de domínios associados padrão:

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

As chaves apps e appID devem especificar os identificadores dos aplicativos que podem ser utilizados no site. Os valores dessas chaves são formados pelo prefixo do identificador do aplicativo e pelo identificador do pacote.

Importante

O arquivo de domínio associado deve ser hospedado usando https com um certificado válido e sem redirecionamentos.

Para mais informações, confira o tópico Suporte a domínios associados disponível no site developer.apple.com.

Adicionar o direito de domínios associados ao seu aplicativo

Após hospedar um arquivo de domínio associado em seu domínio, você precisará adicionar o direito de domínios associados ao seu aplicativo. Quando um usuário instala seu aplicativo, o iOS tenta baixar o arquivo de domínio associado e verificar os domínios presentes no seu direito.

O direito de domínios associados lista os domínios aos quais o aplicativo está associado. Esse direito deve ser adicionado ao arquivo Entitlements.plist em seu aplicativo. Para mais informações sobre como adicionar um direito ao iOS, confira Direitos. Para mais informações sobre como adicionar um direito ao Mac Catalyst, confira Direitos.

O direito é definido usando a chave com.apple.developer.associated-domains, do tipo Array de String:

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

Para mais informações sobre esse direito, confira o tópico Direitos de domínios associados disponível no site developer.apple.com.

Você também pode modificar o arquivo de projeto (.csproj) para adicionar o direito em um elemento <ItemGroup>:

<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>

Neste exemplo, substitua applinks:recipe-app.com pelo valor correto para o seu domínio. Inclua apenas o subdomínio desejado e o domínio primário. Não inclua componentes de caminho e consulta ou uma barra à direita (/).

Observação

No iOS 14+ e no macOS 11+, os aplicativos não enviam mais solicitações de arquivos apple-app-site-association diretamente ao seu servidor web. Em vez disso, as solicitações são enviadas para uma rede de distribuição de conteúdo (CDN) gerenciada pela Apple, dedicada a domínios associados.

Adicionar a funcionalidade de domínios associados à ID do Aplicativo

Depois de adicionar o direito de domínios associados ao seu aplicativo, você precisará adicionar a funcionalidade de domínios associados à ID do seu aplicativo em sua Conta de Desenvolvedor da Apple. Isso é necessário porque todos os direitos definidos em seu aplicativo também precisam ser adicionados como funcionalidades à ID do seu Aplicativo em sua Conta de Desenvolvedor da Apple.

Para adicionar a funcionalidade de domínios associados à ID do aplicativo:

  1. Em um navegador da Web, faça logon em sua Conta de Desenvolvedor da Apple e navegue até a página Certificados, IDs e Perfis.

  2. Na página Certificados, Identificadores e Perfis, selecione a guia Identificadores.

  3. Na página Identificadores, selecione a ID do Aplicativo que corresponde ao seu aplicativo.

  4. Na página Editar a Configuração da ID do Aplicativo, habilite a funcionalidade Domínios Associados e, em seguida, selecione o botão Salvar:

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

  5. Na caixa de diálogo Modificar Recursos do Aplicativo, selecione o botão Confirmar.

Depois de atualizar a ID do aplicativo, você precisará gerar e baixar um perfil de provisionamento atualizado.

Observação

Se posteriormente você remover o direito de domínios associados do seu aplicativo, precisará atualizar a configuração da ID do Aplicativo em sua Conta de Desenvolvedor da Apple.

Quando um usuário ativa um link universal, o iOS e o Mac Catalyst abrem seu aplicativo e enviam um objeto NSUserActivity. Esse objeto pode ser consultado para entender como seu aplicativo foi iniciado e qual ação tomar. Essa verificação deve ser feita nos delegados de ciclo de vida FinishedLaunching e ContinueUserActivity. O delegado FinishedLaunching é chamado quando o aplicativo é iniciado e o delegado ContinueUserActivity é chamado quando o aplicativo está em execução ou suspenso. Para mais informações sobre delegados de ciclo de vida, confira Eventos do ciclo de vida da plataforma.

Para responder a um delegado de ciclo de vida do iOS que está sendo chamado, chame o método ConfigureLifecycleEvents no objeto MauiAppBuilder no método CreateMauiapp da sua classe MauiProgram. Em seguida, no objeto ILifecycleBuilder, chame o método AddiOS e especifique o Action que registra um manipulador para o delegado necessário:

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 o iOS abre seu aplicativo por meio de um link universal, o objeto NSUserActivity terá uma propriedade ActivityType com um valor igual a BrowsingWeb. A propriedade WebPageUrl do objeto de atividade vai conter a URL que o usuário quer acessar. Essa URL pode ser encaminhada para a sua classe App usando o método SendOnAppLinkRequestReceived.

Observação

Se você não estiver utilizando o recurso Cenas no seu aplicativo para suporte a múltiplas janelas, pode ignorar os manipuladores de ciclo de vida para os métodos de Cena.

Em sua classe App, substitua o método OnAppLinkRequestReceived para receber e processar a URL:

namespace MyNamespace;

public partial class App : Application
{
    ...

    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());
    }
}

No exemplo acima, a substituição OnAppLinkRequestReceived exibe a URL do link do aplicativo. Na prática, o link do aplicativo deve levar os usuários diretamente ao conteúdo representado pela URL, sem solicitações, logins ou outras interrupções. Portanto, a substituição é o local a partir do qual invocar a navegação OnAppLinkRequestReceived para o conteúdo representado pela URL.

Aviso

Os links universais oferecem um vetor de ataque potencial em seu aplicativo, portanto, certifique-se de validar todos os parâmetros de URL e descartar as URLs malformadas.

Para mais informações, confira ao tópico Suporte a Links universais no seu aplicativo disponível no site developer.apple.com.

Importante

No iOS, é recomendável testar links universais em um dispositivo real, não em um Simulador.

Para testar um link universal, cole um link em seu aplicativo Notas e pressione e segure (no iOS) ou clique com o Control pressionado (no macOS) para ver as opções disponíveis. Se os links universais estiverem configurados corretamente, aparecerão as opções de abrir no aplicativo e no Safari. A opção escolhida definirá o comportamento padrão no seu dispositivo ao seguir os links universais desse domínio. Para alterar essa configuração padrão, repita o processo e escolha uma opção diferente.

Observação

Digitar a URL diretamente no Safari nunca abrirá o aplicativo. Em vez disso, o Safari interpretará essa ação como navegação direta. Se um usuário estiver no seu domínio após acessá-lo diretamente, seu site exibirá um banner para abrir o aplicativo.

No iOS, você pode testar seus links universais com os testes de diagnóstico de domínios associados nas configurações para desenvolvedores:

  1. Habilitar o modo desenvolvedor nas Configurações. Para mais informações, confira o tópico Ativando o modo desenvolvedor em um dispositivo disponível no site developer.apple.com.
  2. EmConfigurações> Desenvolvedor, vá até Links Universais e habilite Desenvolvimento de Domínios Associados.
  3. Abra o Diagnóstico e digite em sua URL. Você receberá um retorno indicando se o link é válido para algum aplicativo instalado.

Muitas vezes, links universais inválidos são causados por configurações incorretas do applinks.

Para saber como solucionar problemas, veja Depuração de links universais disponível no site developer.apple.com.