实际上您不必多次指定权限。在我们的OpenTasks Provider 中,我们在运行时从清单加载权限。
基本思路是这样的:
Context context = getContext();
PackageManager packageManager = context.getPackageManager();
ProviderInfo providerInfo = packageManager.getProviderInfo(
new ComponentName(context, this.getClass()),
PackageManager.GET_PROVIDERS | PackageManager.GET_META_DATA);
String authority = providerInfo.authority;
在 Android 2.2 上,您必须付出一些额外的努力,因为方法 getProviderInfo 尚不存在。
您也可以选择在字符串资源中指定权限并从清单中引用它,如下所示:
<provider
android:name=".provider.FeedProvider"
android:authorities="@string/authority"
android:exported="false" />
在您的内容提供者中,您照常加载权限:
String authority = getContext().getString(R.string.authority);
如果您的内容提供者服务于多个机构,这会有点困难,但无论如何这可能不是一个好主意。
更新以跟进您的评论:
我认为向合同提供Context 没有问题。
而不是写类似的东西
Cursor c = contentProvider.query(MyContract.Items.CONTENT_URI,
null, null, null, null);
你会写
Cursor c = contentProvider.query(MyContract.Items.itemsUri(getContext()),
null, null, null, null);
与
public final interface MyContract {
// ... lots of other tables ...
public final static class Items {
public final static String CONTENT_PATH = "items";
// all the contract definitions
public final static Uri itemsUri(Context context) {
return new Uri.Builder()
.scheme("content")
.authority(context.getString(R.string.authority)).
.path(CONTENT_PATH)
.build();
}
}
没有太大区别,只是当你还需要添加ID的时候会更方便:
Cursor c = contentProvider.query(MyContract.Items.itemUri(getContext(), myItemId),
null, null, null, null);
将Context 传递给这些静态方法通常不是问题,因为无论如何您都需要上下文来获得ContentResolver。
这种技术的一个优点是您的代码完全独立于实际权限,您可以轻松地将ContentProvider 作为库导入到具有不同权限的不同项目中,而无需更改一行你的代码。
顺便说一句,我更喜欢第一个版本(从清单加载权限),因为在这种情况下您甚至不需要字符串资源。你可以只inject ${applicationId} 并且永远不要再碰它。
以下清单 sn-p 保证您的权限对于您导入的每个应用程序都是唯一的:
<provider
android:name=".provider.FeedProvider"
android:authorities="${applicationId}.myauthority"
android:exported="false" />