Skip to content

Control Android FileProvider locations #2847

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 24, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/platform-integration/appmodel/launcher.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Launcher"
description: "Learn how to use the .NET MAUI ILauncher interface in the Microsoft.Maui.ApplicationModel namespace, which can open another application by URI."
ms.date: 02/02/2023
ms.date: 03/24/2025
no-loc: ["Microsoft.Maui", "Microsoft.Maui.ApplicationModel"]
---

@@ -84,6 +84,10 @@ The following code example writes text to a file, and opens the text file with t

:::code language="csharp" source="../snippets/shared_1/AppModelPage.xaml.cs" id="launcher_open_file":::

### Control file locations

[!INCLUDE [android-fileproviderpaths](../includes/android-fileproviderpaths.md)]

## Set the launcher location

[!INCLUDE [ios-PresentationSourceBounds](../includes/ios-PresentationSourceBounds.md)]
6 changes: 5 additions & 1 deletion docs/platform-integration/communication/email.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Email"
description: "Learn how to use the .NET MAUI IEmail interface in the Microsoft.Maui.ApplicationModel.Communication namespace to open the default email application. The subject, body, and recipients of an email can be set."
ms.date: 02/02/2023
ms.date: 03/24/2025
no-loc: ["Microsoft.Maui", "Microsoft.Maui.ApplicationModel.Communication"]
---

@@ -67,6 +67,10 @@ The following example demonstrates adding an image file to the email attachments

:::code language="csharp" source="../snippets/shared_1/CommsPage.xaml.cs" id="email_picture" highlight="18":::

### Control file locations

[!INCLUDE [android-fileproviderpaths](../includes/android-fileproviderpaths.md)]

<!-- markdownlint-disable MD025 -->
<!-- markdownlint-disable MD024 -->
## Platform Differences
6 changes: 5 additions & 1 deletion docs/platform-integration/data/share.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Share"
description: "Learn how to use the .NET MAUI IShare interface, which can share data, such as web links, to other applications on the device."
ms.date: 02/02/2023
ms.date: 03/24/2025
no-loc: ["Microsoft.Maui", "Microsoft.Maui.ApplicationModel.DataTransfer"]
---

@@ -67,6 +67,10 @@ The following code example writes two text files to the device, and then request

:::code language="csharp" source="../snippets/shared_1/DataPage.xaml.cs" id="share_file_multiple":::

## Control file locations

[!INCLUDE [android-fileproviderpaths](../includes/android-fileproviderpaths.md)]

## Presentation location

[!INCLUDE [ios-PresentationSourceBounds](../includes/ios-PresentationSourceBounds.md)]
44 changes: 44 additions & 0 deletions docs/platform-integration/includes/android-fileproviderpaths.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
ms.topic: include
ms.date: 03/24/2025
---

> [!IMPORTANT]
> This section only applies to Android.
In some scenarios on Android, such as when a file is in private storage, it can be copied into the app cache which is then shared via an Android `FileProvider`. However, this can [unintentionally expose the entire cache and app data](https://developer.android.com/privacy-and-security/risks/file-providers) to an attacker. This can be prevented by adding a file provider file paths override file to your app, and ensuring that files are copied to the location specified in this file prior to sharing.

To add a file provider file paths override file to your app, add a file named *microsoft_maui_essentials_fileprovider_file_paths.xml* to the *Platforms\Android\Resources\xml* folder in your app. Therefore, the full relative file name to the project should be *Platforms\Android\Resources\xml\microsoft_maui_essentials_fileprovider_file_paths.xml*. Then, add XML to the file for your required paths:

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

For more information about file provider paths, see [FileProvider](https://developer.android.com/reference/androidx/core/content/FileProvider) on developer.android.com.

Prior to sharing a file, you should ensure it's first written to the *sharing-root* folder in one of the locations from the override file:

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

You can verify that the file is being shared correctly if the shared URI excludes the sharing root directory. For example, if you share the file *\<CacheDirectory\>/sharing-root/mydata.txt* and the shared URI is `content://com.companyname.overwritefileproviderpaths.fileProvider/internal_cache/sharing-root/mydata.txt` then the file provider isn't using the correct path. If the shared URI is `content://com.companyname.overwritefileproviderpaths.fileProvider/internal_cache/mydata.txt` then the file provider is using the correct path.

> [!WARNING]
> When sharing a file, if you receive an `Java.Lang.IllegalArgumentException`, with a message similar to "Failed to find configured root that contains /data/data/com.companyname.overwritefileproviderpaths/cache/some-non-sharing-path/mydata.txt", you are most likely sharing a file that's outside of the sharing-root.