写了一个适配 Android12-exported 的小插件

简介: 从 Android12 开始,如果我们的 tagSdk >=31, 即以 Android 12 或更高版本为目标平台时,且包含使用 intent 过滤器的 activity、服务或广播接收器,则必须为这些应用组件显式声明 android:exported 属性。

📚 背景

Android12 开始,如果我们的 tagSdk >=31, 即以 Android 12 或更高版本为目标平台时,且包含使用 intent 过滤器activity服务广播接收器,则必须为这些应用组件显式声明 android:exported 属性。

如果你满足上述条件,并且 tagSdk>=31 ,而未声明 exported 属性,则在不同的 Agp 版本有着以下不同提醒方式:

  • Agp7.0 及以上,在 build 时会出现下面的报错:Manifest merger failed : android:exported needs to be explicitly specified for . Apps targeting Android 12 and higher are required to specify an explicit value for android:exported when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details
  • Agp7.0以下

则并不会在编译时报错,而是在安装后打开相关页面时报错,相应的,Android Studio 会以 ⚠️ 的样式提醒你添加 exported

恰好最近也正好在做相关的适配,于是就查了下,发现了恋猫的小郭大佬写的这样一篇文章,Android12的适配,其中关于 exported 部分,比较简单实用,但相对来说,存在版本差异,真实使用起来还需要再改一下。本文就是针对其做的一个完善,并将其抽离成了一个小插件,以便更好的复用。

💬 插件简介

manifest-exported-plugin

一个用于快速适配 Manifest-exported 的小插件,通过修改 manifest 文件,从而做到适配。

👨‍💻‍ 使用方式

1. 添加jitpack

build.gradle

Gradle7.0 以下

buildscript {
  repositories {
      // ...
      maven { url 'https://jitpack.io' }
  }
}

Gradle7.0+ ,并且已经对依赖方式进行过调整,则可能需要添加到如下位置:

settings.gradle

pluginManagement {
 repositories {
     //...
        maven { url 'https://jitpack.io' }
    }
}

Gradle

dependencies {
      classpath 'com.github.xiachufang:manifest-exported-plugin:1.0.6'
}

2. 添加插件

在主app Model中添加:

apply plugin: 'com.xiachufang.manifest.exported'
• 1

plugins {
 id 'com.xiachufang.manifest.exported'
}

3. 参数说明

app-build.gradle

apply plugin: 'com.xiachufang.manifest.exported'
...
exported {
    actionRules = ["android.intent.action.MAIN"]
    enableMainManifest false
    logOutPath "自定义的日志输出目录,如果不存在会自动创建"
}
  • logOutPath 日志输出目录,默认 app/build/exported/outManifest.md
  • actionRules action的匹配项(数组), 如:
<activity android:name=".simple.MainActivity" >
      <intent-filter>
          // action 对应的 android:name 可与actionRules 数组任意一项匹配 ,并且当前没有配置exported
            // -> yes: android:exported="true"
            // -> no: android:exported="false"
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
</activity>

enableMainManifest 是否对主 model-AndroidManifest 进行修改

对于 主model ,属于业务可控的,建议开发者自行调整。

插件默认不会对主 model-AndroidManifest 进行修改,如果发现可用匹配上述规则的,即会进行修正。

开发者可根据日志中的提示,进行修改。

📰 相关截图说明

默认情况下插件的输出目录如下所示,主 model/build/exportred/outManifestLog.md,默认日志如下:

💭 注意事项

对于主model下的 manifest ,默认不进行适配(可开关 enableManifest ),会通过日志进行输出,建议大家自行对比调整。

什么默认不对主 model 进行适配?

  • 对于业务 model ,我们建议开发者自行适配,这属于我们可控范围,适配来说主要就是为了不可控的,即第三方 aar
  • 修改之后,会影响原有的 manifest 代码风格,需要重新格式化一下,相比默认的,增加了不少空格,暂时不知道怎么解决。

🤔 原理解析

通过插入到 processxxxMainManifest Task之前,提前对manifest进行修改。

