Android自定义权限-Marshmallow

2024-03-20

背景

从历史上看,Android 自定义权限已经一团糟 https://code.google.com/p/android/issues/detail?id=65864 and 取决于安装顺序 https://code.google.com/p/android/issues/detail?id=25906,众所周知暴露漏洞 https://commonsware.com/blog/2014/02/12/vulnerabilities-custom-permissions.html.

在 API 21 之前,有一个令人不安的解决方法,即在清单中声明另一个应用程序的自定义权限,并授予该权限...但是,自 API 21 以来,只有一个应用程序可以声明自定义权限,并安装另一个应用程序声明同样的许可将被阻止。

替代方法是重新安装需要权限的应用程序,以便系统检测到它们,但是不是一个好的用户体验 https://stackoverflow.com/questions/10620464/reinstall-application-apk-programmatically-without-downloading。或者在运行时检查调用应用程序的权限,但是这并非没有理论缺陷 https://stackoverflow.com/questions/18573139/programmatically-alter-manifest-android-custom-permissions.

Problem

从 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>

从第三方应用程序中,声明它使用清单中的自定义权限(并通过对话框或设置接受它)并调用:

    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:权限拒绝:接收意图{ act=com.example.app.REQUEST_RECEIVER flg=0x10 (有额外内容) } 到 com.example.app/.MyBroadcastReceiver 需要 com.example.app.permission.CONTROL_EXAMPLE_APP 由于发件人 com.example.thirdparty

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

Question

这是预期的行为吗?还是我忽略了一些事情?

提出一个对话说似乎很荒谬

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

它可能确实让用户担心,向他们提供这样一个无意义的请求。

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

Note

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

感谢您阅读本文。

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


据我了解,您尝试做下一步(至少,这就是我能够重现您的问题的方式):

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

    And, 这个很重要,您向 S 应用授予了权限,但未向 F 应用授予权限。

    结果,您在 F 应用程序中声明的广播接收器没有收到任何内容。

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

我想这是正确的行为,因为这是doc https://developer.android.com/guide/topics/manifest/manifest-intro.html#perms我们说:

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

并且声明权限的应用程序也必须请求相同的权限才能与自身通信。

因此,android API 23 应该首先获得用户的许可。我们必须获得 2 个授予的权限,第一个来自 F 应用程序(因为指南是这么说的),第二个来自 S 应用程序(因为我们只需要获得访问权限)。

但我没有明白你的下一点:

提出一个对话说似乎很荒谬

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

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

应用程序示例应用程序想要

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android自定义权限-Marshmallow 的相关文章

