次の方法で共有


Apple ユニバーサル リンク

Web サイトとモバイル アプリを接続し、Web サイト上のリンクによってモバイル アプリが起動し、モバイル アプリにコンテンツが表示されるようにするのが望ましい場合がよくあります。 "ディープ リンク" とも呼ばれる "アプリ リンク" は、モバイル デバイスが URL に応答し、URL で表されるコンテンツをモバイル アプリで起動できるようにする手法です。

Apple プラットフォームでは、ディープ リンクは "ユニバーサル リンク" と呼ばれます。 ユーザーがユニバーサル リンクをタップすると、システムは Safari や Web サイトを介したルーティングを使用せずに、リンクをアプリに直接リダイレクトします。 これらのリンクでは、myappname:// などのカスタム スキームをベースにすることも、HTTP や HTTPS スキームを使用することもできます。 たとえば、レシピの Web サイトのリンクをクリックすると、その Web サイトに関連付けられているモバイル アプリが開き、特定のレシピがユーザーに表示されます。 アプリをインストールしていないユーザーは、Web サイト上のコンテンツに移動させられます。 この記事では、HTTPS スキームを使用するユニバーサル リンクに重点を置きます。

.NET MAUI iOS アプリでは、ユニバーサル リンクがサポートされています。 これには、アプリとのリレーションシップを記述するデジタル資産リンク JSON ファイルをドメイン上でホストする必要があります。 これにより、Apple は、URL を処理しようとしているアプリが URL の所有権を持っていることを確認し、悪意のあるアプリがアプリ リンクを妨害するのを防ぐことができます。

.NET MAUI iOS または Mac Catalyst アプリで Apple ユニバーサル リンクを処理するプロセスは以下のとおりです。

詳細については、developer.apple.com の「アプリと Web サイトがコンテンツへのリンクを行うことの許可」を参照してください。 アプリのカスタム URL スキームの定義については、developer.apple.com の「アプリのカスタム URL スキームの定義」を参照してください。

関連付けられたドメイン ファイルを作成してホストする

