Android 自定义权限 - 棉花糖

32

背景

历史上,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: Permission Denial: receiving Intent { act=com.example.app.REQUEST_RECEIVER flg=0x10 (has extras) } to com.example.app/.MyBroadcastReceiver requires com.example.app.permission.CONTROL_EXAMPLE_APP due to sender com.example.thirdparty
如果我使用标准的ActivityCompat.requestPermissions()对话框来允许用户接受权限,则接收器会像您预期的那样正常工作。
问题:
这是预期行为吗?还是我忽略了什么?
看起来要求用户弹出一个对话框,说“Example App应用程序想要使用Example App”,这似乎很荒谬,并且确实会让用户感到困惑。
当然,我可以更改权限描述和名称,以便他们接受,例如“与其他已安装的应用程序通信”,但在我叹了口气并采取这种方法之前,我想问一下这个问题。
注:
有序广播的示例是为了复制问题。我的应用程序确实使用了其他内容提供程序和绑定服务的实现。我需要确认的不是替代实现,而是问题本身。
感谢您一直阅读到这里。
编辑:为了澄清,对于其他实现,例如在服务上声明权限(最简单的复制方式),所声明的自定义权限会自动授予。

1
就我所知,至少在Android 7.1(Google Pixel)上,我无法重现您的问题。我将您的代码复制到一个新的Android Studio项目中,并没有遇到从客户端发送广播并获得响应的问题。现在,我的示例可能比您的简单(例如,两个应用程序都由相同的签名密钥签名)。如果您能创建一个始终能够重现此问题的示例应用程序,并且您可以在7.1上重现它,请提交问题报告(http://b.android.com),包括示例应用程序和完整说明。 - CommonsWare
只是为了明确,您是在询问如何以合理的方式请求用户的权限,使他不会拒绝吗?还是在询问当他拒绝您的权限时提出解决方案可能有哪些可能性?我有点困惑。 - Zulqurnain Jutt
我认为应用程序请求自己的权限可以被解释为“主开关”,类似于“让其他应用程序控制此应用程序”。即使第三方应用程序必须授予权限才能控制示例应用程序,但某些用户实际上可能正在使用它来完全禁用“可控性”功能。(但仍然很奇怪,例如服务自动获取自定义权限...) - Gyebro
5个回答

3

我理解您尝试做的事情(至少,这是我复制您的问题时的方式):

  1. You declare your new custom permission in first (lets call it F) application

    <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"/>
    
  2. You define that your F app uses com.example.app.permission.CONTROL_EXAMPLE_APP permission. That is right as the guideline says.

    <uses-permission
        android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
    
  3. You declare your custom broadcast receiver in your F app. To communicate with that broadcast your app (it's no matter which one, F or other app) must obtain your custom permission

    <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>
    
  4. You define that you second (lets call it S) application uses com.example.app.permission.CONTROL_EXAMPLE_APP permission. Because you want to allow S app to send broadcast messages to F app receiver.

    <uses-permission
        android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
    
  5. Finally you try to send broadcast message from your S app using this code.

    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);
    

    And, this is important, you granted permission to your S app, but you didn't grant permission to your F app.

    As result your broadcast receiver declared in F app didn't receive anything.

  6. After you granted permission to your F app (Note that now S and F granted your custom permission) everything works fine. Broadcast receiver declared in F app received message from S app.

我想这是正确的行为,因为这个文档告诉我们:(链接)
请注意,在此示例中,DEBIT_ACCT权限不仅声明为元素,而且还使用元素请求其使用。您必须请求其使用,以便应用程序的其他组件启动受保护的活动,即使保护是由应用程序本身强制执行。
同时,声明权限的应用也必须请求相同的权限与自己通信。
结果,Android API 23首先需要从用户那里获取访问权限。我们需要获得两个已授权的权限:第一个来自F应用程序(因为指南要求如此),第二个来自S应用程序(因为我们只需要获得访问权限)。
但我没有理解你下一步的意思:
似乎提出对话框说
Example App应用程序想要使用Example App 看起来很荒谬。
我的本机Android API 23会显示类似于以下内容:
Example App应用程序想要

0

我认为声明自定义权限不会自动授予应用程序并非完全正确。当自定义权限具有“normal”或“signature”保护级别时,该权限将在安装时被授予。否则,如果保护级别为“dangerous”,则它是一项运行时权限,并且与其他危险权限一样工作:您需要提示用户授予应用程序权限。


0

我认为你的例子中存在的问题是你明确要求两个应用程序都被授予自定义权限。

这部分要求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拥有自定义权限,而在Service情况下,您没有。

我希望我没有误解您的问题。如果我误解了,请告诉我,我会删除此回复。


-1

虽然对于用户来说,在同一个应用程序中声明应用程序的权限请求可能会产生歧义,但这是安卓从棉花糖版本开始设计运行的方式。我认为,从安卓的角度来看,这种行为是预期和正确的。


这个语句不可能正确,因为在其他情况下自定义权限会被自动授予,因此它并非普遍“按设计”。 - brandall

-2

首先在清单文件中添加权限

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接