Виджет с контент-провайдером; невозможно использовать ReadPermission? - PullRequest
18 голосов
/ 29 февраля 2012

Итак, я только что реализовал виджет для своего приложения. Он получает свои данные из базы данных через мой 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 с виджетом? Или вы вынуждены использовать незащищенного экспортированного поставщика?

Ответы [ 2 ]

21 голосов
/ 02 октября 2013

Мне удалось найти ответ здесь , кредит идет на Костю Васильева.

Хотя контекст на самом деле правильный, он связан с неправильным процессом.

Итак, ключ к этому:

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 голосов
/ 02 октября 2013

Скорее всего, это потому, что вы используете контекст виджета, который будет контекстом домашнего экрана.Попробуйте следующую строку в вашем коде:

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

Обратите внимание, как я заменил mContext..Служба - это собственный контекст, который должен иметь правильное разрешение с учетом вашего манифеста.

...