为什么不插入到 processxxxManifest ,这样不就不用操作 manifest 源文件了吗,只需要对build下的 mergeManifest 进行操作不就行了?

首先说明这两者的顺序:

  1. processxxxMainManifest
  2. processxxxManifest

我们都知道,build 时会将所有 aar 里的 manifest 的全部进行合并,如果有异常会进行报错。

但在不同的 AGP 版本,它们的检测时机不一样。

通常情况下,在 processxxxMainManifest 结束后,我们就可以拿到已经合并好的 manifest 文件,此时就可以直接进行更改适配。

在agp7.0这个思路没有问题,因为 processxxxMainManifest 里面不会去检测 manifest 是否合并成功,而会在 processxxxManifest 去检测。

但在agp7.0以上,因为会先去检测 manifest 是否合并成功,这就导致我们后续的任务没法正常执行,所以我们没有办法将任务插入到 processxxxMainManifest 之后,只能在其之前执行,所以此时我们只能去修改 manifest 源文件从而做到适配。

具体的适配上也比较简单,我们使用 XmlParser 拿到manifest里的节点,通过如下几个条件层层判断,最终完成适配:

  1. 判断是不是 activity、services、broadcasts 以及是不是包含了
  2. 判断 exported 是否为 null
  3. 判断 action 是否匹配我们的条件

需要注意的是,在 Agp4.2 && gradle6.7 及以下时,tagSdk31,就算你不去写 exported ,编译也不会报错,但此时运行在Android12 手机上时,就会出现相应的报错提示。所以在写插件时我们需要对这种情况进行容错,对于未适配的 主mainManifest ,进行报错以便提醒用户。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
1天前
|
Web App开发 移动开发 小程序
"项目中mpaas升级到10.2.3 适配Android 14之后 app中的H5以及小程序都访问不了,
"项目中mpaas升级到10.2.3 适配Android 14之后 app中的H5以及小程序都访问不了,显示“网络不给力,请稍后再试”,预发内网版本不能使用,线上版本可以正常使用,这个是什么原因啊,是某些参数没有配置吗,还是说是一些参数改错了?
66 2
|
7月前
|
Android开发
Android 全屏适配刘海机型
Android 全屏适配刘海机型
111 0
|
1天前
|
Android开发
Android RIL 动态切换 4G 模块适配
Android RIL 动态切换 4G 模块适配
19 0
|
1天前
|
编解码 人工智能 测试技术
安卓适配性策略:确保应用在不同设备上的兼容性
【4月更文挑战第13天】本文探讨了提升安卓应用兼容性的策略,包括理解平台碎片化、设计响应式UI(使用dp单位,考虑横竖屏)、利用Android SDK的兼容工具(支持库、资源限定符)、编写兼容性代码(运行时权限、设备特性检查)以及优化性能以适应低端设备。适配性是安卓开发的关键,通过这些方法可确保应用在多样化设备上提供一致体验。未来,自动化测试和AI将助力应对设备碎片化挑战。
|
1天前
|
Android开发
Android保存图片到相册(适配android 10以下及以上)
Android保存图片到相册(适配android 10以下及以上)
29 1
|
1天前
|
Android开发
Android Uri转File方法(适配android 10以上版本及android 10以下版本)
Android Uri转File方法(适配android 10以上版本及android 10以下版本)
48 0
|
7月前
|
安全 API 开发工具
Android14 适配之——targetSdkVersion 升级到 34 需要注意些什么?(下)
Android14 适配之——targetSdkVersion 升级到 34 需要注意些什么?(下)
416 0
|
7月前
|
存储 缓存 安全
Android14 适配之——现有 App 安装到 Android14 手机上需要注意些什么?
Android14 适配之——现有 App 安装到 Android14 手机上需要注意些什么?
288 0
|
8月前
|
存储 5G API
Android 11 来袭,一起来看看怎么适配(三)
Android 11 来袭,一起来看看怎么适配
|
8月前
|
安全 Shell 测试技术
Android 11 来袭,一起来看看怎么适配(二)
Android 11 来袭,一起来看看怎么适配