内容提供商的小部件;不可能使用ReadPermission?

问题描述 投票:18回答:2

所以我刚为我的应用程序实现了一个小部件。它通过我的ContentProvider从数据库中获取数据。我在清单中定义了自己的读/写权限,说明我使用它们(似乎没有什么区别),并在内容提供程序中要求它们:

<!-- Define my permissions for the provider -->
<permission
    android:name="com.nononsenseapps.notepad.permissions.read"
    android:description="@string/permission_read_desc"
    android:label="@string/permission_read_label"
    android:permissionGroup="android.permission-group.PERSONAL_INFO"
    android:protectionLevel="normal" />
<permission
    android:name="com.nononsenseapps.notepad.permissions.write"
    android:description="@string/permission_write_desc"
    android:label="@string/permission_write_label"
    android:permissionGroup="android.permission-group.PERSONAL_INFO"
    android:protectionLevel="normal" />
......
<uses-permission android:name="com.nononsenseapps.notepad.permissions.read" />
<uses-permission android:name="com.nononsenseapps.notepad.permissions.write" />
<uses-permission android:name="android.permission.BIND_REMOTEVIEWS" />
......
<provider
        android:name=".NotePadProvider"
        android:authorities="com.nononsenseapps.NotePad"
        android:enabled="true"
        android:exported="true"
        android:label="@string/app_name"
        android:readPermission="com.nononsenseapps.notepad.permissions.read"
        android:syncable="true"
        android:writePermission="com.nononsenseapps.notepad.permissions.write" >
        <grant-uri-permission android:pathPattern=".*" />
    </provider>

我通过Service更新我的小部件(根据小部件教程):

    <!-- List Widget -->
    <receiver android:name="com.nononsenseapps.notepad.widget.ListWidgetProvider" >
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>

        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/listwidgetinfo" />
    </receiver>

    <service
        android:name="com.nononsenseapps.notepad.widget.ListWidgetService"
        android:exported="false"
        android:permission="android.permission.BIND_REMOTEVIEWS" />

Service反过来做这个(不包括一堆代码):

/**
 * This is the service that provides the factory to be bound to the collection
 * service.
 */
public class ListWidgetService extends RemoteViewsService {

@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
    return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
}
}

/**
 * This is the factory that will provide data to the collection widget.
 */
class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {

public StackRemoteViewsFactory(Context context, Intent intent) {
    mContext = context;
    observer = new ListChecker(null);
    mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
            AppWidgetManager.INVALID_APPWIDGET_ID);
}
public void onDataSetChanged() {
    Log.d(TAG, "onDataSetChanged");
    // Refresh the cursor
    if (mCursor != null) {
        mCursor.close();
    }

    // Get widget settings
    SharedPreferences settings = mContext.getSharedPreferences(
            ListWidgetConfigure.getSharedPrefsFile(mAppWidgetId),
            mContext.MODE_PRIVATE);
    if (settings != null) {
        String listWhere = settings.getString(ListWidgetConfigure.LIST_WHERE, null);
        listId  = settings.getLong(ListWidgetConfigure.LIST_ID, -1);
        String sortOn = settings.getString(ListWidgetConfigure.SORT_ON, NotePad.Notes.ALPHABETIC_ASC_ORDER);

        mCursor = mContext.getContentResolver().query(
                NotePadProvider.CONTENT_VISIBLE_URI, PROJECTION, listWhere, null,
                sortOn);
    }
}
}

所以这就是问题所在:当我将小部件添加到主屏幕时,当我尝试查询提供程序时,SecurityException会立即抛出onDataSetChanged()。这似乎是因为主屏幕不具有读取我的内容提供商的权限。我的直觉是,这不会是一个问题,因为我自己的应用程序有权限,而且服务显然是我的应用程序的一部分。

如果我从提供程序中删除ReadPermission要求,一切都会很好地工作。但这似乎是一个安全问题,因为任何应用程序都可以访问提供程序而无需用户批准任何内容。

那么是否有一种方法可以将具有ReadPermission的提供程序与窗口小部件一起使用?或者您被迫使用不安全的导出提供商?

android android-widget android-contentprovider
2个回答
21
投票

我能够找到答案here,归功于Kostya Vasilyev。

虽然上下文实际上是正确的,但它必然是错误的过程。

所以关键是这样做:

public void onDataSetChanged() {
     // Revert back to our process' identity so we can work with our
     // content provider
     final long identityToken = Binder.clearCallingIdentity();

     // Update your cursor or whatever here
     // ...

     // Restore the identity - not sure if it's needed since we're going
     // to return right here, but it just *seems* cleaner
     Binder.restoreCallingIdentity(identityToken);
}

0
投票

最有可能的是,这是因为您正在使用小部件的上下文,这将是主屏幕的上下文。在代码中尝试以下行:

mCursor = ListWidgetService.this.getContentResolver().query(
            NotePadProvider.CONTENT_VISIBLE_URI, PROJECTION, listWhere, null,
            sortOn);

请注意我是如何取代mContext.的。服务是一个自己的上下文,根据您的清单,它应该具有正确的权限。

© www.soinside.com 2019 - 2024. All rights reserved.