共用方式為


啟動器

瀏覽範例。 瀏覽範例

本文說明如何使用 .NET 多平臺應用程式 UI (.NET MAUI) ILauncher 介面。 此介面可讓應用程式由系統開啟URI。 當深層連結至另一個應用程式的自定義 URI 配置時,通常會使用這種開啟應用程式的方式。

ILauncher 介面的預設實作可透過 Launcher.Default 屬性取得。 ILauncher 介面和 Launcher 類別都包含在 Microsoft.Maui.ApplicationModel 命名空間中。

這很重要

若要將瀏覽器開啟至網站,請改用 瀏覽器 API。

開始吧

若要存取啟動器功能,需要下列平臺特定設定。

如果您想要使用深層連結來開啟其他 Android 應用程式,您應該在應用程式中定義意圖篩選。 將下列 XML 新增至 Platform/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>

<data> 元素是預先向您的應用程式註冊的 URI 協定。 您無法使用意圖篩選中未定義的配置。

若要讓您的應用程式能被其他應用程式瀏覽,請宣告具有 android:scheme 屬性的 <data> 元素:

<data android:scheme="appName"/>

開啟另一個應用程式

若要使用啟動器功能,請呼叫 ILauncher.OpenAsync 方法,並傳入代表應用程式開啟的 StringUri。 或者,ILauncher.CanOpenAsync(Uri) 方法可用來檢查裝置上的應用程式是否可以處理 URI 配置。 下列程式代碼示範如何檢查 URI 配置是否受到支援,然後開啟 URI:

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

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

先前的程式代碼範例可以使用 TryOpenAsync(Uri)來簡化,它會先檢查 URI 配置是否可以開啟,再開啟它:

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

if (launcherOpened)
{
    // Do something fun
}

透過檔案開啟另一個應用程式

啟動器也可以用來開啟具有所選檔案的應用程式。 .NET MAUI 會自動偵測檔案類型 (MIME),並開啟該檔案類型的默認應用程式。 如果有多個應用程式向檔案類型註冊,則會向用戶顯示應用程式選取的彈出選單。

下列程式代碼範例會將文字寫入檔案,並使用啟動器開啟文字檔:

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)));

控制檔案位置

這很重要

本節僅適用於 Android。

在 Android 的某些情況下,例如檔案位於私人儲存空間時,它可以被複製到應用程式快取中,然後透過 Android FileProvider進行共用。 不過,這可能會 無意中向攻擊者公開整個快取和應用程式 數據。 這可以藉由將檔案提供者檔案路徑覆寫檔案新增至您的應用程式,並確保檔案會先複製到此檔案中指定的位置,再進行共用,以防止這種情況。

若要將檔案提供者檔案路徑覆寫檔案新增至您的應用程式,請將名為 microsoft_maui_essentials_fileprovider_file_paths.xml 的檔案新增至應用程式中的 Platform\Android\Resources\xml 資料夾。 因此,專案的完整相對檔案名應該 平臺\Android\Resources\xml\microsoft_maui_essentials_fileprovider_file_paths.xml。 然後,將 XML 新增至檔案中,以取得所需的路徑:

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

如需檔案提供者路徑的詳細資訊,請參閱 developer.android.com 上的 FileProvider

在分享檔案之前,您應該先將其寫入到覆寫檔中指定位置之一的 共用根目錄 資料夾。

// 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),
});

如果共用的 URI 不包含共用根目錄,您可以確認檔案已正確共用。 例如,如果您共用檔案 <CacheDirectory>/sharing-root/mydata.txt,且共用 URI content://com.companyname.overwritefileproviderpaths.fileProvider/internal_cache/sharing-root/mydata.txt 則檔案提供者未使用正確的路徑。 如果共用 URI content://com.companyname.overwritefileproviderpaths.fileProvider/internal_cache/mydata.txt,則檔案提供者會使用正確的路徑。

警告

共用檔案時,如果您收到 Java.Lang.IllegalArgumentException,且訊息類似「找不到包含 /data/data/com.companyname.overwritefileproviderpaths/cache/some-non-sharing-path/mydata.txt的已設定根目錄」,那您很可能是在分享共用根目錄以外的檔案。

設定啟動器位置

這很重要

本節僅適用於 iPadOS。

在 iPadOS 上要求共用或開啟啟動器時,您可以在彈出視窗中呈現它。 這會指定彈出視窗出現的位置,並直接讓一支箭頭指向該位置。 這個位置通常是啟動動作的控制件。 您可以使用 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
    });

此處所述的一切同樣適用於 ShareLauncher

以下是可協助計算檢視界限的擴充方法:

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);
    }
}

接著,呼叫 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
    }
}

觸發 Command 時,您可以傳入呼叫元素:

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

如需 ViewHelpers 類別的範例,請參閱裝載在 GitHub 上的.NET MAUI 範例。

平台差異

本節說明啟動器 API 的平臺特定差異。

CanOpenAsync 傳回的 Task 會即時完成。