iOS シミュレーターと Android エミュレーターからローカル Web サービスに接続する
モバイル アプリケーションの多くが Web サービスを使用します。 開発フェーズ中では、Web サービスをローカルに展開して、iOS シミュレーターまたは Android エミュレーター内で実行しているモバイル アプリケーションからそれを使うことは一般的です。 これにより、ホストされているエンドポイントに Web サービスを展開する必要がなくなります。また、モバイル アプリケーションと Web サービスの両方がローカルで実行されるため、わかりやすいデバッグ エクスペリエンスが実現します。
iOS シミュレーターまたは Android エミュレーターで実行されているモバイル アプリケーションでは、次のように、ローカルで実行されているか、HTTP 経由で公開されている ASP.NET Core Web サービスを使用できます。
- iOS シミュレーターで実行されているアプリケーションは、ご自分のコンピューターの IP アドレス、または
localhost
ホスト名を使って、ローカルの HTTP Web サービスに接続できます。 たとえば、相対 URI/api/todoitems/
を使って GET 操作を公開しているローカル HTTP Web サービスがある場合、iOS シミュレーターで実行されているアプリケーションでは、http://localhost:<port>/api/todoitems/
に GET 要求を送信することでその操作を使用できます。 - Android エミュレーターで実行されているアプリケーションでは、ホスト ループバック インターフェイスに対する別名である
10.0.2.2
アドレス (開発用マシンでは127.0.0.1
) 経由でローカル HTTP Web サービスに接続できます。 たとえば、相対 URI/api/todoitems/
を使って GET 操作を公開しているローカル HTTP Web サービスがある場合、Android エミュレーターで実行されているアプリケーションでは、http://10.0.2.2:<port>/api/todoitems/
に GET 要求を送信することでその操作を使用できます。
ただし、iOS シミュレーターまたは Android エミュレーターで実行されているアプリケーションで、HTTPS 経由で公開されているローカル Web サービスを使用する場合は、追加の作業が必要です。 このシナリオ用のプロセスは次のようになります。
- ご自身のコンピューター上に自己署名済み開発証明書を作成します。 詳しくは、「Create a development certificate (開発証明書を作成する)」をご覧ください。
- デバッグ ビルド用に適切な
HttpClient
ネットワーク スタックを使うようプロジェクトを構成します。 詳細については、「Configure your project (プロジェクトを構成する)」をご覧ください。 - ご自分のローカル コンピューターのアドレスを指定します。 詳細については、「Specify the local machine address (ローカル コンピューターのアドレスを指定する)」をご覧ください。
- ローカル開発証明書のセキュリティ チェックをバイパスします。 詳細については、「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 を有効にする」をご覧ください。
プロジェクトを構成する
iOS および Android 上で実行する Xamarin アプリケーションでは、HttpClient
クラスでどのネットワーク スタックを使うか指定できます。選択はマネージド ネットワーク スタックまたはネイティブ ネットワーク スタックです。 マネージド スタックには既存の .NET コードとの互換性が高いレベルで備わっていますが、TLS 1.0 に制限されていて、低速になり実行可能ファイルのサイズがより大きくなる可能性があります。 ネイティブ スタックはより高速で、よりセキュリティに優れていますが、HttpClient
クラスのすべての機能が備わっていない場合があります。
iOS
iOS 上で実行される Xamarin アプリケーションでは、マネージド ネットワーク スタック、またはネイティブの CFNetwork
または NSUrlSession
ネットワーク スタックを使用できます。 既定では、新しい iOS プラットフォームのプロジェクトでは NSUrlSession
ネットワーク スタックが使われ、TLS 1.2 がサポートされ、またパフォーマンスの向上と実行可能ファイルのサイズの縮小のためにネイティブ API が使われます。 詳細については、「HttpClient and SSL/TLS implementation selector for iOS/macOS (iOS/macOS 用の HttpClient と SSL/TLS の実装セレクター)」をご覧ください。
Android
Android 上で実行される Xamarin アプリケーションでは、マネージド HttpClient
ネットワーク スタック、またはネイティブの AndroidClientHandler
ネットワーク スタックを使用できます。 既定では、新しい Android プラットフォームのプロジェクトでは AndroidClientHandler
ネットワーク スタックが使われ、TLS 1.2 がサポートされ、またパフォーマンスの向上と実行可能ファイルのサイズの縮小のためにネイティブ API が使われます。 Android のネットワーク スタックについて詳しくは、「Android 用の HttpClient スタックと SSL/TLS の実装セレクター」をご覧ください。
ローカル コンピューターのアドレスを指定する
iOS シミュレーターと Android エミュレーターのどちらも、ローカル コンピューター上で実行されているセキュリティで保護された Web サービスにアクセスできます。 ただし、ローカル コンピューターのアドレスはそれぞれで異なります。
iOS
iOS シミュレーターでは、ホスト コンピューターのネットワークを使います。 そのため、シミュレーターで実行されているアプリケーションでは、コンピューターの IP アドレス、または localhost
ホスト名を使って、ローカル コンピューター上で実行されている Web サービスに接続できます。 たとえば、相対 URI /api/todoitems/
を使って GET 操作を公開しているローカルのセキュリティで保護された Web サービスがある場合、iOS シミュレーターで実行されているアプリケーションでは、https://localhost:<port>/api/todoitems/
に GET 要求を送信することでその操作を使用できます。
Note
Windows から iOS シミュレーターでモバイル アプリケーションを実行している場合、アプリケーションは Windows 用のリモートの iOS シミュレーターで表示されます。 ただし、アプリケーションはペアリング済みの Mac 上で実行されます。 そのため、Mac 上で実行されている iOS アプリケーション用の、Windows で実行されている Web サービスへの localhost アクセスはありません。
Android
Android エミュレーターの各インスタンスは、開発用コンピューターのネットワーク インターフェイスから分離され、仮想ルーターの背後で実行されます。 そのため、エミュレートされたデバイスでは、開発用コンピューターやネットワーク上のその他のエミュレーター インスタンスを確認できません。
ただし、各エミュレーターの仮想ルーターで、事前に割り当てられたアドレスを含む特殊なネットワーク空間が管理されます。ここで、10.0.2.2
アドレスはホスト ループバック インターフェイス (開発用コンピューター上の 127.0.0.1) の別名です。 そのため、相対 URI /api/todoitems/
を使って GET 操作を公開しているローカルのセキュリティで保護された Web サービスがある場合、Android エミュレーターで実行されているアプリケーションでは、https://10.0.2.2:<port>/api/todoitems/
に GET 要求を送信することでその操作を使用できます。
オペレーティング システムを検出する
DeviceInfo
クラスを使用して、アプリケーションが実行されているプラットフォームを検出することができます。 次に、ローカルのセキュリティで保護された Web サービスへのアクセスを実現する適切なホスト名は、次のように設定できます。
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
クラスの詳細については、「Xamarin.Essentials: デバイス情報」を参照してください。
証明書のセキュリティ チェックをバイパスする
iOS シミュレーターまたは Android エミュレーターで実行されているアプリケーションからローカルのセキュリティで保護された Web サービスを呼び出そうとすると、各プラットフォーム上でマネージド ネットワーク スタックを使っている場合でも、HttpRequestException
がスローされます。 これは、ローカルの HTTPS 開発証明書が自己署名であり、自己署名された証明書は iOS または Android で信頼されないためです。 したがって、アプリケーションでローカルのセキュリティで保護された Web サービスを使用するときに、SSL エラーを無視する必要があります。 iOS と Android でマネージドとネイティブ両方のネットワーク スタックを使っている場合、HttpClientHandler
オブジェクトの ServerCertificateCustomValidationCallback
プロパティを、ローカルの HTTPS 開発証明書に向けた証明書のセキュリティ チェックの結果を無視するコールバックに設定することで、これを実現できます。
// This method must be in a class in a platform project, even if
// the HttpClient object is constructed in a shared project.
public HttpClientHandler GetInsecureHandler()
{
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
{
if (cert.Issuer.Equals("CN=localhost"))
return true;
return errors == System.Net.Security.SslPolicyErrors.None;
};
return handler;
}
このコード例では、検証が行われた証明書が localhost
証明書ではない場合に、サーバー証明書の検証結果が返されます。 この証明書に対して、検証結果が無視され、証明書が有効であることを示す true
が返されます。 生成される HttpClientHandler
オブジェクトを、デバッグ ビルド用に HttpClient
コンストラクターに対する引数として渡す必要があります。
#if DEBUG
HttpClientHandler insecureHandler = GetInsecureHandler();
HttpClient client = new HttpClient(insecureHandler);
#else
HttpClient client = new HttpClient();
#endif
HTTP クリアテキスト トラフィックを有効にする
必要に応じて、クリアテキストの HTTP トラフィックを許可するように、iOS と Android のプロジェクトを構成できます。 バックエンド サービスが HTTP トラフィックを許可するように構成されている場合は、ベース URL で HTTP を指定した後、クリアテキスト トラフィックを許可するようにプロジェクトを構成できます。
public static string BaseAddress =
DeviceInfo.Platform == DevicePlatform.Android ? "http://10.0.2.2:5000" : "http://localhost:5000";
public static string TodoItemsUrl = $"{BaseAddress}/api/todoitems/";
iOS ATS のオプトアウト
iOS でクリアテキストのローカル トラフィックを有効にするには、以下を Info.plist ファイルに追加することにより、ATS をオプトアウトする必要があります。
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
Android のネットワーク セキュリティ構成
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>
その後、Android マニフェストの application ノードで networkSecurityConfig プロパティを構成します。
<?xml version="1.0" encoding="utf-8"?>
<manifest>
<application android:networkSecurityConfig="@xml/network_security_config">
...
</application>
</manifest>
ビルド アクションが AndroidResource として設定されていることを確認します。それ以外の場合、XML ファイルはビルド時に見つかりません。