Android エミュレーターと iOS シミュレーターからローカル Web サービスに接続する

Browse sample. サンプルを参照する

多くのモバイルおよびデスクトップ アプリは、Web サービスを使用します。 ソフトウェア開発フェーズでは、Web サービスをローカルにデプロイし、Android エミュレーターまたは iOS シミュレーター内で実行されているアプリからそれを使用するのが一般的です。 これにより、ホストされたエンドポイントに Web サービスをデプロイする必要がなくなり、アプリと Web サービスの両方がローカルで実行されることで、デバッグ エクスペリエンスが簡潔になります。

Windows または MacCatalyst 上で実行される .NET マルチプラットフォーム アプリ UI (.NET MAUI) アプリは、開発証明書を信頼していれば、HTTP または HTTPS を経由してローカルで実行されている ASP.NET Core Web サービスを、追加の作業なしで使用することができます。 ただし、そのアプリが Android エミュレーターまたは iOS シミュレーター内で実行されている場合は、追加の作業が必要です。そのプロセスは、Web サービスが HTTP または HTTPS 経由で実行されているかどうかによって異なります。

ローカル コンピューターのアドレス

Android エミュレーターと iOS シミュレーターはどちらも、ローカル コンピューター上で HTTP または HTTPS を経由して実行されている Web サービスへのアクセスが提供されています。 ただし、ローカル コンピューターのアドレスはそれぞれで異なります。

Android

Android エミュレーターの各インスタンスは、開発用コンピューターのネットワーク インターフェイスから分離され、仮想ルーターの背後で実行されます。 そのため、エミュレートされたデバイスでは、開発用コンピューターやネットワーク上のその他のエミュレーター インスタンスを確認できません。

ただし、各エミュレーターの仮想ルーターで、事前に割り当てられたアドレスを含む特殊なネットワーク空間が管理されます。ここで、10.0.2.2 アドレスはホスト ループバック インターフェイス (開発用コンピューター上の 127.0.0.1) の別名です。 したがって、相対 URI /api/todoitems/ を介して GET 操作を公開するローカル Web サービスがある場合、Android エミュレーター上で実行されているアプリは http://10.0.2.2:<port>/api/todoitems/ または https://10.0.2.2:<port>/api/todoitems/ に GET 要求を送信すると、その操作を使用することができます。

iOS

iOS シミュレーターでは、ホスト コンピューターのネットワークを使います。 したがって、シミュレーター内で実行されているアプリは、マシンの IP アドレスまたは localhost ホスト名を介して、ローカル コンピューター上で実行されている Web サービスに接続することができます。 たとえば、相対 URI /api/todoitems/ を介して GET 操作を公開するローカル Web サービスがある場合、iOS シミュレーター上で実行されているアプリは http://localhost:<port>/api/todoitems/ または https://localhost:<port>/api/todoitems/ に GET 要求を送信すると、その操作を使用することができます。

Note

Windows から iOS シミュレーター内で .NET MAUI アプリを実行すると、Windows 用リモート iOS シミュレーターにそのアプリが表示されます。 ただし、そのアプリはペアリングされた Mac 上で実行されています。 そのため、Mac 上で実行されている iOS アプリには、Windows 内で実行されている Web サービスへの localhost アクセスはありません。

HTTP 経由で実行されているローカル Web サービス

Android エミュレーターまたは iOS シミュレーター内で実行されている .NET MAUI アプリは、HTTP を経由してローカルで実行されている ASP.NET Core Web サービスを使用することができます。 これを実現するには、クリアテキスト HTTP トラフィックを許可するように .NET MAUI アプリ プロジェクトと ASP.NET Core Web サービス プロジェクトを構成します。

.NET MAUI アプリ内でローカル Web サービスの URL を定義するコードにおいて、その Web サービスの URL で HTTP スキームと正しいホスト名が指定されていることをご確認ください。 この DeviceInfo クラスを使用して、アプリが実行されているプラットフォームを検出することができます。 それから、正しいホスト名を次のように設定することができます。

public static string BaseAddress =
    DeviceInfo.Platform == DevicePlatform.Android ? "http://10.0.2.2:5000" : "http://localhost:5000";
public static string TodoItemsUrl = $"{BaseAddress}/api/todoitems/";

DeviceInfo クラスについて詳しくは、「デバイス情報」をご参照ください。

