Xamarin.Forms Android中FileProvider跨应用返回文件失败问题
我有两个Xamarin Forms Android应用,App1启动App2中的Activity,需要将App2生成的文件返回给App1。之前通过在两个应用的AndroidManifest.xml中设置相同的sharedUserId,直接返回文件路径就能实现共享,但sharedUserId已被废弃,且与Microsoft Defender按应用VPN不兼容,因此必须更换方案。
一、App2的现有配置
1. AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.app2"> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" /> <application android:label="App2.Android" android:theme="@style/MainTheme"> <provider android:name="androidx.core.content.FileProvider" android:authorities="com.companyname.app2.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/> </provider> </application> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> </manifest>
2. file_paths.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="." /> </paths>
3. MainApplication代码
using System; using Android.App; using Android.Content; using Android.OS; using Android.Runtime; namespace App2.Droid { [Application] public partial class MainApplication : Application, Application.IActivityLifecycleCallbacks { internal static Context CurrentContext { get; private set; } internal static String FileProviderAuthority { get => MainApplication.CurrentContext.ApplicationContext.PackageName + ".fileprovider"; } public MainApplication(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer) { } public override void OnCreate() { base.OnCreate(); RegisterActivityLifecycleCallbacks(this); } public override void OnTerminate() { base.OnTerminate(); UnregisterActivityLifecycleCallbacks(this); } public void OnActivityCreated(Activity activity, Bundle savedInstanceState) { CurrentContext = activity; } public void OnActivityDestroyed(Activity activity) { } public void OnActivityPaused(Activity activity) { } public void OnActivityResumed(Activity activity) { CurrentContext = activity; } public void OnActivitySaveInstanceState(Activity activity, Bundle outState) { } public void OnActivityStarted(Activity activity) { CurrentContext = activity; } public void OnActivityStopped(Activity activity) { } } }
二、App2测试代码及问题
在App2的MainActivity中编写了测试方法,用于创建文件、生成URI、自行读取文件并尝试分享URI。尝试过多种Context,但目前存在以下问题:
- 选择WhatsApp分享时直接崩溃
- 选择Gmail时,邮件能附上test1.txt且显示正确大小,但无法下载文件
测试代码如下:
private void test() { StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.SetVmPolicy(builder.Build()); string savefilePath = Path.Combine($"{Android.App.Application.Context.GetExternalFilesDir("")}", "test1.txt"); System.IO.File.WriteAllText(savefilePath, "Hello from FileProvider 2!"); _file = new Java.IO.File(savefilePath); Context context = Android.App.Application.Context; //Context context = this; //Context context = this.ApplicationContext; //Context context = MainApplication.CurrentContext; Android.Net.Uri contentUri = MyFileProvider.GetUriForFile(context, "com.companyname.app2.fileprovider", _file); using (var contentResolver = this.ContentResolver) using (var inputStream = contentResolver.OpenInputStream(Android.Net.Uri.Parse(contentUri.ToString()))) { if (inputStream != null) { byte[] buffer; buffer = new byte[40000 * 2]; int bytesRead = inputStream.Read(buffer, 0, buffer.Length); System.Console.WriteLine($"Read {bytesRead} from the file"); // 此处读取正常 } else { System.Console.WriteLine("Failed to open input stream for URI"); } } var shareIntent = new Intent(); shareIntent.SetAction(Intent.ActionSend); shareIntent.SetType("text/plain"); shareIntent.PutExtra(Intent.ExtraStream, contentUri); shareIntent.AddFlags(ActivityFlags.GrantReadUriPermission); StartActivityForResult(Intent.CreateChooser(shareIntent, "Share file"), RequestCode); }
三、跨应用读取的困境
将URI返回给App1后,用相同的contentResolver.OpenInputStream代码读取时,会出现以下问题之一:
- 权限错误
- 找不到内容提供程序
- 提示文件不存在
试过Uri.FromFile、各种旧版Xamarin/Android代码,均无法解决问题。也未找到Xamarin.Essentials FileProvider的相关使用示例。
需求目标
需要在App2的Activity返回的JSON结果中包含文件URI,让App1能正常读取该文件。当前返回结果的代码如下:
var rtn = new Intent(); string json = "...somthing with uri files..."; rtn.PutExtra("result", json); SetResult(Result.Ok, rtn); Finish();
URI能正常返回,但App1无法读取文件内容。
内容的提问来源于stack exchange,提问作者Jones Abramoff
相关产品推荐
相关产品推荐

