热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Androidactivityexported属性理解

背景这么久了,我自己看来对此属性的理解有点小偏差,当然不是表面上的理解误差,而是涉及到具体实现的细节。这里先贴下官方关于此属性的解释:android:exportedThisele

背景

这么久了,我自己看来对此属性的理解有点小偏差,当然不是表面上的理解误差,而是涉及到具体实现的细节。这里先贴下官方关于此属性的解释:

android:exported
This element sets whether the activity can be launched by components of other applications — “true” if it can be, and “false” if not. If “false”, the activity can be launched only by components of the same application or applications with the same user ID.
If you are using intent filters, you should not set this element “false”. If you do so, and an app tries to call the activity, system throws an ActivityNotFoundException. Instead, you should prevent other apps from calling the activity by not setting intent filters for it.

If you do not have intent filters, the default value for this element is “false”. If you set the element “true”, the activity is accessible to any app that knows its exact class name, but does not resolve when the system tries to match an implicit intent.

This attribute is not the only way to limit an activity’s exposure to other applications. You can also use a permission to limit the external entities that can invoke the activity (see the permission attribute).

这段文字说明,值得多读几遍!!!

由于我们团队的关系,我们开发的模块经常需要集成到多个app中,而我们不想为某个app单独维护一份代码,即我们的开发中,所有的宿主app用的都是同一套代码。比如就存在类似这样的代码:

android:name=".SubActivity"
android:cOnfigChanges="orientation|keyboardHidden"
android:exported="false" // 注意这行代码!!!
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden">







这样在宿主app里,通过打开mlpf://sub这样的短链就能轻松地来到我们模块的SubActivity。注意这里android:exported=false的设置,因为如果不设置的话,根据Android的规则只要有intent-filter存在,那么exported就是true,即对外暴露的;而这里我们显然不希望是对外暴露的,因为如果这样的话,当安装了多个集成了我们模块的App时,当要打开这样的短链请求时系统就会弹出选择框让用户选择在哪个app里打开,这当然不是我们期望的。

当同一个设备上装了我们的多个app的时候,在8.0之前都是ok的,即A app里的SubActivity和B app里的SubActivity互相是没任何关系的,也是互相看不到对方的,这是我们对exported=false的认识;直到上周某天晚上快要下班了,QA同学拿着升级到8.0的Nexus 6P跟我说,你看你们这个页面跳不过去了,还弹出了个讨厌的没有应用可执行此操作的提示,我当时也是一脸懵逼啊,但心里已经有种不祥的预感,看起来像是google改出来的bug。

我接过设备,点击了几下,确保能复现,然后连着电脑,看了下adb logcat关于ActivityManager相关的输出,果然我们这个intent没有找到对应的cmp(component),而是到了系统的ResolverActivity,ResolverAct大家都知道,当系统找到了多个目标或者没目标时会弹出它提醒用户。这就有点奇怪了,同样的case在7.x的设备上就是好的,虽然行为上也是到了ResolverAct,但ResolverAct内部最终还是导到了本app内部的SubActivity,最终正确调起了。

解惑

有一点我们需要知道,即当我们通过Intent打开act的时候,系统内部会调用
Intent.resolveActivity(pm),其内部又会接着调用PackageManager#resolveActivity。另外你也可以调用PackageManager#queryIntentActivities来查看某个intent究竟可以被哪个act处理。有一点需要特别注意的是,这些方法会考察设备上所有安装的app里的activity,即使是那些被显式标记成了exported=false的act,这就是我上文说到的理解偏差,这让我很惊讶。因为我以前的认识中,既然标记了不对外暴露,那么这些act也不应该被找到才对,但很可惜,看起来Android的实现不是这样的,关于这点,可以参考以下问题:Android queryintentactivities.

7.x(包括)之前虽然也能查到别的app里exported=false的act(这个行为看起来一直都有),但最终会正确打开匹配到的本app里exported=false的act,但在8.0上这个行为break掉了,直接变成了上文提到的“没有应用可执行此操作”,真是一个忧伤的故事。

8.0解决办法

关于8.0的这个问题,AOSP上也有人报了bug:intent有多个match时无法正确跳转。不过看起来仅仅是个没多少关注的P3bug,而且我手头的5x升级到了8.1.0,此问题依然存在,看来指望google修复希望不大。还好我们也有办法处理下,看下Intent.setPackage方法,如下:

/**
* (Usually optional) Set an explicit application package name that limits
* the components this Intent will resolve to. If left to the default
* value of null, all components in all applications will considered.
* If non-null, the Intent can only match the components in the given
* application package.
*
* @param packageName The name of the application package to handle the
* intent, or null to allow any application package.
*
* @return Returns the same Intent object, for chaining multiple calls
* into a single statement.
*
* @see #getPackage
* @see #resolveActivity
*/
public Intent setPackage(String packageName) {
if (packageName != null && mSelector != null) {
throw new IllegalArgumentException(
"Can't set package name when selector is already set");
}
mPackage = packageName;
return this;
}

我们面临的主要问题就是系统API在startActivity的过程中查到了别的app里面的非暴露act,这个方法看起来刚好可以将系统的这个查找行为局限在本app内,所以我们的fix如下:

if (Build.VERSION.SDK_INT >= 26) {
intent.setPackage(mContext.getPackageName());
}

