Android跨应用共享存储

Android跨应用共享存储,android,storage,android-contentprovider,Android,Storage,Android Contentprovider,我正在努力寻找在用户设备上的多个应用程序之间共享数据的最佳解决方案。所有这些android应用程序都将使用相同的签名。由于用户体验非常重要,因此无法提示共享或授予数据权限(因此共享意图是不可能的) 我尝试了以下解决方案,结果如下: 使用sharedUserId的SharedReferences不是一个选项,因为这些是现有的应用程序,它们已经具有默认的sharedUserId值,这将阻止用户升级 ContentProvider使用SQLite很有希望,但是由于任何应用程序都可以共享数据,并且不知

我正在努力寻找在用户设备上的多个应用程序之间共享数据的最佳解决方案。所有这些android应用程序都将使用相同的签名。由于用户体验非常重要,因此无法提示共享或授予数据权限(因此共享意图是不可能的)

我尝试了以下解决方案,结果如下:

  • 使用
    sharedUserId
    的SharedReferences不是一个选项,因为这些是现有的应用程序,它们已经具有默认的
    sharedUserId
    值,这将阻止用户升级
  • ContentProvider
    使用
    SQLite
    很有希望,但是由于任何应用程序都可以共享数据,并且不知道将首先安装或安装哪个应用程序,因此无法确定哪个应用程序应该具有
    。除非有一种方法可以创建一个内容提供商,如果它是第一个应用程序,任何应用程序都可以初始化,否则我不确定如何继续使用此解决方案
  • 我目前正在尝试使用外部存储,只是存储一个包含需要共享的数据的文件。这显然是最易受攻击的解决方案,但我可能只存储临时敏感数据(几分钟后过期的令牌)而不受影响。然而,我们仍在寻找最佳解决方案

任何专业知识或见解都会有所帮助。

谢谢@morrison chang和@blackapps。利用你评论中的要点,我找到了一个有效的解决方案。我对每个应用程序上的同一提供商都有唯一的权限。但是,默认情况下它们都被禁用。每当任何应用程序需要访问其提供商时,它都会检查是否已有可用的应用程序

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;
}
...
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>
...
已知限制;
由于这只会将启用该应用程序的数据存储在内容提供商中,因此如果卸载该应用程序,则使用该应用程序的所有应用程序的“共享”数据都将丢失。对于我来说,这很好。

不清楚为什么每个应用程序都没有自己的
ContentProvider
,因为每个应用程序都可以按任何顺序安装。另一种选择是使用主应用程序管理所有数据/处理,但需要二次安装。
。除非有一种方法可以创建任何应用都可以初始化的内容提供商(如果它是第一个应用),否则我不确定如何继续此解决方案
Yes。这是可能的,因为您可以将android:enabled=“false”添加到该提供者标记。然后在运行时,应用程序可以根据需要启用它。
...
resValue "string", "shared_storage_provider_authority", applicationId + ".SharedStorageProvider." + project.env.get("APP_GROUP") // Used to generate dynamic authority name
...