Xamarin Forms中Android与iOS跨应用单向数据共享方案咨询
Hey there! Let's break down your Android cross-app data sharing question since you've already got the iOS side covered with App Groups. Given you've set the same android:sharedUserId for both apps A and B, and ruled out some plugins, here are practical alternatives to shared SQLite databases that fit your requirement of B fetching data from A without launching A:
1. Access App A's Shared Preferences Directly via Android Native APIs
Since the Xam.Plugins.Settings plugin doesn't let you specify a target package name, you can bypass it and use Android's native Shared Preferences API directly. With matching sharedUserId, App B can access App A's shared preferences by grabbing its context first:
// In App B's Android project try { // Replace with App A's actual package name var appAContext = Android.App.Application.Context.CreatePackageContext("com.yourcompany.appa", PackageContextFlags.IgnoreSecurity); // Replace with the name of App A's shared preferences file var sharedPrefs = appAContext.GetSharedPreferences("AppA_Preferences", FileCreationMode.MultiProcess); // Read data from App A's prefs string sharedValue = sharedPrefs.GetString("KeyToFetch", "DefaultValue"); bool sharedBool = sharedPrefs.GetBoolean("AnotherKey", false); } catch (PackageManager.NameNotFoundException ex) { // Handle case where App A isn't installed on the device }
Just make sure App A uses a multi-process accessible mode (like MultiProcess) when creating its Shared Preferences, and both apps are signed with the same keystore—this is a mandatory requirement for sharedUserId to work.
2. Use a Content Provider (Android's Official Recommended Approach)
Content Providers are built explicitly for cross-app data sharing. You can implement a simple Content Provider in App A to expose the data B needs, then have B query it via ContentResolver.
Step 1: Implement Content Provider in App A
Create a class inheriting from ContentProvider in App A's Android project, override the Query method to return the data you want to share:
[ContentProvider(new string[] { "com.yourcompany.appa.dataprovider" })] public class AppADataProvider : ContentProvider { public override bool OnCreate() { // Initialize your data source (e.g., local database, in-memory collection) return true; } public override ICursor Query(Uri uri, string[] projection, string selection, string[] selectionArgs, string sortOrder) { // Return a cursor with the data B needs // Example: Fetch from App A's local database and return as a cursor var db = AppADataHelper.GetDatabaseInstance(); return db.Query("YourDataTable", projection, selection, selectionArgs, null, null, sortOrder); } // Override other required methods with empty implementations if you only need read access public override int Delete(Uri uri, string selection, string[] selectionArgs) => 0; public override string GetType(Uri uri) => null; public override Uri Insert(Uri uri, ContentValues values) => null; public override int Update(Uri uri, ContentValues values, string selection, string[] selectionArgs) => 0; }
Declare the provider in App A's AndroidManifest.xml (tailor permissions to your sharedUserId setup):
<provider android:name=".AppADataProvider" android:authorities="com.yourcompany.appa.dataprovider" android:exported="true" android:readPermission="com.yourcompany.shared_data_access" />
Add the permission declaration in both App A and B's manifests:
<uses-permission android:name="com.yourcompany.shared_data_access" />
Step 2: Query from App B
In App B's Android project, use ContentResolver to fetch data from App A's provider:
var dataUri = Uri.Parse("content://com.yourcompany.appa.dataprovider/yourdatatable"); var cursor = Android.App.Application.Context.ContentResolver.Query(dataUri, new string[] { "Column1", "Column2" }, null, null, null); if (cursor != null && cursor.MoveToFirst()) { do { string value1 = cursor.GetString(cursor.GetColumnIndex("Column1")); // Process the fetched data as needed } while (cursor.MoveToNext()); cursor.Close(); }
3. Shared External Storage (Simpler for File-Based Data)
If your data is in file format (e.g., JSON, text, binary), you can store it in a shared external directory. With matching sharedUserId, both apps have read/write access to each other's app-specific external storage folders.
App-Specific External Storage (More Secure)
Store data in App A's external files directory, which App B can access directly:
// In App A: Write data to its external files folder string sharedFilePath = Path.Combine(Android.App.Application.Context.GetExternalFilesDir(null).AbsolutePath, "SharedData.json"); File.WriteAllText(sharedFilePath, "{\"userPreference\": \"darkMode\", \"version\": \"1.0\"}"); // In App B: Read the same file string appAExternalDir = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, "Android/data/com.yourcompany.appa/files"); string sharedFilePath = Path.Combine(appAExternalDir, "SharedData.json"); if (File.Exists(sharedFilePath)) { string rawData = File.ReadAllText(sharedFilePath); // Parse and use the data (e.g., deserialize JSON) }
Note: For Android 10+, you don't need READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE permissions for app-specific external storage, making this approach cleaner and more secure.
Key Notes for All Approaches
- Same Signature Requirement: Apps with the same
sharedUserIdmust be signed with the same keystore. For local testing, ensure both apps use the debug keystore. - Android 11+ Scoped Storage: Avoid public external directories if possible, as Scoped Storage restricts broad access. App-specific external storage is the safer, compliant choice.
- Error Handling: Always add checks for App A's presence (e.g., catch
PackageManager.NameNotFoundException) to avoid crashes if A isn't installed on the device.
内容的提问来源于stack exchange,提问作者SnapADragon

