Android 自定义权限 - Marshmallow
Posted
技术标签:
【中文标题】Android 自定义权限 - Marshmallow【英文标题】:Android custom permissions - Marshmallow 【发布时间】:2016-11-09 02:19:41 【问题描述】:背景
历史上,have been a mess 和 were install order dependent 的 android 自定义权限是 expose vulnerabilities 已知的。
在 API 21 之前,有一个令人不安的解决方法,即在您的清单中声明另一个应用程序的自定义权限,授予该权限...但是,从 API 21 开始,只有一个应用程序可以声明自定义权限并安装将阻止进一步声明相同权限的应用程序。
替代方法是重新安装需要权限的应用程序,以便系统检测到它们,但is not a good user experience。或者在运行时检查调用应用程序的权限,但是that is not without its theoretical flaws。
问题
从 Android Marshmallow (6.0 - API 23) 开始,应用程序需要向用户请求权限,才能使用自己的自定义权限。声明的自定义权限不会自动授予。
这似乎很奇怪,因为现在只有一个应用程序可以声明它。
复制
在 Manifest 中声明自定义权限和 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>
从第三方应用程序中,声明它使用 Manifest 中的自定义权限(并通过对话框或设置接受)并调用:
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(有附加功能) 到 com.example.app/.MyBroadcastReceiver 需要 com.example.app.permission.CONTROL_EXAMPLE_APP 由于发件人 com.example.thirdparty
如果我使用标准的ActivityCompat.requestPermissions()
对话框来允许用户接受权限,那么接收器正如您所期望的那样工作正常。
问题
这是预期的行为吗?还是我忽略了什么?
提出对话说似乎很荒谬
应用程序示例应用程序想要使用示例应用程序的权限
而且它可能确实让用户担心,向他们提供这样一个无意义的请求。
我当然可以将权限描述和名称更改为他们会接受的内容,例如“与其他已安装的应用程序通信”,但在我叹息并采取这种方法之前,我想我会问这个问题。
注意
有序广播的例子就是复制问题。我的应用程序确实使用了内容提供程序和绑定服务的其他实现。这不是我需要的替代实现,它是对问题的确认。
感谢您阅读本文。
编辑:澄清一下,对于其他实现,例如在服务上声明权限(这将是最简单的复制),声明的自定义权限是自动授予的。
【问题讨论】:
FWIW,我无法重现您的问题,至少在 Android 7.1(Google Pixel)上。我将您的代码复制到一个新的 Android Studio 项目中,并且从客户端向接收器发送广播并获得响应没有问题。现在,我的示例可能比您的示例更简单(例如,两个应用程序都由相同的签名密钥签名)。如果您可以创建一个始终重现此问题的示例应用程序,并且您可以在 7.1 上重现它,file an issue 针对开发人员预览版,包括示例应用程序和完整说明。 要明确一点,您是否要求指导如何以合理的方式向用户请求许可,他不会拒绝?或者您是否要求提出解决方案,以解决他拒绝您的许可时的可能性?我很困惑 我认为应用程序请求自己的权限这一事实可以解释为“主开关”,例如:“让其他应用程序控制这个应用程序”。即使必须在第三方应用程序中授予权限(也)才能控制示例应用程序,但某些用户实际上可能正在使用它来完全禁止“可控性”功能。 (但仍然很奇怪,例如服务会自动获得自定义权限......) 【参考方案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 app 向 F app 接收者发送广播消息。
<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 app 中声明的广播接收器收到了来自 S app 的消息。
我猜这是正确的行为,因为 doc 告诉我们:
请注意,在此示例中,DEBIT_ACCT 权限不仅 用元素声明,它的使用也被要求 元素。您必须请求使用它才能 应用程序的其他组件启动受保护的活动, 即使保护是由应用程序本身施加的。
声明权限的应用也必须请求相同的权限才能与自身通信。
因此,android API 23 应该首先获得使用您的许可表单用户的访问权限。我们必须获得 2 个授予的权限,第一个来自 F 应用(因为 guidline 这么说),第二个来自 S 应用(因为我们只需要获得访问权限)。
但我没听懂你的下一点:
提出对话说似乎很荒谬
应用程序示例应用程序想要使用示例应用程序的权限
我的原生 Android API 23 向我显示了类似的内容:
Example App 想要的应用程序
【讨论】:
【参考方案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不需要。
换句话说,我认为这种行为是设计使然,您看到的广播和服务行为之间的区别是因为在广播的情况下,您特别要求 com.example.app 具有自定义权限,而在服务案例中您没有。
希望我没有误解您的问题。如果我这样做了,请告诉我,我将删除此回复。
【讨论】:
【参考方案3】:我不认为声明的自定义权限不会自动授予应用程序是完全正确的。因为当自定义权限具有“正常”或“签名”保护级别时,则在安装时授予该权限。否则,如果保护级别为“危险”,则它是运行时权限,它的作用与其他危险权限一样:您需要提示用户将权限授予应用程序。
【讨论】:
【参考方案4】:虽然用户看到在同一个应用程序中声明的应用程序的权限请求可能是模棱两可的,但自棉花糖以来,这就是 android 的设计运行方式。我认为,从 android 的角度来看,这种行为符合预期且是正确的。
【讨论】:
这句话不可能是正确的,因为自定义权限是在其他情况下自动授予的——因此它不是普遍的“设计”【参考方案5】:先在manifest文件中添加权限后
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
【讨论】:
以上是关于Android 自定义权限 - Marshmallow的主要内容,如果未能解决你的问题,请参考以下文章