Универсальные ссылки Apple

Часто желательно подключить веб-сайт и мобильное приложение, чтобы ссылки на веб-сайт запускали мобильное приложение и отображали содержимое в мобильном приложении. Связывание приложений, которое также называется глубоким связыванием, — это метод, позволяющий мобильному устройству реагировать на URL-адрес и запускать содержимое в мобильном приложении, представленном URL-адресом.

На платформах Apple глубокие ссылки называются универсальными ссылками. Когда пользователь нажимает на универсальную ссылку, система перенаправляет ссылку непосредственно в приложение без маршрутизации через Safari или веб-сайт. Эти ссылки могут быть основаны на пользовательской схеме, например myappname://, или могут использовать схему HTTP или HTTPS. Например, щелкнув ссылку на веб-сайте рецепта, откроется мобильное приложение, связанное с этим веб-сайтом, а затем отобразится конкретный рецепт для пользователя. Пользователи, у которых нет установленного приложения, принимают содержимое на веб-сайте. В этой статье рассматриваются универсальные ссылки, использующие схему HTTPS.

Приложения iOS для .NET MAUI поддерживают универсальные ссылки. Для этого требуется размещение JSON-файла в домене, в котором описывается связь с приложением. Это позволяет Apple проверить, что приложение, пытающееся обработать URL-адрес, имеет право на домен URL-адресов, чтобы предотвратить перехват вредоносных приложений ссылок приложения.

Процесс обработки универсальных ссылок Apple в приложении .NET MAUI iOS или Mac Catalyst выглядит следующим образом:

Дополнительные сведения см. в статье "Разрешение приложениям и веб-сайтам ссылки на содержимое " на developer.apple.com. Сведения об определении пользовательской схемы URL-адресов для приложения см. в разделе "Определение пользовательской схемы URL-адресов для приложения " на developer.apple.com.

Создание и размещение файла связанных доменов

Чтобы связать веб-сайт с приложением, необходимо разместить связанный файл домена на веб-сайте. Связанный файл домена — это JSON-файл, который должен размещаться в домене в следующем расположении: https://domain.name/.well-known/apple-app-site-association

В следующем формате JSON показано содержимое типичного файла связанных доменов:

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

appID Ключи apps должны указывать идентификаторы приложений для приложений, доступных для использования на веб-сайте. Значения этих ключей состоят из префикса идентификатора приложения и идентификатора пакета.

Внимание

Связанный файл домена должен размещаться с https допустимым сертификатом и не перенаправлять.

Дополнительные сведения см. в разделе "Поддержка связанных доменов " на developer.apple.com.

Добавление прав связанных доменов в приложение

После размещения связанного файла домена в домене необходимо добавить в приложение право связанных доменов. Когда пользователь устанавливает приложение, iOS пытается скачать связанный файл домена и проверить домены в вашем праве.

Назначение связанных доменов указывает список доменов, с которым связано приложение. Это право должно быть добавлено в файл Entitlements.plist в приложении. Дополнительные сведения о добавлении прав в iOS см. в разделе "Права". Дополнительные сведения о добавлении прав на Mac Catalyst см. в разделе "Права".

Назначение определяется с помощью com.apple.developer.associated-domains ключа типа ArrayString:

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

Дополнительные сведения об этом праве см. в разделе "Связанные домены" на developer.apple.com.

Кроме того, можно изменить файл проекта (CSPROJ), чтобы добавить право в <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>

В этом примере замените правильное applinks:recipe-app.com значение для домена. Убедитесь, что вы включаете только нужный поддомен и домен верхнего уровня. Не включать компоненты пути и запроса или косую черту (/).

Примечание.

В iOS 14+ и macOS 11+ приложения больше не отправляют запросы на apple-app-site-association файлы непосредственно на веб-сервер. Вместо этого они отправляют запросы в управляемую Apple сеть доставки содержимого (CDN), выделенную для связанных доменов.

Добавление возможностей связанных доменов в идентификатор приложения

После добавления права связанных доменов в приложение необходимо добавить связанные домены в идентификатор приложения для приложения в учетной записи разработчика Apple. Это необходимо, так как все права, определенные в приложении, также должны быть добавлены в качестве возможностей в идентификатор приложения для вашего приложения в учетной записи разработчика Apple.

