14

我有一个小部件,我试图用它在列表视图中显示来自应用程序本地数据库的信息。

我正在使用 RemoteViewsService.RemoteViewsFactory 接口来加载列表的内容。如果我运行在 onDataSetChanged 方法中重新加载列表的代码块。该应用程序崩溃并显示以下消息:

11-01 16:40:39.540: E/ACRA(27175): DataDisplay fatal error : Permission Denial: reading com.datadisplay.content.ContentProviderAdapter uri content://com.datadisplay.provider.internalDB/events from pid=573, uid=10029 requires the provider be exported, or grantUriPermission()

但是,在类的构造函数中运行的相同代码可以正常工作。当然,我需要让这个也可以在 onDataSetChanged 方法中进行更新和填充。

这是我的提供商在清单中的条目:

    <provider android:name="com.datadisplay.content.ContentProviderAdapter"
        android:authorities="com.datadisplay.provider.internalDB"
        android:exported="true"
        android:enabled="true"
        android:grantUriPermissions="true">
            <grant-uri-permission android:pathPattern="/events/"/>
    </provider>

我正在导出它并授予 Uri 权限,如错误消息请求,但它仍然失败。我发现了这个问题,这家伙遇到了问题,但最终删除了他的自定义权限并且它起作用了。我没有这样的自定义权限,但仍然没有运气:

带有内容提供者的小部件;无法使用 ReadPermission?

如果有人有见识,我将不胜感激,这令人难以置信的沮丧,哈哈。

4

3 回答 3

31

This is happening because RemoteViewsFactory is being called from a remote process, and that context is being used for permission enforcement. (The remote caller doesn't have permission to use your provider, so it throws a SecurityException.)

To solve this, you can clear the identity of the remote process, so that permission enforcement is checked against your app instead of against the remote caller. Here's a common pattern you'll find across the platform:

final long token = Binder.clearCallingIdentity();
try {
    [perform your query, etc]
} finally {
    Binder.restoreCallingIdentity(token);
}
于 2013-12-17T22:19:55.637 回答
9

如果这只发生在 4.2 而不是其余版本,则需要设置 android:exported="true",因为默认值已更改:http: //developer.android.com/about/versions/android-4.2.html

默认情况下不再导出内容提供程序。也就是说,android:exported 属性的默认值现在是“false”。如果其他应用能够访问您的内容提供程序很重要,您现在必须显式设置 android:exported="true"。

于 2013-01-09T14:16:57.417 回答
9

把它放在你的onDataSetChanged()方法中:

    Thread thread = new Thread() {
        public void run() {
            query();
        }
    };
    thread.start();
    try {
        thread.join();
    } catch (InterruptedException e) {
    }

query()从内部方法的数据库中获取数据。我不知道为什么在单独的线程中获取数据有助于解决这个问题,但它确实有效!我从其中一个 Android 示例中得到了这个。

于 2012-11-02T14:47:43.837 回答