多个应用程序使用相同的内容提供商
我正在开发一组仅适用于某些品牌的应用程序(请考虑不同的运动队);然而,我遇到了一个问题,我正在为所有特定品牌的应用程序使用一个库项目,并希望为所有这些应用程序使用相同的ContentProvider。在创建ContentProvider时,我将AUTHORITY声明为类中的常量(根据开发示例代码),并且我在清单文件中的每个特定应用程序中使用相同的权限。它看起来像我不能用跨越每一个应用程序一样的权限,因为我在尝试安装第二个应用程序时,这个错误(我安装一个品牌一个就好了,但第二个安装):多个应用程序使用相同的内容提供商
WARN/PackageManager(66): Can't install because provider name com.xxx.Provider (in package com.xxx) is already used by com.zzz
我已经尝试了几种方法,但他们似乎都没有工作。我还没有做的一个想法是创建一个库jar,只是省略了我的Provider类并在每个特定的应用程序中对其进行了自定义。任何想法如何解决这个问题而不诉诸于此?
ContentProviders由权威机构标识,因此它必须是唯一的。我不认为这有什么窍门。
此外,Android平台中存在一个错误,即使它们具有不同的权限并且包含在单独的APK中,也会阻止为两个不同的ContentProviders使用相同的类名。查看错误here。
我建议你的解决方案是在你的库项目中创建抽象提供者类,然后在每个单独的应用程序中用一个唯一的名称来扩展它。为了实现这一点,您可能需要创建一个脚本来生成/修改个别清单和内容提供程序类。
希望这会有所帮助。
比方说你 库包com.android.app.library
免费包com.android.app.free
支付包com.android.app.paid
在免费的项目和支付项目,使这可以是任何一个包相同的文件,但必须是相同。
例子:
在您的免费版本com.android.app.data创建一个新的包
-
创建一个名为Authority.java和内部文件(Authority.java)提出:
public class Authority {
`public static final String CONTENT_AUTHORITY = "YOUR PROVIDER";`
}
对付费版本重复此操作,请记住保留包名称与类名称相同。现在
,在你的合同文件,在资料库中使用以下命令:
public static String AUTHORITY = initAuthority();
private static String initAuthority() {
String authority = "something.went.wrong.if.this.is.used";
try {
ClassLoader loader = Contract.class.getClassLoader();
Class<?> clz = loader.loadClass("com.android.app.data.Authority");
Field declaredField = clz.getDeclaredField("CONTENT_AUTHORITY");
authority = declaredField.get(null).toString();
} catch (ClassNotFoundException e) {}
catch (NoSuchFieldException e) {}
catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
return authority;
}
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
现在你应该可以使用两个部门。
来源:伊恩Warick(代码写了) Android - Having Provider authority in the app project 免责声明:我张贴在这里还有:Android duplicate provider authority problem - 不知道是否允许使用同样的答案回答同一个类型的问题。
可以使用以下方法将ContentProvider打包到库中,并在运行时设置ContentProvider的权限,以便在没有ContentProvider权限冲突的情况下将其包含到多个项目中。这是有效的,因为真正的'权威'来自AndroidManifest ...而不是ContentProvider类。
先从基本的ContentProvider implementation..AUTHORITY,CONTENT_URI和UriMatcher是静态的,而不是 '最终' ....
public class MyContentProvider extends ContentProvider {
public static String AUTHORITY = "com.foo.bar.content";
public static Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
protected static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
然后,重写 'attachInfo' 的方法,这样当的ContentProvider首先被初始化,你的ContentProvider将被从AndroidManifest收集到的ProviderInfo调用。这将在进行任何可能的查询之前发生,很可能在初始应用程序类设置期间进行。使用此机会将AUTHORITY,CONTENT_URI和UriMatcher重置为其“真实”值,如使用ContentProvider库的应用程序所提供的。
@Override
public void attachInfo(Context context, ProviderInfo info) {
super.attachInfo(context, info);
AUTHORITY = info.authority;
CONTENT_URI = Uri.parse("content://" + AUTHORITY);
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, AlarmTable.TABLENAME, ALARMS);
uriMatcher.addURI(AUTHORITY, AttributeTable.TABLENAME, ATTRIBUTES);
uriMatcher.addURI(AUTHORITY, DeepLinkTable.TABLENAME, DEEPLINKS);
uriMatcher.addURI(AUTHORITY, NotificationTable.TABLENAME, NOTIFICATIONS);
uriMatcher.addURI(AUTHORITY, MetaDataTable.TABLENAME, RESOURCE_METADATA);
uriMatcher.addURI(AUTHORITY, ResourceTable.TABLENAME, RESOURCES);
uriMatcher.addURI(AUTHORITY, ResourceAttributeTable.TABLENAME, RESOURCES_ATTRIBUTES);
uriMatcher.addURI(AUTHORITY, ResourceTagTable.TABLENAME, RESOURCES_TAGS);
uriMatcher.addURI(AUTHORITY, TagTable.TABLENAME, TAGS);
uriMatcher.addURI(AUTHORITY, UserTagTable.TABLENAME, USER_TAGS);
uriMatcher.addURI(AUTHORITY, UserTable.TABLENAME, USERS);
uriMatcher.addURI(AUTHORITY, CUSTOM, RAW);
}
当应用程序启动时,ContentProvider的实际上是与应用类一起实例化,所以将有机会获得所有所需的程序包信息。 ProviderInfo对象将包含AndroidManifest中提供的信息...包含在最终应用程序中的列表。
<provider android:authorities="com.foo.barapp.content"
android:name="com.foo.bar.MyContentProvider"/>
管理局现将“com.foo.barapp.content”,而不是默认值改写,而UriMatcher将被更新到应用程序的价值,而不是默认。依赖于“AUTHORITY”的类现在将访问更新的值,并且UriMatcher将正确区分传入的查询“com.foo.barapp.content”。
我已经同时测试了这两个示例应用程序和androidTest包,并发现它能正常工作。
这是一个古老的问题,但我最近在做类似的事情。建立口味,现在它非常简单。
指定BuildConfigField在gradle这个文件:
productFlavors {
free {
applicationId "com.example.free"
buildConfigField 'String', 'AUTHORITY', '"com.example.free.contentprovider"'
}
paid {
applicationId "com.example.paid"
buildConfigField 'String', 'AUTHORITY', '"com.example.paid.contentprovider"'
}
在清单中指定的供应商授权:
<provider
android:name=".ContentProvider"
android:authorities="${applicationId}.contentprovider" />
设置在使用BuildConfigField变量提供者的权力:
public static final String AUTHORITY = BuildConfig.AUTHORITY
这应该是新接受的答案。尽管可以避免在运行时使用getApplicationContext()。getPackageName()来创建'buildConfigField'。 – 2017-11-08 01:08:39
你可以!
如this post说(至极解释了火力地堡怎么没有给它从你的Application#onCreate()
方法的情况下初始化其库),你可以在你的清单使用占位符,就像这样:
<provider
android:authorities="${applicationId}.yourcontentprovider"
android:name=".YourContentProvider" />
你可以尝试申请我的解决方案为类似的任务:http:// *。com/a/15964372/1220237 – Sash0k 2013-04-12 06:19:11