Mateusz Siniarski
Mateusz Siniarski

Reputation: 1015

Android Shared Storage across apps

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;

Any expertise or insight would be helpful.

Upvotes: 1

Views: 1710

Answers (1)

Mateusz Siniarski
Mateusz Siniarski

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

Related Questions