Чтобы добавить в идентификатор приложения возможность связанных доменов, выполните следующие действия.

  1. В веб-браузере войдите в учетную запись разработчика Apple и перейдите на страницу сертификатов, идентификаторов и профилей .

  2. На странице "Сертификаты", "Идентификаторы и профили" выберите вкладку "Идентификаторы".

  3. На странице "Идентификаторы" выберите идентификатор приложения, соответствующий приложению.

  4. На странице "Изменение конфигурации идентификатора приложения" включите возможность связанных доменов и нажмите кнопку "Сохранить".

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

  5. В диалоговом окне "Изменение возможностей приложений" нажмите кнопку "Подтвердить".

После обновления идентификатора приложения необходимо создать и скачать обновленный профиль подготовки.

Примечание.

Если вы позже удалите из приложения права связанных доменов, необходимо обновить конфигурацию идентификатора приложения в учетной записи разработчика Apple.

Когда пользователь активирует универсальную ссылку, iOS и Mac Catalyst запускают приложение и отправляют его NSUserActivity объект. Этот объект можно запросить, чтобы определить, как запущено приложение, и определить, какие действия следует предпринять. Это должно выполняться в FinishedLaunching делегатах жизненного цикла и ContinueUserActivity их жизненном цикле. Делегат FinishedLaunching вызывается при запуске приложения, и ContinueUserActivity делегат вызывается при запуске или приостановке приложения. Дополнительные сведения о делегатах жизненного цикла см. в разделе "События жизненного цикла платформы".

Чтобы ответить на вызываемый делегат жизненного цикла iOS, вызовите ConfigureLifecycleEvents метод объекта MauiAppBuilder в методе CreateMauiapp класса MauiProgram . Затем вызовите ILifecycleBuilderAddiOS метод и укажите Action обработчик для требуемого делегата:

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

Когда iOS открывает приложение в результате универсальной ссылки, NSUserActivity объект будет иметь ActivityType свойство со значением BrowsingWeb. Свойство объекта WebPageUrl действия будет содержать URL-адрес, к которому пользователь хочет получить доступ. URL-адрес можно передать App в класс с SendOnAppLinkRequestReceived помощью метода.

Примечание.

Если вы не используете Сцены в приложении для поддержки нескольких окон, можно опустить обработчики жизненного цикла для методов Сцены.

App В классе переопределите OnAppLinkRequestReceived метод для получения и обработки 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());
    }
}

В приведенном выше OnAppLinkRequestReceived примере переопределение отображает URL-адрес ссылки приложения. На практике ссылка приложения должна принимать пользователей непосредственно к содержимому, представленному URL-адресом, без каких-либо запросов, имен входа или других прерываний. OnAppLinkRequestReceived Поэтому переопределение — это расположение, из которого необходимо вызвать навигацию к содержимому, представленному URL-адресом.

Предупреждение

Универсальные ссылки предлагают потенциальный вектор атаки в приложение, поэтому убедитесь, что вы проверяете все параметры URL-адреса и дис карта любые неправильные URL-адреса.

Дополнительные сведения см. в разделе "Поддержка универсальных ссылок" в приложении на developer.apple.com.

Внимание

В iOS универсальные ссылки должны тестироваться на устройстве, а не на симуляторе.

Чтобы проверить универсальную ссылку, вставьте ссылку в приложение "Заметки" и нажмите ее (в iOS) или щелкните ее (в macOS), чтобы узнать, какие варианты можно выбрать для перехода по ссылке. Если универсальные ссылки настроены правильно, появится выбор для открытия в приложении и в Safari. Вы будете задавать поведение по умолчанию на устройстве при выполнении универсальных ссылок из этого домена. Чтобы изменить этот выбор по умолчанию, повторите шаги и внесите другой выбор.

Примечание.

Ввод URL-адреса в Safari никогда не откроется приложение. Вместо этого Safari примет это действие как прямую навигацию. При условии, что пользователь находится в вашем домене после перехода туда напрямую, ваш сайт отобразит баннер для открытия приложения.

В iOS можно протестировать универсальные ссылки с помощью диагностических тестов связанных доменов в параметрах разработчика:

  1. Включите режим разработчика в Параметры. Дополнительные сведения см. в разделе "Включение режима разработчика" на устройстве на developer.apple.com.
  2. В Параметры > разработчик прокрутите страницу до универсальных ссылок и включите разработку связанных доменов.
  3. Откройте диагностику и введите URL-адрес. Затем вы получите отзыв о том, является ли ссылка допустимой для установленного приложения.

Часто недопустимые универсальные ссылки являются результатом applinks неправильной настройки.

Рекомендации по устранению неполадок см. в статье об отладке универсальных ссылок на developer.apple.com.