最后,关于exported=false的实现,我个人的看法是应该再提早些,直接一开始在匹配的过程中就找不到这样的act,而不是一股脑全找到(导致本来就1个target满足,结果找了多个出来),等到最后要打开了,看下exported是false,才弹个无权限的错误!!!之前魅族更新了次系统后也出过这问题,弹出让用户选,结果选了之后又告诉用户无权限(因为实际是exported=false的activity)。就像在实现某个方法的时候,有些前置条件不满足,我们应该尽早return,而不是埋头做了很多工作后,才检查一些必要条件,发现不对了才退出,fail fast常常是很好用的策略。

ps:实在是没明白google这里的实现为啥要找到这些实际上private的act,看起来完全是在做无用功啊,反正怎么着都不可能打开,你把它找出来干啥呢!!!有想法的同学可以留言交流下,谢谢。


推荐阅读
  • 在Linux系统中,网络配置是至关重要的任务之一。本文详细解析了Firewalld和Netfilter机制,并探讨了iptables的应用。通过使用`ip addr show`命令来查看网卡IP地址(需要安装`iproute`包),当网卡未分配IP地址或处于关闭状态时,可以通过`ip link set`命令进行配置和激活。此外,文章还介绍了如何利用Firewalld和iptables实现网络流量控制和安全策略管理,为系统管理员提供了实用的操作指南。 ... [详细]
  • 如何在Linux服务器上配置MySQL和Tomcat的开机自动启动
    在Linux服务器上部署Web项目时,通常需要确保MySQL和Tomcat服务能够随系统启动而自动运行。本文将详细介绍如何在Linux环境中配置MySQL和Tomcat的开机自启动,以确保服务的稳定性和可靠性。通过合理的配置,可以有效避免因服务未启动而导致的项目故障。 ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • POJ 2482 星空中的星星:利用线段树与扫描线算法解决
    在《POJ 2482 星空中的星星》问题中,通过运用线段树和扫描线算法,可以高效地解决星星在窗口内的计数问题。该方法不仅能够快速处理大规模数据,还能确保时间复杂度的最优性,适用于各种复杂的星空模拟场景。 ... [详细]
  • 在Android 4.4系统中,通过使用 `Intent` 对象并设置动作 `ACTION_GET_CONTENT` 或 `ACTION_OPEN_DOCUMENT`,可以从相册中选择图片并获取其路径。具体实现时,需要为 `Intent` 添加相应的类别,并处理返回的 Uri 以提取图片的文件路径。此方法适用于需要从用户相册中选择图片的应用场景,能够确保兼容性和用户体验。 ... [详细]
  • 解决Only fullscreen opaque activities can request orientation错误的方法
    本文介绍了在使用PictureSelectorLight第三方框架时遇到的Only fullscreen opaque activities can request orientation错误,并提供了一种有效的解决方案。 ... [详细]
  • Halcon之图像梯度、图像边缘、USM锐化
    图像梯度、图像边缘、USM锐化图像梯度、图像边缘、USM锐化图像梯度、图像边缘、USM锐化图像卷积:1.模糊2.梯度3.边缘4.锐化1.视频教程:B站、 ... [详细]
  • 本文对比了杜甫《喜晴》的两种英文翻译版本:a. Pleased with Sunny Weather 和 b. Rejoicing in Clearing Weather。a 版由 alexcwlin 翻译并经 Adam Lam 编辑,b 版则由哈佛大学的宇文所安教授 (Prof. Stephen Owen) 翻译。 ... [详细]
  • 本文详细介绍了数据库并发控制的基本概念、重要性和具体实现方法。并发控制是确保多个事务在同时操作数据库时保持数据一致性的关键机制。文章涵盖了锁机制、多版本并发控制(MVCC)、乐观并发控制和悲观并发控制等内容。 ... [详细]
  • poj 3352 Road Construction ... [详细]
  • 在CentOS 7环境中安装配置Redis及使用Redis Desktop Manager连接时的注意事项与技巧
    在 CentOS 7 环境中安装和配置 Redis 时,需要注意一些关键步骤和最佳实践。本文详细介绍了从安装 Redis 到配置其基本参数的全过程,并提供了使用 Redis Desktop Manager 连接 Redis 服务器的技巧和注意事项。此外,还探讨了如何优化性能和确保数据安全,帮助用户在生产环境中高效地管理和使用 Redis。 ... [详细]
  • 深入解析Struts、Spring与Hibernate三大框架的面试要点与技巧 ... [详细]
  • 在HTML布局中,即使将 `top: 0%` 和 `left: 0%` 设置为元素的定位属性,浏览器中仍然会出现空白填充。这个问题通常与默认的浏览器样式、盒模型或父元素的定位方式有关。为了消除这些空白,可以考虑重置浏览器的默认样式,确保父元素的定位方式正确,并检查是否有其他CSS规则影响了元素的位置。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 本文详细介绍了定时器输入捕捉技术的原理及其应用。通过配置定时器通道的引脚模式为输入模式,并设置相应的捕获触发条件,可以实现对外部信号的精确捕捉。该技术在实时控制系统中具有广泛的应用,如电机控制、频率测量等场景。文中还提供了具体的配置步骤和示例代码,帮助读者更好地理解和应用这一技术。 ... [详细]
author-avatar
mobiledu2502938445
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有