Android自定义权限 – 棉花糖

背景

从历史上看,Android自定义权限一直是一团糟,并且依赖于安装顺序 ,这已知会泄露漏洞 。

在API 21之前,有一个令人不安的解决方法,即在你的Manifest中声明另一个应用程序的自定义许可,授予许可…但是,由于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> 

从第三方应用程序中,声明它使用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:Permission Denial:receiving Intent {act = com.example.app.REQUEST_RECEIVER flg = 0x10(have extras)} to com.example.app/.MyBroadcastReceiver requires com.example.app.permission.CONTROL_EXAMPLE_APP due to sender com.example.thirdparty

如果我使用标准的ActivityCompat.requestPermissions()对话框来允许用户接受权限,接收者就像你所期望的那样工作正常。

这是预期的行为? 或者我忽略了某些东西?

提出一个对话说话似乎是荒谬的

应用示例应用想要使用示例应用的权限

它确实可能会关注用户,为他们提供这样一个无意义的请求。

我当然可以将权限描述和名称改为他们接受的东西,比如“ 与其他已安装的应用程序通信 ”,但是在我叹息并采取这种方法之前,我想我会问这个问题。

注意

有序广播的例子是复制问题。 我的应用程序确实使用内容提供者和绑定服务的其他实现。 这不是我所需要的替代实施,而是对问题的确认。

感谢您阅读这个。

编辑:为了澄清,对于其他实现,例如声明一个服务的权限(这将是最容易复制)声明的自定义权限是自动授予。

Related of "Android自定义权限 – 棉花糖"

据我了解,你试图做下一件事(至less,这是我能够重现你的问题):

  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"/> 
  2. 您定义您的F应用程序使用com.example.app.permission.CONTROL_EXAMPLE_APP权限。 指引说的是对的。

     <uses-permission android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/> 
  3. 您在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> 
  4. 你定义你第二个(让我们称之为S)应用程序使用com.example.app.permission.CONTROL_EXAMPLE_APP权限。 因为你想允许S app向F app接收者发送广播消息。

     <uses-permission android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/> 
  5. 最后,您尝试使用此代码从您的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应用程序中声明的广播接收器没有收到任何东西。

  6. 在您授予您的F应用程序许可后(请注意,现在S和F授予您的自定义许可)一切正常。 在F app中声明的广播接收者收到来自S app的消息。

我想这是正确的行为,因为这个文件告诉我们:

请注意,在这个例子中,DEBIT_ACCT权限不仅用元素声明,还用元素请求它的使用。 您必须请求使用它,以便应用程序的其他组件启动受保护的活动,即使该保护是由应用程序本身施加的。

而声明权限的应用程序也必须请求相同的权限才能与自己进行通信。

因此,android API 23应该首先获得使用您的权限表单用户的权限。 我们必须得到2个授予的权限,首先从F应用程序(因为guidline说的那样),第二个从S应用程序(因为我们只需要访问)。

但是我没有理解你的下一个观点:

提出一个对话说话似乎是荒谬的

应用示例应用想要使用示例应用的权限

我的原生Android API 23显示了类似这样的内容:

应用示例应用需要

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

这部分要求, 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不需要拥有它。

换句话说,我认为这种行为是有意devise的,而你在广播和服务行为之间所看到的差异是因为在广播情况下,你特别要求com.example.app具有自定义权限,而在服务情况下别。

我希望我没有误解你的问题。 如果我这样做,请让我知道,我会删除这个回应。

我不认为声明的自定义权限不会被自动授予应用程序是完全正确的。 对于自定义权限具有“正常”或“签名”保护级别的情况,则在安装时授予权限。 否则,如果保护级别是“危险的”,那么它是一个运行时权限,并且与其他危险权限一样工作:您将需要提示用户授予应用程序权限。

虽然用户看到在同一个应用程序中声明的应用程序的许可请求可能是模糊的,但它是如何devise运行自棉花糖。 我认为,从Android的angular度来看,这种行为是有目的和正确的。

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

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