Reputation: 1015
I'm trying to find the best solution for sharing data between multiple apps on a user's device. All these android apps would be using the same signing. Having prompts to share or grant data permission will not be possible due the user experience being important (so Sharing Intents are out of the picture)
I've tried the following solutions with the following results;
sharedUserId
is not an option as these are existing apps that already have a default sharedUserId
value which will prevent users from upgradingContentProvider
using SQLite
was promising however since any of the apps can share data and it's not know which one will be installed or installed first, there is no way to determine which app should have the <provider>
. Unless there is a way to create a content provider that any of the apps can initialise if its the first app then I'm unsure how to proceed with this solutionAny expertise or insight would be helpful.
Upvotes: 1
Views: 1710
Reputation: 1015
Thank you @morrison-chang and @blackapps. Using key points in your comments I found a solution that works. I had a unique authority for the same provider on each app. However they are all disabled by default. Whenever any of the apps need to access their provider it will check if there is any existing ones already available.
SomeClassUsingMyContextProvider.java
...
private Uri getActiveSharedStorageContentUri(){
List<PackageInfo> packs = packageManager.getInstalledPackages(PackageManager.GET_PROVIDERS);
for (PackageInfo pack : packs) {
ProviderInfo[] providers = pack.providers;
if (providers != null) {
for (ProviderInfo provider : providers) {
if(provider != null && provider.authority != null && provider.authority.endsWith(SharedStorageProvider.AUTHORITY_SUFFIX)){
return SharedStorageProvider.createContentUri(provider.authority);
}
}
}
}
// If no valid provider.authority was found for SharedStorageProvider then we can assume
// that the current app's SharedStorageProvider provider has not been enabled yet.
// Lets activate it and then use its CONTENT_URI
ComponentName componentName = new ComponentName(reactContext, SharedStorageProvider.class);
packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
return SharedStorageProvider.CONTENT_URI;
}
...
SharedStorageProvider.java
public class SharedStorageProvider extends ContentProvider {
public static final String AUTHORITY_SUFFIX = String.format(".SharedStorageProvider.%s", BuildConfig.APP_GROUP);
public static final String AUTHORITY = String.format("%s%s", BuildConfig.APPLICATION_ID, AUTHORITY_SUFFIX);
...
public static final Uri CONTENT_URI = createContentUri(AUTHORITY);
...
public static Uri createContentUri(String authority) {
return Uri.parse("content://" + authority + "/" + BASE_PATH);
}
...
AndroidManifest.xml
...
<uses-permission android:name="com.myapps.READ_DATABASE" />
<uses-permission android:name="com.myapps.WRITE_DATABASE" />
<permission android:name="com.myapps.READ_DATABASE" android:protectionLevel="signature" />
<permission android:name="com.myapps.WRITE_DATABASE" android:protectionLevel="signature" />
...
<application
...
<provider
android:name=".SharedStorageProvider"
android:authorities="@string/shared_storage_provider_authority"
android:exported="true"
android:enabled="false"
android:readPermission="com.myapps.READ_DATABASE"
android:writePermission="com.myapps.WRITE_DATABASE"
/>
</application>
...
build.gradle
...
resValue "string", "shared_storage_provider_authority", applicationId + ".SharedStorageProvider." + project.env.get("APP_GROUP") // Used to generate dynamic authority name
...
Known limitation; Since this only stores data in the content provider from the app that enabled it, if that app is uninstalled then the "shared" data will be lost from all the apps that were using it. For my use this is fine.
Upvotes: 1