Android开发升级AGP7.0后的一些适配方法技巧

作者:究极逮虾户 时间:2022-10-22 17:41:22 

升级

年初了,我们打算升级下apg,这样之后就拥抱下jetpack compose了!!

想用comopse有两个必选项agp7.0和kotlin版本1.5.31.

Java11配置

因为apg7.0需要把所有的module编译环境切换到java11版本上,然而这个地方很容易出错。

首先是命令行的配置,对于mac用户来说,可能会写死默认的java环境到1.8. 这个时候我们需要做的就是删除bashprofile内的java配置。

同时最好用命令行java --version尝试下输出的版本是不是java11。

Android开发升级AGP7.0后的一些适配方法技巧

as的配置则相对来说比较简单了。

Android开发升级AGP7.0后的一些适配方法技巧

Android开发升级AGP7.0后的一些适配方法技巧

按照这两个配置完成之后重新同步下工程应该就行了。

AndroidComponentsExtension

之前在现在准备好告别Transform了吗?的文章就简单展开了下AndroidComponentsExtension,新版本更换了extensions。这次给项目升级适配之前写的哪些插件,想了想用新不用久吗,尝试下新东西了。

onVariants

以前在写android插件的时候很多时候都需要在gralde的afterEvaluate方法执行之后才能获取到很多安卓对应的属性。

这次在v2的api中,则提供了非常多不同的节点,让我们在不同的阶段做一些不同的事情。

比如说onVariants,beforeVariants,finalizeDsl这三个不同的阶段,正常情况下我们选择onVariants就足够了。

Component Artifacts

demo 地址

Gralde 内的一部分核心是Task,但是要想写好一个Task其实并没有想象中的那么容易。特别是一个CacheableTask,他更多的关注与他们的输入和输出。

构建缓存(build cache)的工作原理是:在缓存中存储已编译的类、测试输出和其他构建构件,同时考虑所有的任务输入,包括输入文件内容、相关类路径和任务配置。

所以在AGP 7.0中,提供了这部分新的api让我们简化对于task,输入输出这些参数的优化,让我们可以更专注到我们想要变更的东西上。

比如说APk,MANIFEST,MAPPING_FILE,BUNDLE,AAR或者其他的一些编译产物,当前agp给我们提供的也是相对来说比较少的一部分功能。

另外一点就是,我们如果想要知道一个task的输入其实如果不去阅读源码,之后获取对应的路径或者源代码,其实是一个非常繁琐的过程。之后还要通过变更dependon或者finalizedBy等等手段将任务插入到编译流程内。

所以就有了我们这次的其中一个主角Artifacts,他主要负责帮助我们将我们的task,插入到编译流程内,让我们尽量少的关注到输入和输出。

// 生成TaskProvider
         val taskProvider = project.tasks.register(
                 "manifestCopy${variant.name}Task",
                 ManifestSampleTask::class.java
         )
         // 获取variant的artifacts之后将Task转化成我们所想要的
         variant.artifacts.use(taskProvider).wiredWithFiles(
                 ManifestSampleTask::mergedManifest,
                 ManifestSampleTask::outputManifest
         ).toTransform(SingleArtifact.MERGED_MANIFEST)

这个就是官方的一个Artifacts的简单的使用了,通过变化我们可以轻松的完成一个有获取合并后的Manifest作为输入,之后以另外一个Manifest文件作为输出的一个task。而且会被直接添加编译流程内,就不需要我们关心他们的前置和后置任务是啥了。

registerJavaGenerateTask 没了

原先在v1的api上吧,有registerJavaGenerateTask这个方法,能加一些简单的代码生成的操作,比如j神以前生成的R2就是通过挂载这个方法。

这次v2版本我在AndroidComponentsExtension中没找到的对应的api,所以只能无中生友,自己搞一个出来咯。

@Override
public void registerJavaGeneratingTask(@NonNull Task task, @NonNull File... sourceFolders) {
    getVariantData().registerJavaGeneratingTask(task, sourceFolders);
}
open fun registerJavaGeneratingTask(
   task: Task,
   generatedSourceFolders: Collection<File>
) {
   @Suppress("DEPRECATION")
   taskContainer.sourceGenTask.dependsOn(task)
   val fileTrees = extraGeneratedSourceFileTrees ?: mutableListOf<ConfigurableFileTree>().also {
       extraGeneratedSourceFileTrees = it
   }
   for (f in generatedSourceFolders) {
       val fileTree = services.fileTree(f).builtBy(task)
       fileTrees.add(fileTree)
   }
   addJavaSourceFoldersToModel(generatedSourceFolders)
}