さらに、Android 上でそのアプリを実行するには、必要なネットワーク セキュリティ構成を追加する必要があります。また、iOS 上でそのアプリを実行するには、Apple Transport Security (ATS) をオプトアウトする必要があります。 詳しくは、「Android ネットワーク セキュリティの構成」と「iOS ATS の構成」をご参照ください。

ASP.NET Core Web サービスが、確実に HTTP トラフィックを許可するように構成されている必要があります。 これを実現するには、ASP.NET Core Web サービス プロジェクト内の launchSettings.jsonprofiles セクションに、HTTP プロファイルを追加します。

{
  ...
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "api/todoitems",
      "applicationUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    ...
  }
}

Android エミュレーターまたは iOS シミュレーター内で実行されている .NET MAUI アプリは、http プロファイルを使用して Web サービスが起動された場合、HTTP を経由してローカルで実行されている ASP.NET Core Web サービスを使用することができます。

Android のネットワーク セキュリティ構成

Android 上でクリアテキスト ローカル トラフィックを有効にするには、ネットワーク セキュリティ構成ファイルを作成する必要があります。 これを実現するには、.NET MAUI アプリ プロジェクト内の Platforms\Android\Resources\xml フォルダーに、network_security_config.xml という名前の新しい XML ファイルを追加します。 その XML ファイルで、次の構成を指定する必要があります。

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">10.0.2.2</domain>
  </domain-config>
</network-security-config>

Note

network_security_config.xml ファイルのビルド アクションが AndroidResource に設定されていることをご確認ください。

次に、.NET MAUI アプリ プロジェクト内の Platforms\Android\AndroidManifest.xml ファイル内の application ノード上で、networkSecurityConfig プロパティを構成します。

<?xml version="1.0" encoding="utf-8"?>
<manifest>
    <application android:networkSecurityConfig="@xml/network_security_config" ...>
        ...
    </application>
</manifest>

ネットワーク セキュリティ構成ファイルについて詳しくは、developer.android.com 上の「ネットワーク セキュリティ構成」をご参照ください。

iOS ATS の構成

iOS 上でクリアテキスト ローカル トラフィックを有効にするには、.NET MAUI アプリ内で Apple Transport Security (ATS) をオプトアウトする必要があります。 これを実現するには、.NET MAUI アプリ プロジェクト内の Platforms\iOS\Info.plist ファイルに、次の構成を追加します。

<key>NSAppTransportSecurity</key>    
<dict>
    <key>NSAllowsLocalNetworking</key>
    <true/>
</dict>

ATS について詳しくは、developer.apple.com 上の「Preventing Insecure Network Connections」をご参照ください。

HTTPS 経由で実行されているローカル Web サービス

Android エミュレーターまたは iOS シミュレーター内で実行されている .NET MAUI アプリは、HTTPS を経由してローカルで実行されている ASP.NET Core Web サービスを使用することができます。 これを有効にするプロセスは次のとおりです。

  1. マシン上の自己署名開発証明書を信頼します。 詳しくは、「開発証明書を信頼する」をご参照ください。
  2. ご自分のローカル コンピューターのアドレスを指定します。 詳細については、「Specify the local machine address (ローカル コンピューターのアドレスを指定する)」をご覧ください。
  3. ローカル開発証明書のセキュリティ チェックをバイパスします。 詳細については、「Bypass the certificate security check (証明書のセキュリティ チェックをバイパスする)」をご覧ください。

それぞれの項目について順番に説明します。

開発証明書を信頼する

.NET Core SDK をインストールすると、ASP.NET Core HTTPS 開発証明書がローカル ユーザー証明書ストアにインストールされます。 ただし、証明書はインストールされましたが、信頼されていません。 証明書を信頼するには、次の 1 回限りの手順を実行して dotnet の dev-certs ツールを実行します。

dotnet dev-certs https --trust

次のコマンドにより、dev-certs ツールに関するヘルプが表示されます。

dotnet dev-certs https --help

または、HTTPS を使用する、ASP.NET Core 2.1 (またはそれ以降) のプロジェクトを実行する場合、Visual Studio によって開発証明書が不足しているかどうかが検出され、それをインストールして信頼するよう提案されます。

Note

ASP .NET Core HTTPS 開発証明書は自己署名です。

コンピューターでローカルの HTTPS を有効にする方法について詳しくは、「ローカル HTTPS を有効にする」をご覧ください。

ローカル コンピューターのアドレスを指定する

