Compartir a través de


Iniciador

Examinar ejemplo. Examinar el ejemplo

En este artículo se describe cómo puedes utilizar la interfaz ILauncher de .NET Multi-platform App UI (.NET MAUI). Esta interfaz permite a una aplicación abrir un URI por el sistema. Esta forma de abrir una aplicación se suele usar cuando se vincula profundamente a esquemas de URI personalizados de otra aplicación.

La implementación predeterminada de la interfaz ILauncher está disponible a través de la propiedad Launcher.Default. Tanto la interfaz ILauncher como la clase Launcher se encuentran en el espacio de nombres Microsoft.Maui.ApplicationModel.

Importante

Para abrir el navegador en un sitio web, use la API Browser en su lugar.

Comenzar

Para acceder a la funcionalidad del iniciador, se requiere la siguiente configuración específica de la plataforma.

Si desea usar vínculos profundos para abrir otras aplicaciones android, debe definir un filtro de intención en la aplicación. Esto se puede lograr agregando el siguiente XML al archivo Platforms/Android/AndroidManifest.xml:

<activity android:name="appName" android:exported="true">
    <intent-filter>
       <action android:name="android.intent.action.VIEW" />
       <category android:name="android.intent.category.DEFAULT" />
       <category android:name="android.intent.category.BROWSABLE" />
       <data android:scheme="lyft"/>
       <data android:scheme="fb"/>
       </intent-filter>
</activity>

Los elementos <data> son los esquemas de URI previamente registrados con la aplicación. No puede usar esquemas que no estén definidos en el filtro de intención.

Para que la aplicación se pueda examinar desde otras aplicaciones, declare un elemento <data> con el atributo android:scheme:

<data android:scheme="appName"/>

Abrir otra aplicación

Para usar la funcionalidad Launcher, llame al método ILauncher.OpenAsync y pase un String o Uri que represente la aplicación para abrirla. Opcionalmente, se puede usar el método ILauncher.CanOpenAsync(Uri) para comprobar si una aplicación en el dispositivo puede manejar el esquema de URI. En el código siguiente se muestra cómo comprobar si se admite o no un esquema de URI y, a continuación, se abre el URI:

bool supportsUri = await Launcher.Default.CanOpenAsync("lyft://");

if (supportsUri)
    await Launcher.Default.OpenAsync("lyft://ridetype?id=lyft_line");

El ejemplo de código anterior se puede simplificar mediante el TryOpenAsync(Uri), que comprueba si se puede abrir el esquema de URI antes de abrirlo:

bool launcherOpened = await Launcher.Default.TryOpenAsync("lyft://ridetype?id=lyft_line");

if (launcherOpened)
{
    // Do something fun
}

Abrir otra aplicación a través de un archivo

El iniciador también se puede usar para abrir una aplicación con un archivo seleccionado. .NET MAUI detecta automáticamente el tipo de archivo (MIME) y abre la aplicación predeterminada para ese tipo de archivo. Si se registra más de una aplicación con el tipo de archivo, se muestra una ventana emergente de selección de la aplicación al usuario.

En el ejemplo de código siguiente se escribe texto en un archivo y se abre el archivo de texto con el iniciador:

string popoverTitle = "Read text file";
string name = "File.txt";
string file = System.IO.Path.Combine(FileSystem.CacheDirectory, name);

System.IO.File.WriteAllText(file, "Hello World");

await Launcher.Default.OpenAsync(new OpenFileRequest(popoverTitle, new ReadOnlyFile(file)));

Controlar ubicaciones de archivos

Importante

Esta sección solo se aplica a Android.

En algunos escenarios de Android, como cuando un archivo está en almacenamiento privado, se puede copiar en la memoria caché de la aplicación, que luego se comparte a través de una FileProviderde Android. Sin embargo, esto puede exponer involuntariamente toda la memoria caché y los datos de la aplicación a un atacante. Esto se puede evitar agregando un archivo de anulación de rutas de archivo del proveedor en tu aplicación y asegurándote de que los archivos se copian en la ubicación especificada en este archivo antes de compartir.

Para añadir un archivo de anulación de rutas de acceso de proveedor de archivos a tu aplicación, agrega un archivo llamado microsoft_maui_essentials_fileprovider_file_paths.xml a la carpeta Platforms\Android\Resources\xml de la aplicación. Por lo tanto, el nombre de archivo relativo completo al proyecto debe ser Plataformas\Android\Resources\xml\microsoft_maui_essentials_fileprovider_file_paths.xml. A continuación, agregue XML al archivo para las rutas de acceso necesarias:

 <?xml version="1.0" encoding="UTF-8" ?>
 <paths>
    <external-path name="external_files" path="sharing-root" />
    <cache-path name="internal_cache" path="sharing-root" />
    <external-cache-path name="external_cache" path="sharing-root" />  
 </paths>

