Подтвердить что ты не робот

Пользовательские разрешения Android - Marshmallow

Фон

Исторически, пользовательские разрешения Android были беспорядок и были установить порядок в зависимости от, который был известен подвергать уязвимости.

До API 21 возникло нерешенное временное решение, в котором объявлялось пользовательское разрешение другого приложения в вашем манифесте, предоставлялось разрешение... Однако, поскольку API 21, только одно приложение может объявлять пользовательское разрешение и устанавливать дальнейшее приложение, объявляющее это же разрешение, будет предотвращено.

Альтернативой является переустановка приложения, требующего разрешения, поэтому они обнаруживаются системой, но не является хорошим пользовательским интерфейсом. Или проверьте во время выполнения для разрешений вызывающего приложения, но который не лишен теоретических недостатков.

Проблема

Как и в Android Marshmallow (6.0 - API 23), приложение должно запросить разрешение от пользователя , чтобы использовать собственное пользовательское разрешение. Объявленное пользовательское разрешение не предоставляется автоматически.

Это кажется странным, учитывая, что только одно приложение может объявить его.

Чтобы реплицировать

Объявить пользовательское разрешение и BroadcastReceiver в манифесте.

<permission
    android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"
    android:description="@string/control_description"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/control_label"
    android:protectionLevel="normal or dangerous"/>

<uses-permission
    android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>

// etc

<receiver
    android:name="com.example.app.MyBroadcastReceiver"
    android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
    <intent-filter android:priority="999">
        <action android:name="com.example.app.REQUEST_RECEIVER"/>
    </intent-filter>
</receiver>

От стороннего приложения объявите, что он использует пользовательские разрешения в манифесте (и принимает его через диалог или настройки) и вызывает:

    final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER");

    context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {

        // getResultCode();

        }
    }, null, Activity.RESULT_CANCELED, null, null);

Результат вернет CANCELED, и журнал покажет:

system_process W/BroadcastQueue: отказ в разрешении: получение Intent { act = com.example.app.REQUEST_RECEIVER flg = 0x10 (имеет дополнительные функции)} to com.example.app/.MyBroadcastReceiver требует com.example.app.permission.CONTROL_EXAMPLE_APP из-за отправителя com.example.thirdparty

Если я использую стандартное диалоговое окно ActivityCompat.requestPermissions(), чтобы позволить пользователю принять разрешение, приемник, как и следовало ожидать, работает правильно.

Вопрос

Является ли это ожидаемым поведением? Или я почему-то не заметил чего-то?

Казалось бы, смешно поднимать диалог, говорящий

Приложение Пример приложения хочет получить разрешение на использование примера App

И это действительно может касаться пользователя, предоставляя им такой бессмысленный запрос.

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

Примечание

Пример упорядоченной передачи - это репликация проблемы. Мое приложение использует другие реализации поставщиков контента и связанную службу. Это не альтернативная реализация, которую я требую, это подтверждение проблемы.

Благодарим за то, что вы читаете это.

Изменить: Чтобы уточнить, для других реализаций, таких как объявление разрешения на службу (которое было бы наиболее простым для репликации), автоматически предоставляется объявленное пользовательское разрешение.

4b9b3361

Ответ 1

