Compartir a través de


Conexión a servicios web locales desde simuladores de iOS y emuladores de Android

Browse sample. Examinar el ejemplo

Muchas aplicaciones móviles y de escritorio consumen servicios web. Durante la fase de desarrollo de software, es habitual implementar un servicio web localmente y consumirlo desde una aplicación que se ejecuta en el emulador de Android o en el simulador de iOS. Esto evita tener que implementar el servicio web en un punto de conexión hospedado y permite una experiencia de depuración sencilla porque la aplicación y el servicio web se ejecutan localmente.

Las aplicaciones de interfaz de usuario de aplicaciones multiplataforma de .NET (.NET MAUI) que se ejecutan en Windows o MacCatalyst pueden consumir servicios web de ASP.NET Core que se ejecutan localmente a través de HTTP o HTTPS sin ningún trabajo adicional, siempre que haya confiado en el certificado de desarrollo. Sin embargo, se requiere trabajo adicional cuando la aplicación se ejecuta en el emulador de Android o en el simulador de iOS, y el proceso es diferente en función de si el servicio web se ejecuta a través de HTTP o HTTPS.

Dirección del equipo local

El emulador de Android y el simulador de iOS proporcionan acceso a los servicios web que se ejecutan a través de HTTP o HTTPS en la máquina local. Sin embargo, la dirección de la máquina local es diferente en cada uno.

Android

Cada instancia del emulador de Android está aislada de las interfaces de red de la máquina de desarrollo y se ejecuta detrás de un enrutador virtual. Por lo tanto, un dispositivo emulado no puede ver su máquina de desarrollo u otras instancias del emulador en la red.

Sin embargo, el enrutador virtual de cada emulador administra un espacio de red especial que incluye direcciones asignadas previamente, donde la dirección 10.0.2.2 es un alias a la interfaz de bucle invertido del host (127.0.0.1 en la máquina de desarrollo). Por tanto, dado un servicio web local que expone una operación GET a través del identificador URI relativo de /api/todoitems/, una aplicación que se ejecuta en el emulador de Android puede consumir la operación al enviar una solicitud GET a http://10.0.2.2:<port>/api/todoitems/ o https://10.0.2.2:<port>/api/todoitems/.

iOS

El simulador de iOS usa la red de la máquina host. Por tanto, las aplicaciones que se ejecutan en el simulador pueden conectarse a servicios web que se ejecutan en el equipo local a través de la dirección IP de las máquinas o mediante el nombre de host localhost. Por ejemplo, dado un servicio web local que expone una operación GET a través del identificador URI relativo de /api/todoitems/, una aplicación que se ejecuta en el simulador de iOS puede consumir la operación enviando una solicitud GET a http://localhost:<port>/api/todoitems/ o https://localhost:<port>/api/todoitems/.

Nota:

Al ejecutar una aplicación de .NET MAUI en el simulador de iOS desde Windows, la aplicación se muestra en el simulador remoto de iOS para Windows. Sin embargo, la aplicación se ejecuta en el equipo Mac emparejado. Por tanto, no hay acceso localhost a un servicio web que se ejecuta en Windows para una aplicación iOS que se ejecuta en un equipo Mac.

Servicios web locales que se ejecutan a través de HTTP

Una aplicación de .NET MAUI que se ejecuta en el emulador de Android o en el simulador de iOS puede consumir un servicio web de ASP.NET Core que se ejecuta localmente a través de HTTP. Esto se puede lograr configurando el proyecto de aplicación de .NET MAUI y el proyecto de servicio web de ASP.NET Core para permitir el tráfico HTTP de texto no cifrado.

En el código que define la dirección URL del servicio web local en la aplicación de .NET MAUI, asegúrese de que la dirección URL del servicio web especifique el esquema HTTP y el nombre de host correcto. La clase DeviceInfo se puede usar para detectar la plataforma en la que se ejecuta la aplicación. Después, puede establecer el nombre de host correcto de la siguiente manera:

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

Para obtener más información sobre la clase DeviceInfo, consulte Información del dispositivo.

Además, para ejecutar la aplicación en Android, debe agregar la configuración de seguridad de red necesaria y, para ejecutar la aplicación en iOS, debe optar por no participar en Apple Transport Security (ATS). Para más información, consulte Configuración de seguridad de red de Android y configuración de ATS de iOS.

También debe asegurarse de que el servicio web ASP.NET Core esté configurado para permitir el tráfico HTTP. Esto se puede lograr al agregar un perfil HTTP a la sección profiles de launchSettings.json en el proyecto de servicio web de ASP.NET Core:

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

Una aplicación .NET MAUI que se ejecuta en el emulador de Android o en el simulador de iOS puede consumir un servicio web de ASP.NET Core que se ejecuta localmente a través de HTTP, siempre que el servicio web se inicie con el perfil http.

Configuración de seguridad de red de Android

Para habilitar el tráfico local de texto no cifrado en Android, debe crear un archivo de configuración de seguridad de red. Esto se puede lograr al agregar un nuevo archivo XML denominado network_security_config.xml a la carpeta Platforms\Android\Resources\xml en el proyecto de aplicación de .NET MAUI. El archivo XML debe especificar la configuración siguiente:

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

Nota:

Asegúrese de que la acción de compilación del archivo network_security_config.xml esté establecida en AndroidResource.