随机推荐

  • 如何从 Nexus 存储库请求工件的大小?

    我知道 Nexus 支持 REST 请求 您能告诉我如何根据 Nexus 从存储库请求某些工件的大小吗 谢谢 您有以下选项 使用工件内容 URI 的完整路径并添加参数describe info 例如 https repository son
  • 如何将要渲染的任意窗口重定向到内存中的后缓冲区?

    我正在尝试一个自行开发的应用程序托管框架 并且我想抽象输入 输出 以便我可以优雅地处理崩溃 Chrome 使用非常相似的模型 有什么方法可以获取任意窗口句柄 并说服它开始渲染到后缓冲区吗 或者我应该首先创建自己的窗口 然后将客户端应用程序重
  • 如何告诉 TypeScript 接口 T 比具有索引签名的类型 U 窄?

    我有一个函数可以验证 JSON 响应以确保它对应于给定的形状 以下是我的类型 定义了所有可能的 JSON 值 取自https github com microsoft TypeScript issues 1897 issuecomment
  • 如何更改操作栏上的文本

    目前它只显示应用程序的名称 我希望它显示自定义的内容并且对于我的应用程序中的每个屏幕都不同 例如 我的主屏幕可以在操作栏中显示 page1 而应用程序切换到的另一个活动可以在该屏幕操作栏中显示 page2 更新 最新的 ActionBar
  • Android 应用程序中的 VideoView 全屏

    我的应用程序中有一个视频视图 代码是这样的
  • 加载时将 Google 地图信息窗口居中

    我在将 InfoWindow 集中在页面加载时遇到问题 加载时 地图以标记为中心 这使 InfoWindow 离开屏幕 我正在使用地图容器的较短高度 现在 单击标记确实会将地图重新 置于信息窗口的中心 使其看起来与我想要的一模一样 在这种情
  • 访问其他层中的对象(cocos2d)

    我正在用操纵杆在一层中移动精灵 现在 根据最佳实践 操纵杆和精灵必须位于同一场景的不同层中 我已经设法将它们分开 但我现在完全陷入困境 完全不知道如何将操纵杆命令从一层传递到另一层 推荐的方法是什么 Scene Game Play Laye
  • 图像中的隐形水印[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在 JavaFX 8 中管理多线程的最佳方法是什么?

    我正在尝试找到一种有效的方法来影响 JavaFX GUI 元素的形状和内容 例如简单的Pane 使用多线程 假设我有一个简单的Pane 我在其上显示已填充Circle在给定的时间间隔内 我希望有可能回答它们 例如通过按相应的键 到目前为止
  • 向 Jira 的 api 添加附件

    我正在尝试使用他们的 API 将文件附加到 Jira 案例 我在 Drupal 6 PHP v 5 0 中执行此操作 这是我的代码 ch curl init header array Content Type multipart form
  • 身份验证时出现 umbraco 公共访问错误

    我在 Umbraco 7 中的公共访问方面遇到问题 我使用自定义会员资格提供商通过 CRM 数据库对用户进行身份验证 我设置了一条规则来允许访问仅经过身份验证的 前端 用户我使用自定义角色提供程序来定义经过身份验证的用户具有访客角色 如果未
  • 未找到 GoogleWebAuthorizationBroker

    我正在学习 C 为 Windows Phone 开发 并且我正在尝试验证我的用户进入 Google 帐户 我使用这个代码 https developers google com api client library dotnet guide
  • 如何使用 JavaScript 将非英语字符转换为英语

    我有一个 C 函数 它将所有非英语字符转换为给定文本的正确字符 就像下面这样 public static string convertString string phrase int maxLength 100 string str phr
  • 使用 pandas 删除 Excel 中的标题行

    我有一个带有合并标题的 Excel 文件 我使用 pandas 将其读取为数据框 之后看起来像这样pd read excel Unnamed 0 Pair Unnamed 1 Type Unnamed 23 cabinet name gro
  • 设计时 XAML 的默认值

    我有一个绑定的TextBlock XAML
  • C 复数和 printf

    如何打印 使用 printf 复数 例如 如果我有以下代码 include
  • 针对一组测试最小汉明距离的算法?

    我想做一件相对简单的事情 给定一个查询号码Q 查询距离d 和一组数字S 判断是否S包含any汉明距离小于或等于的数字d 最简单的解决方案就是使S一个列表并迭代它 计算距离 如果计算出的距离小于或等于 d 则退出返回TRUE 但考虑到我想做的
  • 在python中打印对象/实例名称

    我想知道是否有一种方法可以将 python 中的对象名称打印为字符串 例如 我希望能够说 ENEMY1 还剩 2 马力 或者 ENEMY2 还剩 4 马力 有办法做到这一点吗 class badguy def init self self
  • 更精确的Thread.Sleep

    我该如何做 Thread Sleep 10 4166667 好吧 我现在明白了 睡眠不是一条出路 所以我使用计时器 但计时器也是以毫秒为单位 我需要更精确 有纳秒精度的计时器吗 那么您希望您的线程恰好在该时间休眠然后恢复 忘掉它 该参数告诉
  • Android自定义权限-Marshmallow

    背景 从历史上看 Android 自定义权限已经一团糟 https code google com p android issues detail id 65864 and 取决于安装顺序 https code google com p a