本文介绍如何使用 .NET Multi-platform App UI (.NET MAUI) 接口。 此接口提供一个 API,用于将数据(如文本或 Web 链接)发送到设备共享函数。
IShare
接口的默认实现可通过 Share.Default 属性获得。
IShare
接口和 Share
类都包含在 Microsoft.Maui.ApplicationModel.DataTransfer
命名空间中。
发出共享请求后,设备会显示共享窗口,提示用户选择要与之共享的应用:
入门
若要访问 共享 功能,需要以下特定于平台的设置:
无需设置。
共享文本和链接
共享功能的工作原理是通过调用 RequestAsync 方法,并使用包含将信息共享到其他应用程序的数据负载来实现的。 ShareTextRequest.Text 和 ShareTextRequest.Uri 可以混合,每个平台将处理基于内容的筛选。
public async Task ShareText(string text)
{
await Share.Default.RequestAsync(new ShareTextRequest
{
Text = text,
Title = "Share Text"
});
}
public async Task ShareUri(string uri, IShare share)
{
await share.RequestAsync(new ShareTextRequest
{
Uri = uri,
Title = "Share Web Link"
});
}
共享文件
还可以将文件共享到设备上的其他应用程序。 .NET MAUI 会自动检测文件类型(MIME)并请求共享。 但是,作系统可能会限制可以共享哪些类型的文件。 若要共享单个文件,请使用 ShareFileRequest 类型。
下面的代码示例将文本文件写入设备,然后请求共享它:
public async Task ShareFile()
{
string fn = "Attachment.txt";
string file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");
await Share.Default.RequestAsync(new ShareFileRequest
{
Title = "Share text file",
File = new ShareFile(file)
});
}
共享多个文件
共享多个文件与共享单个文件略有不同。 若要共享单个文件,请使用 ShareMultipleFilesRequest 类型。
下面的代码示例将两个文本文件写入设备,然后请求共享它们:
public async Task ShareMultipleFiles()
{
string file1 = Path.Combine(FileSystem.CacheDirectory, "Attachment1.txt");
string file2 = Path.Combine(FileSystem.CacheDirectory, "Attachment2.txt");
File.WriteAllText(file1, "Content 1");
File.WriteAllText(file2, "Content 2");
await Share.Default.RequestAsync(new ShareMultipleFilesRequest
{
Title = "Share multiple files",
Files = new List<ShareFile> { new ShareFile(file1), new ShareFile(file2) }
});
}
文件位置控制
重要
本部分仅适用于 Android。
在 Android 上的某些方案中,例如,当文件位于专用存储中时,可以将其复制到应用缓存中,然后通过 Android FileProvider
进行共享。 但是,这 无意中向攻击者公开整个缓存和应用 数据。 这可以通过在应用中添加一个文件提供者路径覆盖文件,并确保在共享之前将文件复制到该文件中指定的位置,从而防止出现此问题。
若要将文件提供程序文件路径替代文件添加到应用,请将名为 microsoft_maui_essentials_fileprovider_file_paths.xml 的文件添加到应用中的 Platforms\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
});
此处所述的一切同样适用于 Share 和 Launcher。
下面是一种扩展方法,可帮助计算视图的边界:
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 的平台特定差异。
- ShareTextRequest.Subject 属性用于消息的所需主题。