行为变更 | 了解 Android 12 中的 intent-filter

行为变更 | 了解 Android 12 中的 intent-filter
www.zeeklog.com  - 行为变更 | 了解 Android 12 中的 intent-filter


Android 12 一个重要的变更是提高应用和系统的安全性,这个变更影响了所有目标版本为 Android 12 的应用

在 AndroidManifest.xml 文件中注册的 Activity、service 和 broadcast receiver 组件如果有 intent-filter 声明都必须显式申明是否需要对外披露服务 (android:exported)。

❗️如果您的应用出现了以下错误信息,很有可能和这个变更有关。

Installation did not succeed.

The application could not be installed: INSTALL_FAILED_VERIFICATION_FAILURE

List of apks:

[0] ‘…/build/outputs/apk/debug/app-debug.apk’

Installation failed due to: ‘null’

NSTALL_PARSE_FAILED_MANIFEST_MALFORMED: Failed parse during installPackageLI:

/data/app/vmdl538800143.tmp/base.apk (at Binary XML file line #…):

com.example.package.ActivityName: Targeting S+ (version 10000 and above) requires that an explicit

value for android:exported be defined when intent filters are present”

解决方法

要解决上述问题,您需要在 AndroidManifest.xml 文件中,为使用了 <intent-filter><activity><activity-alias><service><receiver> 组件声明 android:exported 属性。

我们非常期待收到您对这项关于本要求的反馈,如果有任何建议和想法,请填写这份  向我们反馈,告诉我们您的应用中的哪些用例受到此变更的影响。

⚠️ 请不要 “简单粗暴” 地给这些组件直接添加 android:exported="true",您需要检查并斟酌那些加入了 intent-filter 属性的组件: 用户设备上的任何其他应用都能启动这个组件,这是否是您需要的?

判断组件能否与其他应用的组件或服务相互调用或交互,这取决于应用本身的功能、其他应用如何与本应用交互,以及可能存在的特定应用场景。这里有一些常见例子,例子中包含了 intent-filter 的建议配置以及为什么要这样设置。

为包含 <category android:name="android.intent.category.LAUNCHER" /> 的 Activity 设定 android:exported="true"

这个 Activity 可能是您应用的 MainActivity,由于 Android 上的 Launcher (桌面/启动器) 是一个很常规的应用,这个 Activity 必须设定 exported="true",否则 Launcher 应用就无法启动它。

为包含 <action android:name="android.intent.action.VIEW" /> 的 Activity 设定 android:exported="true"

这个 Activity 负责处理来自其他应用的 “open with” 操作。

为包含 <action android:name="android.intent.action.SEND" /><action android:name="android.intent.action.SEND_MULTIPLE"/> 的 Activity 设定 android:exported="true"

这个 Activity 负责处理来自其他应用分享的内容。如需了解更多,请参阅: 从其他应用接收简单的数据

为包含 <action android:name="android.media.browse.MediaBrowserService" /> 的 Service 设定 android:exported="true"

如果这是一个将应用的媒体库公开给其他应用的 Service,则需要设定为 android:exported=“true”,以便于其他应用连接和浏览。这个 Service 一般是通过直接或者间接继承  来实现的,如果不是,就没有必要设置这个。

为包含 <action android:name="com.google.firebase.MESSAGING_EVENT" /> Service 设定 android:exported="false"

这个 Service 会被 Firebase Cloud Messaging 调用,Service 需要继承 FirebaseMessagingService。这个 Service 不应该设定 android:exported=“true”,因为无论它的属性值是什么,Firebase 都可以启动这个 Service。如需要了解更多,请参阅: 。

为包含 <action android:name="android.intent.action.BOOT_COMPLETED" /> 的 Receiver 设定 android:exported="false"

因为无论是否设定 exported,系统都会向 receiver 发送对应的广播。

背景

在 Android 12 之前,有 intent-filter 属性的组件 (只有 Activity、Service 和 BroadcastReceiver) 自动被默认设定为 exported。

下面的 Activity 默认会 exported:

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

下面的 Activity 不会 exported:

<activity android:name=".MainActivity" />

这个默认的设置看起来可能合理,但这个错误可能会让应用容易受到攻击。举个例子,假设我们的应用有一个播放视频的 Activity:

<activity android:name=”.PlayVideoActivity” />

后来我们发现很多地方都需要显式地调用或启动这个 Activity,为了降低应用的耦合,我们给 Activity 添加了 intent-filter 属性,允许系统选择这个 Activity:

<activity android:name=”.PlayVideoActivity”>
    <intent-filter>
        <action android:name=”android.intent.action.VIEW” />
        <data
            android:mimeType=”video/*”
            android:scheme=”content” />
    </intent-filter>
</activity>

到这里问题就出现了,这个 Activity 设计的目的仅仅是在应用内部使用,可现在却被公开了!

如果我们的应用目标版本是 Android 12,系统会阻止这样的设置,并强制要求我们去设置 android:exported 属性。由于我们不想将 Activity 对外公开,我们可以设置 android:export=false,以确保应用的安全性。

<activity
    android:name=”.PlayVideoActivity”
    android:exported=”false”>
    <intent-filter>
        <action android:name=”android.intent.action.VIEW” />
        <data
            android:mimeType=”video/*”
            android:scheme=”content” />
    </intent-filter>
</activity>

简要总结

Android 12 一个重要的变化是提高了安全性。以 Android 12 为目标版本的应用,如果 AndroidManifest.xml 注册的 activityactivity-aliasservice 或者 broadcast receiver 组件有 intent-filter 属性,必须显式设置 android:exported 的值,否则应用将无法安装。

需要仔细考虑 android:exported 属性需要设置什么值,如果不确定,建议设置 android:exported="false"

了解更多关于 intent 和 intent-filter 的信息,请参阅: 。

了解更多安全和隐私上的更新,请参阅: 。

了解 Android 12 所有的更新,请参阅: 。’

Read more

Spring——条件化Bean注册的注解汇总

Spring——条件化Bean注册的注解汇总

在Spring框架中,与条件化Bean注册相关的注解主要包括以下几种: 1. @ConditionalOnBean:当容器中存在指定Bean时,才会注册当前Bean。 2. @ConditionalOnMissingBean:当容器中不存在指定Bean时,才会注册当前Bean。 3. @ConditionalOnClass:当指定的类在类路径上存在时,才会注册当前Bean。 4. @ConditionalOnMissingClass:当指定的类在类路径上不存在时,才会注册当前Bean。 5. @ConditionalOnProperty:根据配置文件中的属性值来决定是否注册Bean。 6. @ConditionalOnExpression:根据SpEL表达式的结果来决定是否注册Bean。 代码如下: import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframewor

By Ne0inhk
Spring——条件化Bean注册(@Conditional注解)

Spring——条件化Bean注册(@Conditional注解)

条件化Bean注册是Spring框架中的一种机制,通过在Bean定义上添加@Conditional注解,可以根据特定的条件来决定是否注册该Bean。 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean @Conditional(MyCondition.class) public MyBean myBean() { return new MyBean(); } } 通过@Conditional(MyCondition.class)注解来标记myBean()方法,表示只有满足MyCondition条件时才会注册这个Bean。MyCondition是一个自定

By Ne0inhk
Spring——缓存的使用

Spring——缓存的使用

Spring框架提供了强大的缓存支持,可以帮助应用程序提高性能和响应速度。Spring的缓存支持包括注解驱动的缓存和基于接口的缓存管理。 Spring缓存支持: 1. 使用步骤: * 在需要缓存的方法上添加 @Cacheable 注解来指定方法的返回值应该被缓存。 * 使用 @CacheEvict 注解来指定方法调用时清除缓存。 * 需要在配置类上添加 @EnableCaching 注解开启缓存支持。 1. 代码如下: import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.CacheEvict; import org.springframework.stereotype.Service; @Service public class CacheService { @Cacheable(value = "dataCache", key = "#id") public String getCachedD

By Ne0inhk
Spring——文件上传和下载

Spring——文件上传和下载

Spring框架中的文件上传和下载是常见的功能,可以通过Spring提供的MultipartFile类来实现文件上传,同时可以利用ServletOutputStream来实现文件下载。下面看看代码如何使用。 文件上传: @Controller public class FileUploadController { @PostMapping("/upload") public String handleFileUpload(@RequestParam("file") MultipartFile file) { // 处理文件上传逻辑 return "uploadSuccess"; } } 文件下载: @Controller public class FileDownloadController { @GetMapping("/download") public void handleFileDownload(HttpServletResponse response) { // 设置响应头

By Ne0inhk