我仔细观察了下registerJavaGenerateTask的源代码,发现其中只做了两件比较简单的事情。将Task挂载到generateVariantResources任务之后,然后将生成java类的文件夹加入到sourcetSet上去,这样就行了。

sourcetSet就是javac的将java转化成class的编译路径。

所以相对来说就比较简单,我们用新的api模拟出原来的效果就差不多可以了,我们只要找到挂载的任务之后,顺便把代码添加到java和kotlin的sourceset中就行了

fun Project.registerJavaGenerateTask(
   variant: String?,
   task: TaskProvider<out Task>,
   generatedSourceFolders: Collection<File>
) {
   if (variant.isNullOrEmpty().not()) {
       variant?.apply {
           // 因为task生成在配置阶段完成之后
           afterEvaluate {
               findJavaGenerateTask(variant)?.dependsOn(task)
           }
           //  获取最新版本sourceSet
           val application = extensions.findByType(ApplicationExtension::class.java)
           application?.sourceSets {
               findByName(variant)?.apply {
                   generatedSourceFolders.forEach {
                       java.srcDir(it)
                       kotlin.srcDir(it)
                   }
               }
           }
       }
   }
}

这次升级适配主要的代码就是这个了,其实代码量上来说不多。但是把有个坑点,之前因为偷懒就直接用了setSrcDirs这个api,所以文件就被覆盖了。导致了一部分代码没有被编译成class,导致了classnotfound异常。

其他

获取applicationId,我们的插件内有对于应用id的判断,之后进行不同的manifest pleaceholder的调整。逻辑比较简单,只是切换了新版本的api而已。

if (variant is ApplicationVariant) {
   val applicationId = variant.applicationId.get()
     variant.manifestPlaceholders.put("xxxxx", applicationId)
 }

对resValue插入新的string或者values。也是原来就有的能力,但是要对新版本进行一次小小的适配和更换。

private fun addAPGClassFile(config: Variant, key: String, value: String) {
   val resValue = ResValue(value)
   val reskey = config.makeResValueKey("string", key)
   config.resValues.put(reskey, resValue)
}

启动configuration cache

启用配置缓存的操作,本质上是在项目的 gradle.properties 文件中设置了环境变量 org.gradle.unsafe.configuration-cache=true。

结尾

AGP对我们这个算是每年一更新了,会碰到一些新的有趣的api以及新的写法。另外每次新版本的AGP对于编译上都有变更和优化,更多关于AGP7.0升级适配的资料请关注脚本之家其它相关文章!

来源:https://juejin.cn/post/7056395437544046606#heading-6

标签:Android,AGP7.0,升级,适配
0
投稿

猜你喜欢

  • Java并发编程之CountDownLatch源码解析

    2023-11-05 02:06:41
  • android多媒体音乐(MediaPlayer)播放器制作代码

    2022-01-06 01:13:20
  • c#深拷贝文件夹示例

    2023-07-24 07:50:40
  • Android卫星菜单效果的实现方法

    2023-10-18 12:41:34
  • ArrayList详解和使用示例_动力节点Java学院整理

    2023-08-05 13:15:41
  • java设计模式(实战)-责任链模式

    2022-12-24 23:07:53
  • Mybatis-plus多数据源配置的两种方式总结

    2023-07-24 05:22:48
  • 快速学习六大排序算法

    2023-11-02 22:36:19
  • Java函数式编程(十二):监控文件修改

    2022-08-11 10:21:01
  • SSH原理及两种登录方法图文详解

    2023-11-14 11:10:53
  • 如何在Android Studio下进行NDK开发

    2022-01-13 21:49:36
  • java io文件操作从文件读取数据的六种方法

    2023-05-17 02:54:40
  • C#串口通信实现方法

    2023-04-15 06:31:11
  • Java中DataInputStream和DataOutputStream的使用方法

    2023-02-03 04:08:28
  • Java位掩码控制权限与(&)或(|)非(~)、>的介绍

    2023-05-27 19:10:15
  • Flutter Dio二次封装的实现

    2022-08-27 08:56:05
  • java 2d画图示例分享(用java画图)

    2023-07-25 22:03:52
  • JWT.net 操作实践方法

    2022-04-09 16:01:28
  • 详解AndroidStudio3.0开发调试安卓NDK的C++代码

    2022-09-29 07:02:53
  • Android超详细讲解组件ScrollView的使用

    2022-08-05 09:55:18
  • asp之家 软件编程 m.aspxhome.com