Para obtener más información sobre las rutas de acceso del proveedor de archivos, consulte FileProvider en developer.android.com.

Antes de compartir un archivo, debe asegurarse de que esté escrito primero en la carpeta raíz de uso compartido en una de las ubicaciones del archivo de anulación:

// Write into the specific sub-directory
var dir = Path.Combine(FileSystem.CacheDirectory, "sharing-root");  
Directory.CreateDirectory(dir);
var file = Path.Combine(dir, "mydata.txt");
await File.WriteAllTextAsync(file, $"My data: {count}");

// Share the file
await Launcher.OpenAsync(new OpenFileRequest
{
   Title = "My data",
   File = new ReadOnlyFile(file),
});

Puede comprobar que el archivo se comparte correctamente si el URI compartido excluye el directorio raíz de uso compartido. Por ejemplo, si comparte el archivo <CacheDirectory>/sharing-root/mydata.txt y el URI compartido es content://com.companyname.overwritefileproviderpaths.fileProvider/internal_cache/sharing-root/mydata.txt el proveedor de archivos no usa la ruta de acceso correcta. Si el URI compartido es content://com.companyname.overwritefileproviderpaths.fileProvider/internal_cache/mydata.txt, el proveedor de archivos usa la ruta de acceso correcta.

Advertencia

Al compartir un archivo, si recibe un Java.Lang.IllegalArgumentException, con un mensaje similar a "No se pudo encontrar la raíz configurada que contiene /data/data/com.companyname.overwritefileproviderpaths/cache/some-non-sharing-path/mydata.txt", probablemente comparta un archivo que esté fuera de la raíz de uso compartido.

Establecer la ubicación del iniciador

Importante

Esta sección solo se aplica a iPadOS.

Al solicitar un recurso compartido o abrir el iniciador en iPadOS, puede presentarlo en una ventana emergente. Esto especifica dónde aparecerá la ventana emergente y apuntará una flecha directamente. Esta ubicación suele ser el elemento de control que inició la acción. Puede especificar la ubicación mediante la propiedad PresentationSourceBounds:

await Share.RequestAsync(new ShareFileRequest
    {
        Title = Title,
        File = new ShareFile(file),
        PresentationSourceBounds = DeviceInfo.Platform == DevicePlatform.iOS && DeviceInfo.Idiom == DeviceIdiom.Tablet
                                ? new Rect(0, 20, 0, 0)
                                : Rect.Zero
    });
await Launcher.OpenAsync(new OpenFileRequest
    {
        File = new ReadOnlyFile(file),
        PresentationSourceBounds = DeviceInfo.Platform == DevicePlatform.iOS && DeviceInfo.Idiom == DeviceIdiom.Tablet
                                ? new Rect(0, 20, 0, 0)
                                : Rect.Zero
    });

Todo lo descrito aquí funciona igualmente para Share y Launcher.

Este es un método de extensión que ayuda a calcular los límites de una vista:

public static class ViewHelpers
{
    public static Rect GetAbsoluteBounds(this Microsoft.Maui.Controls.View element)
    {
        Element looper = element;

        var absoluteX = element.X + element.Margin.Top;
        var absoluteY = element.Y + element.Margin.Left;

        // Add logic to handle titles, headers, or other non-view bars

        while (looper.Parent != null)
        {
            looper = looper.Parent;
            if (looper is Microsoft.Maui.Controls.View v)
            {
                absoluteX += v.X + v.Margin.Top;
                absoluteY += v.Y + v.Margin.Left;
            }
        }

        return new Rect(absoluteX, absoluteY, element.Width, element.Height);
    }
}

A continuación, se puede usar al llamar a RequestAsync:

public Command<Microsoft.Maui.Controls.View> ShareCommand { get; } = new Command<Microsoft.Maui.Controls.View>(Share);

async void Share(Microsoft.Maui.Controls.View element)
{
    try
    {
        await Share.Default.RequestAsync(new ShareTextRequest
        {
            PresentationSourceBounds = element.GetAbsoluteBounds(),
            Title = "Title",
            Text = "Text"
        });
    }
    catch (Exception)
    {
        // Handle exception that share failed
    }
}

Puede pasar el elemento de llamada cuando se desencadene el Command:

<Button Text="Share"
        Command="{Binding ShareWithFriendsCommand}"
        CommandParameter="{Binding Source={RelativeSource Self}}"/>

Para obtener un ejemplo de la clase ViewHelpers, consulte el ejemplo de MAUI de .NET hospedado en GitHub.

Diferencias de plataforma

En esta sección se describen las diferencias específicas de la plataforma con la API del iniciador.

El Task devuelto de CanOpenAsync se completa inmediatamente.