Después, configure la propiedad networkSecurityConfig en el nodo de aplicación del archivo Platforms\Android\AndroidManifest.xml en el proyecto de aplicación de .NET MAUI:

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

Para más información sobre los archivos de configuración de seguridad de red, consulte Configuración de seguridad de red en developer.android.com.

Configuración de ATS de iOS

Para habilitar el tráfico local de texto no cifrado en iOS, debe optar por no participar en Apple Transport Security (ATS) en la aplicación .NET MAUI. Esto se puede lograr al agregar la siguiente configuración al archivo Platforms\iOS\Info.plist en el proyecto de aplicación de .NET MAUI:

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

Para obtener más información sobre ATS, consulte Prevención de conexiones de red no seguras en developer.apple.com.

Servicios web locales que se ejecutan a través de HTTPS

Una aplicación de .NET MAUI que se ejecuta en el emulador de Android o en el simulador de iOS puede consumir un servicio web de ASP.NET Core que se ejecuta localmente a través de HTTPS. El proceso para habilitar esto es el siguiente:

  1. Confíe en el certificado de desarrollo autofirmado en la máquina. Para más información, consulte Confiar en el certificado de desarrollo.
  2. Especifique la dirección de la máquina local. Para más información, consulte Especificar la dirección de la máquina local.
  3. Omita la comprobación de seguridad del certificado de desarrollo local. Para más información, consulte Omitir la comprobación de seguridad del certificado.

Cada elemento se explicará por turnos.

Confiar en el certificado de desarrollo

Al instalar el SDK de .NET Core, se instala el certificado de desarrollo HTTPS de ASP.NET Core en el almacén de certificados de usuario local. Sin embargo, aunque el certificado se ha instalado, no es de confianza. Para confiar en el certificado, realice el siguiente paso puntual para ejecutar la herramienta dev-certs de dotnet:

dotnet dev-certs https --trust

El siguiente comando proporciona ayuda sobre la herramienta dev-certs:

dotnet dev-certs https --help

De forma alternativa, cuando se ejecuta un proyecto de ASP.NET Core 2.1 (o posterior) que usa HTTPS, Visual Studio detecta si falta el certificado de desarrollo y se ofrece a instalarlo, y confía en él.

Nota:

El certificado de desarrollo HTTPS de ASP.NET Core es autofirmado.

Para más información sobre cómo habilitar HTTPS local en la máquina, consulte Habilitar HTTPS local.

Especificar la dirección de la máquina local

En el código que define la dirección URL del servicio web local en la aplicación de .NET MAUI, asegúrese de que la dirección URL del servicio web especifique el esquema HTTPS y el nombre de host correcto. La clase DeviceInfo se puede usar para detectar la plataforma en la que se ejecuta la aplicación. Después, puede establecer el nombre de host correcto de la siguiente manera:

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

Para obtener más información sobre la clase DeviceInfo, consulte Información del dispositivo.

Omitir la comprobación de seguridad de certificado

Si se intenta invocar un servicio web seguro local desde una aplicación de .NET MAUI que se ejecuta en un emulador de Android, se producirá un mensaje java.security.cert.CertPathValidatorException que indica que no se ha encontrado el anclaje de confianza para la ruta de acceso de certificación. Del mismo modo, si intenta invocar un servicio web seguro local desde una aplicación de .NET MAUI que se ejecuta en un simulador de iOS, se producirá un error NSURLErrorDomain con un mensaje que indica que el certificado del servidor no es válido. Estos errores se producen porque el certificado de desarrollo HTTPS local está autofirmado y los certificados autofirmados no son de confianza para Android o iOS. Por tanto, es necesario omitir los errores SSL cuando una aplicación consume un servicio web seguro local.

Esto se puede lograr pasando versiones configuradas de las clases nativas HttpMessageHandler al constructor HttpClient, lo que indica a la clase HttpClient que confíe en la comunicación de localhost a través de HTTPS. La clase HttpMessageHandler es una clase abstracta, cuya implementación en Android la proporciona la clase AndroidMessageHandler y cuya implementación en iOS la proporciona la clase NSUrlSessionHandler.

En el ejemplo siguiente, se muestra una clase que configura la clase AndroidMessageHandler en Android y la clase NSUrlSessionHandler en iOS para confiar en la comunicación localhost a través de HTTPS:

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)
    {
        return url.StartsWith("https://localhost");
    }
#endif
}

En Android, el método GetPlatformMessageHandler devuelve un objeto AndroidMessageHandler. El método GetPlatformMessageHandler establece la propiedad ServerCertificateCustomValidationCallback del objeto AndroidMessageHandler en una devolución de llamada que omite el resultado de la comprobación de seguridad del certificado para el certificado de desarrollo HTTPS local.

En iOS, el método GetPlatformMessageHandler devuelve un objeto NSUrlSessionHandler que establece su propiedad TrustOverrideForUrl en un delegado denominado IsHttpsLocalHost, que coincide con la firma del delegado NSUrlSessionHandler.NSUrlSessionHandlerTrustOverrideForUrlCallback. El delegado IsHttpsLocalHost devuelve true cuando la dirección URL comienza por https://localhost.

A continuación, el objeto resultante HttpClientHandler se puede pasar como argumento al constructor HttpClient para las compilaciones de depuración:

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

Una aplicación de .NET MAUI que se ejecuta en el emulador de Android o en el simulador de iOS puede consumir un servicio web de ASP.NET Core que se ejecuta localmente a través de HTTPS.