.NET MAUI アプリ内でローカル Web サービスの URL を定義するコード内で、その Web サービスの URL に HTTPS スキームと正しいホスト名が指定されていることをご確認ください。 この DeviceInfo クラスを使用して、アプリが実行されているプラットフォームを検出することができます。 それから、正しいホスト名を次のように設定することができます。

public static string BaseAddress =
    DeviceInfo.Platform == DevicePlatform.Android ? "https://10.0.2.2:5001" : "https://localhost:5001";
public static string TodoItemsUrl = $"{BaseAddress}/api/todoitems/";

DeviceInfo クラスについて詳しくは、「デバイス情報」をご参照ください。

証明書のセキュリティ チェックをバイパスする

Android エミュレーター内で実行されている .NET MAUI アプリから、ローカルのセキュリティで保護された Web サービスを呼び出そうとすると、証明書パスのトラスト アンカーが見つからないことを示すメッセージと共に java.security.cert.CertPathValidatorException がスローされます。 同様に、iOS シミュレーター内で実行されている .NET MAUI アプリからローカルのセキュリティで保護された Web サービスを呼び出そうとすると、そのサーバーの証明書が無効であることを示すメッセージと共に NSURLErrorDomain エラーが発生します。 これらのエラーは、ローカルの HTTPS 開発証明書が自己署名されており、かつ自己署名証明書が Android または iOS によって信頼されていないことが原因で発生します。 したがって、アプリがローカルのセキュリティで保護された Web サービスを使用する場合は、SSL エラーを無視する必要があります。

これを実現するには、構成されたバージョンのネイティブ HttpMessageHandler クラスを HttpClient コンストラクターに渡します。これにより、HTTPS 経由の localhost 通信を信頼するように HttpClient クラスに指示します。 この HttpMessageHandler クラスは抽象クラスであり、Android 上での実装は AndroidMessageHandler クラスによって提供され、iOS 上での実装は NSUrlSessionHandler クラスによって提供されます。

次の例では、Android 上の AndroidMessageHandler クラスと iOS 上の NSUrlSessionHandler クラスに対して、HTTPS 経由の localhost 通信を信頼するように構成するクラスを示します。

public class HttpsClientHandlerService
{
    public HttpMessageHandler GetPlatformMessageHandler()
    {
#if ANDROID
        var handler = new Xamarin.Android.Net.AndroidMessageHandler();
        handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
        {
            if (cert != null && cert.Issuer.Equals("CN=localhost"))
                return true;
            return errors == System.Net.Security.SslPolicyErrors.None;
        };
        return handler;
#elif IOS
        var handler = new NSUrlSessionHandler
        {
            TrustOverrideForUrl = IsHttpsLocalhost
        };
        return handler;
#else
     throw new PlatformNotSupportedException("Only Android and iOS supported.");
#endif
    }

#if IOS
    public bool IsHttpsLocalhost(NSUrlSessionHandler sender, string url, Security.SecTrust trust)
    {
        if (url.StartsWith("https://localhost"))
            return true;
        return false;
    }
#endif
}

Android 上では、この GetPlatformMessageHandler メソッドは AndroidMessageHandler オブジェクトを返します。 この GetPlatformMessageHandler メソッドは、ローカル HTTPS 開発証明書の証明書セキュリティ チェックの結果を無視するコールバックに、AndroidMessageHandler オブジェクト上の ServerCertificateCustomValidationCallback プロパティを設定します。

iOS 上では、この GetPlatformMessageHandler メソッドは NSUrlSessionHandler オブジェクトを返します。このオブジェクトは、その TrustOverrideForUrl プロパティを、NSUrlSessionHandler.NSUrlSessionHandlerTrustOverrideForUrlCallback デリゲートのシグネチャと一致する IsHttpsLocalHost という名前のデリゲートに設定します。 この IsHttpsLocalHost デリゲートは、URL が https://localhost で始まる場合に true を返します。

その結果の HttpClientHandler オブジェクトは、デバッグ ビルドの HttpClient コンストラクターに引数として渡すことができます。

#if DEBUG
            HttpsClientHandlerService handler = new HttpsClientHandlerService();
            HttpClient client = new HttpClient(handler.GetPlatformMessageHandler());
#else
            client = new HttpClient();
#endif

これで、Android エミュレーターまたは iOS シミュレーター内で実行されている .NET MAUI アプリは、 HTTPS を経由してローカルで実行されている ASP.NET Core Web サービスを使用することができます。