Google Pixel设备上Xamarin.Forms应用导出功能异常求助
Hey Cheran, let's tackle this issue you're facing with your Xamarin.Forms app on Google Pixel devices. I've gone through your code and the problem description, and here are the key fixes to get the mobi file sharing to Kindle working properly:
1. Fix the Incorrect MIME Type
Your code hardcodes the MIME type to application/pdf, but you're trying to share a mobi file. Kindle won't recognize this type, which is likely part of the issue. Use the correct MIME type for mobi files:
application/x-mobipocket-ebook(standard mobi type)- Or
application/vnd.amazon.mobi8-ebook(for newer Kindle formats)
You can also dynamically detect the MIME type using MimeTypeMap to avoid hardcoding:
string extension = MimeTypeMap.GetFileExtensionFromUrl(Android.Net.Uri.FromFile(new Java.IO.File(mobileFileName)).ToString()); string mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(extension);
2. Replace file:// URI with FileProvider (Critical for Android 7.0+)
Google Pixel devices run newer Android versions (API 24+), which block cross-app access to file:// URIs for security reasons. You need to use FileProvider to generate a content:// URI instead:
Step 1: Register FileProvider in AndroidManifest.xml
Add this inside the <application> tag:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
Step 2: Create file_paths.xml in Resources/xml
If the xml directory doesn't exist, create it first. Then add this content to map your file storage path:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Adjust the path based on where your mobi files are stored --> <external-files-path name="app_files" path="." /> <!-- Use <external-path> if files are in public external storage --> </paths>
Step 3: Generate the Content URI in Code
Replace your file:// URI generation with this:
var file = new Java.IO.File(mobileFileName); var contentUri = FileProvider.GetUriForFile(context, context.PackageName + ".fileprovider", file); // Grant read permission to the target app sendIntent.AddFlags(ActivityFlags.GrantReadUriPermission);
3. Clean Up Your Intent Setup
Your current code has several redundant or incorrect settings:
- You hardcode
SetPackage("com.google.android.apps.docs"), which limits sharing to Google Docs only (not Kindle). Remove this line unless you specifically want to target Google Docs. - You set
Intent.ExtraStreamtwice (once onsendIntent, once onchooserIntent). Only set it on the basesendIntent. - The
shareIntentsListsis empty in your code, so that block does nothing. If you want to manually filter apps, usePackageManager.QueryIntentActivitiescorrectly.
Corrected Code Snippet
Here's the revised code incorporating all fixes:
var mobileFileName = Path.Combine(path, m_documentName); var file = new Java.IO.File(mobileFileName); // Get correct MIME type for mobi string extension = MimeTypeMap.GetFileExtensionFromUrl(Android.Net.Uri.FromFile(file).ToString()); string mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(extension); Intent sendIntent = new Intent(Intent.ActionSend); sendIntent.SetType(mimeType); // Use FileProvider for secure URI var contentUri = FileProvider.GetUriForFile(context, context.PackageName + ".fileprovider", file); sendIntent.PutExtra(Intent.ExtraStream, contentUri); sendIntent.AddFlags(ActivityFlags.GrantReadUriPermission); // Optional: If you want to target Kindle specifically, uncomment this line // sendIntent.SetPackage("com.amazon.kindle"); // Build the chooser Intent chooserIntent = Intent.CreateChooser(sendIntent, "Share with"); chooserIntent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTop); // Optional: Manually add apps to the chooser (using QueryIntentActivities) var resolveInfoList = context.PackageManager.QueryIntentActivities(sendIntent, PackageInfoFlags.MatchDefaultOnly); var shareIntentsLists = new List<Intent>(); foreach (var resolveInfo in resolveInfoList) { var targetIntent = new Intent(Intent.ActionSend); targetIntent.SetType(mimeType); targetIntent.PutExtra(Intent.ExtraStream, contentUri); targetIntent.SetPackage(resolveInfo.ActivityInfo.PackageName); targetIntent.AddFlags(ActivityFlags.GrantReadUriPermission); shareIntentsLists.Add(targetIntent); } if (shareIntentsLists.Count > 0) { chooserIntent.PutExtra(Intent.ExtraInitialIntents, shareIntentsLists.ToArray()); } context.StartActivity(chooserIntent);
Why This Works on Other Devices but Not Pixel
Most older Android devices don't enforce the file:// URI restriction as strictly as newer Pixel devices (which run recent Android versions). The incorrect MIME type also prevents Kindle from recognizing the file as a valid ebook, even if the URI worked.
内容的提问来源于stack exchange,提问作者cheran