Web サイトをアプリに関連付けるには、Web サイト上で関連付けられたドメイン ファイルをホストする必要があります。 関連付けられたドメイン ファイルは、ドメイン上の場所 (https://domain.name/.well-known/apple-app-site-association) でホストする必要がある JSON ファイルです。

次の JSON は、一般的な関連付けられたドメイン ファイルの内容を示しています。

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

apps および appID キーでは、Web サイトで使用可能なアプリのアプリ識別子を指定する必要があります。 これらのキーの値は、アプリ識別子プレフィックスとバンドル識別子で構成されます。

重要

関連付けられたドメイン ファイルは、https と有効な証明書を使用してリダイレクトなしでホストする必要があります。

詳細については、developer.apple.com の「関連付けられたドメインのサポート」を参照してください。

関連付けられたドメイン エンタイトルメントをアプリに追加する

ドメイン上で関連付けられたドメイン ファイルをホストした後、関連付けられたドメイン エンタイトルメントをアプリに追加する必要があります。 ユーザーがアプリをインストールすると、iOS は関連付けられたドメイン ファイルのダウンロードとエンタイトルメント内のドメインの検証を試みます。

関連付けられているドメイン エンタイトルメントは、アプリが関連付けられているドメインの一覧を指定します。 このエンタイトルメントは、アプリの Entitlements.plist ファイルに追加する必要があります。 iOS でのエンタイトルメントの追加の詳細については、「エンタイトルメント」を参照してください。 Mac Catalyst でのエンタイトルメントの追加の詳細については、「エンタイトルメント」を参照してください。

エンタイトルメントは、StringArray 型の com.apple.developer.associated-domains キーを使用して定義されます。

<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 をドメイン用の正しい値に置き換えます。 目的のサブドメインと最上位ドメインのみを含めるように注意します。 パスおよびクエリ コンポーネントや末尾のスラッシュ (/) は含めないでください。

Note

iOS 14 以上と macOS 11 以上では、アプリは apple-app-site-association ファイルの要求を Web サーバーに直接送信しなくなりました。 代わりに、関連付けられたドメイン専用の Apple が管理するコンテンツ配信ネットワーク (CDN) に要求を送信します。

関連付けられたドメイン機能をアプリ ID に追加する

関連付けられたドメイン エンタイトルメントをアプリに追加した後、Apple Developer アカウントで、関連付けられたドメイン機能をアプリのアプリ ID にを追加する必要があります。 これが必要なのは、アプリで定義されているすべてのエンタイトルメントも、Apple Developer アカウントでアプリのアプリ ID に機能として追加する必要があるためです。

関連付けられたドメイン機能をアプリ ID に追加するには:

  1. Web ブラウザーで、Apple Developer アカウントにログインし、[証明書、ID、プロファイル] ページに移動します。

  2. [証明書、ID、プロファイル] ページで、[識別子] タブを選択します。

  3. [識別子] ページで、アプリに対応するアプリ ID を選択します。

  4. [App ID 構成の編集] ページで、関連付けられたドメイン機能を有効にして、[保存] ボタンを選択します。

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

  5. [アプリ機能の変更] ダイアログで、[確認] ボタンを選択します。

アプリのアプリ ID を更新したら、更新されたプロビジョニング プロファイルを生成してダウンロードする必要があります。

Note

関連付けられたドメイン エンタイトルメントを後でアプリから削除する場合は、Apple Developer アカウントでアプリ ID の構成を更新する必要があります。

ユーザーがユニバーサル リンクをアクティブにすると、iOS と Mac Catalyst によってアプリが起動され、それが NSUserActivity オブジェクトに送信されます。 このオブジェクトにはクエリを実行して、アプリがどのように起動されたかを決定し、実行するべきアクションを決定することができます。 これは、FinishedLaunching および ContinueUserActivity ライフサイクル デリゲートで実行する必要があります。 FinishedLaunching デリゲートはアプリの起動時に呼び出され、ContinueUserActivity デリゲートはアプリの実行中または中断時に呼び出されます。 ライフサイクル デリゲートの詳細については、「プラットフォーム ライフサイクル イベント」を参照してください。

呼び出されている iOS ライフサイクル デリゲートに応答するには、MauiProgram クラスの CreateMauiapp メソッド内の MauiAppBuilder オブジェクトに対して ConfigureLifecycleEvents メソッドを呼び出します。 次に、ILifecycleBuilder オブジェクトで AddiOS メソッドを呼び出して、必要なデリゲートのハンドラーを登録する 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 は、SendOnAppLinkRequestReceived メソッドを使用して App クラスに渡すことができます。

Note

アプリで複数ウィンドウのサポートに Scenes を使用していない場合は、Scene メソッドのライフサイクル ハンドラーを省略できます。

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 では、シミュレーター上ではなくデバイス上でユニバーサル リンクをテストする必要があります。

ユニバーサル リンクをテストするには、Notes アプリにリンクを貼り付けてそれを長押しするか (iOS の場合)、control キーを押しながらクリックして (macOS の場合)、リンクをフォローするための選択肢を確認します。 ユニバーサル リンクが正しく構成されている場合は、アプリと Safari で開くための選択肢が表示されます。 ここでの選択によって、デバイス上でこのドメインからユニバーサル リンクをフォローする際の既定の動作が設定されます。 この既定の選択を変更するには、手順を繰り返し、別の選択を行います。

Note

Safari に URL を入力しても、アプリが開くことはありません。 代わりに、Safari はこのアクションを直接のナビゲーションとして捉えます。 ユーザーが直接移動してドメイン上にいる場合、サイトはアプリを開くためのバナーを表示します。

iOS では、以下のように開発者設定で関連するドメイン診断テストを使用してユニバーサル リンクをテストできます。

  1. [設定] で開発者モードを有効にします。 詳細については、developer.apple.com の「デバイスでの開発者モードの有効化」を参照してください。
  2. [設定] > [開発者] で、[ユニバーサル リンク] までスクロールして [関連付けられたドメイン開発] を有効にします。
  3. [診断] を開き、URL を入力します。 するとインストールされたアプリでリンクが有効かどうかについてのフィードバックが提供されます。

多くの場合、無効なユニバーサル リンクは、applinks が誤って構成されていることが原因です。

トラブルシューティングのアドバイスについては、developer.apple.com の「ユニバーサル リンクのデバッグ」を参照してください。