Как я понял, вы пытались сделать следующее (по крайней мере, как я смог воспроизвести вашу проблему):

  • Вначале вы объявляете свое новое пользовательское разрешение (разрешаете его F) приложение

    <permission
        android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"
        android:description="@string/control_description"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/control_label"
        android:protectionLevel="normal or dangerous"/>
    
  • Вы определяете, что ваше приложение F использует разрешение com.example.app.permission.CONTROL_EXAMPLE_APP. Это правильно, как говорится в руководстве.

    <uses-permission
        android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
    
  • Вы объявляете свой собственный широковещательный приемник в своем приложении F. Чтобы общаться с этой трансляцией вашего приложения (независимо от того, какой из них, F или другого приложения), вы должны получить свое пользовательское разрешение.

    <receiver
        android:name="com.example.app.MyBroadcastReceiver"
        android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
        <intent-filter android:priority="999">
            <action android:name="com.example.app.REQUEST_RECEIVER"/>
        </intent-filter>
    </receiver>
    
  • Вы определяете, что второе (позволяет использовать его S) приложение использует разрешение com.example.app.permission.CONTROL_EXAMPLE_APP. Поскольку вы хотите разрешить S-приложению отправлять широковещательные сообщения в приемник F-приложений.

    <uses-permission
        android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
    
  • Наконец, вы пытаетесь отправить широковещательное сообщение из своего S-приложения, используя этот код.

    final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER");
    context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() {
            @Override
            public void onReceive(final Context context, final Intent intent) {
                // getResultCode();
            }
        }, null, Activity.RESULT_CANCELED, null, null);
    

    И, это важно, вы предоставили разрешение своему S-приложению, но вы не предоставили разрешение своему F-приложению.

    В результате ваш вещательный приемник, заявленный в приложении F, ничего не получил.

  • После того, как вы предоставили разрешение на свое приложение F (обратите внимание, что теперь S и F предоставили вам собственное разрешение), все работает нормально. Приемник широковещательной передачи, заявленный в приложении F, получил сообщение из приложения S.

Я думаю, что это правильное поведение, потому что этот doc говорит нам:

Обратите внимание, что в этом примере разрешение DEBIT_ACCT не только объявленный элементом, его использование также запрашивается с элемент. Вы должны запросить его использование, чтобы другие компоненты приложения для запуска защищенной деятельности, даже если защита наложена самим приложением.

И приложение, объявляющее разрешение, также должно запрашивать одно и то же разрешение для связи с самим собой.

Как результат, API-интерфейс Android 23 должен получить доступ, прежде всего, для использования вашей формы разрешения. И мы должны получить 2 предоставленных разрешения, сначала из приложения F (потому что guidline говорит, что и это), и второе из S приложения (потому что нам просто нужно получить доступ).

Но я не поймал ваш следующий момент:

Казалось бы, смешно поднимать диалог, говорящий

Приложение Пример приложения хочет получить разрешение на использование примера App

Мой родной Android API 23 показывает мне что-то вроде этого:

Приложение примера приложения хочет

Ответ 2

Я думаю, что проблема в вашем примере заключается в том, что вы явно требуете, чтобы оба приложения получили пользовательское разрешение.

Эта часть требует, чтобы приложение com.example.thirdparty имело разрешение:

<receiver
    android:name="com.example.app.MyBroadcastReceiver"
    android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">

И эта часть требует, чтобы приложение com.example.app также имело разрешение:

context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", ...

Вы упомянули, что у вас нет этой проблемы при использовании службы. Я не знаю, как именно вы используете службу, но если вы просто объявляете ее так:

<service
    android:name="com.example.app.MyService"
    android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">

а затем привяжите его следующим образом:

context.bindService(serviceIntent, mServiceConnection, ...

тогда это достаточно, если com.example.thirdparty имеет предоставленное разрешение, в то время как com.example.app не нуждается в нем.

Другими словами, я думаю, что это поведение по дизайну, и разница, которую вы видите между поведением Broadcast и Service, заключается в том, что в случае Broadcast вы специально запрашиваете, что com.example.app имеет специальное разрешение, тогда как в Служебный случай у вас нет.

Надеюсь, я не понял вашу проблему неправильно. Если да, сообщите мне, и я удалю этот ответ.

Ответ 3

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

Ответ 4

Хотя для пользователя может быть неоднозначно видеть запрос на разрешение для приложения, которое объявлено в том же приложении, это то, как андроид предназначен для запуска с зефира. Я думаю, на перспективу андроида поведение по-своему и правильно.

Ответ 5

Сначала добавьте разрешения в файл манифеста после

 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />