AGP 3.5.3升级到4.2.2问题记录

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AGP 3.5.3升级到4.2.2问题记录相关的知识,希望对你有一定的参考价值。

参考技术A

修改前:

修改后:

项目早就支持了androidx,根目录下的gradle.properties已经有如下两行

但是rebuild后依然报上面的错,找了半天发现老项目的app的module下也有一个gradle.properties,但是里面的android.useAndroidX=false。。。。。。
醉了醉了,把这个多余的gradle.properties删掉就好了。

后来在 AGP4.2.0更新说明 中看到了这么一句话:

gradle.properties 文件的行为变更
从 AGP 4.2 开始,无法再从子项目中替换 Gradle 属性。也就是说,如果您在子项目(而不是根项目)上的 gradle.properties 文件中声明某个属性,该属性将被忽略。

AGP 3.6 以上的版本,在调试开发APP的时候采用了新的打包方式,这里关闭新的打包方式,可以让编译通过

android.namespacedRClass 属性已重命名为 android.nonTransitiveRClass
实验性标记 android.namespacedRClass 已重命名为 android.nonTransitiveRClass。
此标记在 gradle.properties 文件中设置,可启用每个库的 R 类的命名空间,以便其 R 类仅包含库本身中声明的资源,而不包含库的依赖项中的任何资源,从而缩减相应库的 R 类大小。

解决办法:删除gradle.properties中的android.nonTransitiveRClass=true

报错信息如下:Direct local .aar file dependencies are not supported when building an AAR.
The resulting AAR would be broken because the classes and Android resources from any local .aar
file dependencies would not be packaged in the resulting AAR. Previous versions of the Android
Gradle Plugin produce broken AARs in this case too (despite not throwing this error).

修改前aar依赖方式:

修改后aar依赖方式:

4.在module中添加对local_aar的依赖

可以参考: Direct local .aar file dependencies are not supported

[CIRCULAR REFERENCE:com.android.tools.r8.utils.b: Expected [access-flag]* void <init> at C:\\Users\\DT.gradle\\caches\\transforms-3\\fd8ee676f15f0d57578a9e28a336cbac\\transformed\\pol
yvPlayer-2.15.2\\proguard.txt:95:42
public PolyvAuxiliaryVideoView <init>;

解决办法: polyvPlayer升级至net.polyv.android:polyvPlayer:2.15.3

这个问题还未解决,应该是某个第三方library中manifest不规范少写了尖括号导致的

参考:

Android agp 对 R 文件内联支持

Android Gradle 插件版本说明

Gradle Receipes (AGP-7.3) & AGP 使用指南

本文所有代码是基于 https://github.com/android/gradle-recipes agp-7.3分支版本的官方 sample。由于缺乏清晰易懂的说明文档(目前我没有找到可读性较好的文档,如果你知道,请留言告知),有些sample代码即便能够跑通,但在细节方便仍然不是很容易让人理解。

从 AGP 7.0 开始,AGP的API相较AGP 7.0 以前的变化较大,且迭代更新比较频繁,目前官方最新已迭代至8.0,请注意对照你所使用的AGP版本。但是据官方的说法是,从 AGP 7.0+之后的API将逐渐趋于稳定,你不用担心升级之后API会变化太大而导致不能使用了。(我信你个鬼)

另外Gradle插件和Android Studio的版本之间存在着兼容要求,请参考这里

我的电脑目前使用的Android Studio的版本是小海豚,所以AGP的要求是7.3,Gradle的要求是至少7.4:

Groovy Use

获取所有Class文件

import org.gradle.api.DefaultTask
import org.gradle.api.file.Directory
import org.gradle.api.file.RegularFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.TaskAction
import org.gradle.api.provider.ListProperty
import com.android.build.api.artifact.MultipleArtifact

abstract class GetAllClassesTask extends DefaultTask 

    @InputFiles
    abstract ListProperty<Directory> getAllClasses()

    @InputFiles
    abstract ListProperty<RegularFile> getAllJarsWithClasses()

    @TaskAction
    void taskAction() 
        allClasses.get().forEach  directory ->
            println("Directory : $directory.asFile.absolutePath")
            directory.asFile.traverse(type: groovy.io.FileType.FILES)  file ->
                println("File : $file.absolutePath")
            
            allJarsWithClasses.get().forEach  file ->
                println("JarFile : $file.asFile.absolutePath")
            
        
    



androidComponents 
    onVariants(selector().all(),  variant ->
        project.tasks.register(variant.getName() + "GetAllClasses", GetAllClassesTask.class) 
            it.allClasses.set(variant.artifacts.getAll(MultipleArtifact.ALL_CLASSES_DIRS.INSTANCE))
            it.allJarsWithClasses.set(variant.artifacts.getAll(MultipleArtifact.ALL_CLASSES_JARS.INSTANCE))

        
    )


执行任务后输出:

修改Class文件

在根目录build.gradle中引入javassist插件:

buildscript 
    dependencies 
        classpath("org.javassist:javassist:3.22.0-GA")
    

plugins 
    id 'com.android.application' version '7.3.1' apply false
    id 'com.android.library' version '7.3.1' apply false

app/build.gradle中添加任务:

import org.gradle.api.DefaultTask;
import org.gradle.api.file.Directory;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.TaskAction;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.io.FileInputStream;

abstract class ModifyClassesTask extends DefaultTask 

    @InputFiles
    abstract ListProperty<Directory> getAllClasses();

    @OutputFiles
    abstract DirectoryProperty getOutput();

    @TaskAction
    void taskAction() 
        ClassPool pool = new ClassPool(ClassPool.getDefault());
        allClasses.get().forEach  directory ->
            System.out.println("Directory : $directory.asFile.absolutePath");
            directory.asFile.traverse(type: groovy.io.FileType.FILES)  file ->
                System.out.println(file.absolutePath)
                if (file.name == "SomeSource.class") 
                    System.out.println("File : $file.absolutePath")
                    CtClass interfaceClass = pool.makeInterface("com.android.api.tests.SomeInterface");
                    System.out.println("Adding $interfaceClass")
                    System.out.println("Write to $output.get().asFile.absolutePath")
                    interfaceClass.writeFile(output.get().asFile.absolutePath)
                    new FileInputStream(file).withCloseable 
                        CtClass ctClass = pool.makeClass(it)
                        ctClass.addInterface(interfaceClass)
                        CtMethod m = ctClass.getDeclaredMethod("toString")
                        if (m != null) 
                            m.insertBefore(" System.out.println(\\"Some Extensive Tracing\\"); ")
                        
                        ctClass.writeFile(output.get().asFile.absolutePath)
                    
                
            
        
    


androidComponents 
    onVariants(selector().all(),  variant ->
        TaskProvider<ModifyClassesTask> taskProvider = project.tasks.register(variant.getName() + "ModifyAllClasses", ModifyClassesTask.class)
        variant.artifacts.use(taskProvider)
                .wiredWith(  it.getAllClasses() ,  it.getOutput() )
                .toTransform(MultipleArtifact.ALL_CLASSES_DIRS.INSTANCE)
    )

新建一个 SomeSource 类:

package com.android.api.tests;

class SomeSource 
    public String toString() 
        return "Something !";
    

执行 assembleDebug 后会自动触发 debugModifyAllClasses 任务被执行

在build\\intermediates\\all_classes_dirs\\debug\\debugModifyAllClasses目录下生成一个SomeInterface.class接口类文件,同时SomeSource.class文件中实现了该接口:


添加Class文件

abstract class AddClassesTask extends DefaultTask 

    @OutputFiles
    abstract DirectoryProperty getOutput();

    @TaskAction
    void taskAction() 

        ClassPool pool = new ClassPool(ClassPool.getDefault());
        CtClass interfaceClass = pool.makeInterface("com.android.api.tests.SomeInterface2")
        System.out.println("Adding $interfaceClass")
        interfaceClass.writeFile(output.get().asFile.absolutePath)
    


androidComponents 
    onVariants(selector().all(),  variant ->
        TaskProvider<AddClassesTask> taskProvider = project.tasks.register(variant.getName() + "AddAllClasses", AddClassesTask.class)
        variant.artifacts.use(taskProvider)
                .wiredWith(  it.getOutput() )
                .toAppendTo(MultipleArtifact.ALL_CLASSES_DIRS.INSTANCE)
    )

执行 assembleDebug 后会自动触发 debugAddAllClasses 任务,在 build\\intermediates\\all_classes_dirs\\debug\\debugAddAllClasses 目录下生成一个接口类文件SomeInterface2.class.

获取APK文件

import com.android.build.api.artifact.SingleArtifact
import com.android.build.api.variant.BuiltArtifacts
import com.android.build.api.variant.BuiltArtifactsLoader

abstract class DisplayApksTask extends DefaultTask 

    @InputFiles
    abstract DirectoryProperty getApkFolder()

    @Internal
    abstract Property<BuiltArtifactsLoader> getBuiltArtifactsLoader()

    @TaskAction
    void taskAction() 
        BuiltArtifacts artifacts = getBuiltArtifactsLoader().get().load(getApkFolder().get())
        if (artifacts == null) 
            throw new RuntimeException("Cannot load APKs")
        
        artifacts.elements.forEach 
            println("Got an APK at $it.outputFile")
        
    


androidComponents 
    onVariants(selector().all(),  variant ->
        project.tasks.register(variant.getName() + "DisplayApks", DisplayApksTask.class) 
            it.apkFolder.set(variant.artifacts.get(SingleArtifact.APK.INSTANCE))
            it.builtArtifactsLoader.set(variant.artifacts.getBuiltArtifactsLoader())
        
    )


执行 debugDisplayApks 任务,输出:

修改 ApplicationId

abstract class ApplicationIdProducerTask extends DefaultTask 

    @OutputFile
    abstract RegularFileProperty getOutputFile()

    @TaskAction
    void taskAction() 
        getOutputFile().get().getAsFile().write("set.from.task." + name)
    


androidComponents 
    onVariants(selector().withBuildType("debug"))  variant ->
        TaskProvider appIdProducer = tasks.register(variant.name + "AppIdProducerTask", ApplicationIdProducerTask.class)  task ->
            File outputDir = new File(getBuildDir(), task.name)
            println("outputDir: $outputDir.absolutePath")
            task.getOutputFile().set(new File(outputDir, "appId.txt"))

        
        variant.setApplicationId(appIdProducer.flatMap  task ->
            task.getOutputFile().map  it.getAsFile().text 
        )
    

执行 assembleDebug 任务,会自动执行 debugAppIdProducerTask 任务,然后运行app,发现BuildConfig.APPLICATION_ID和context.getPackageName() 返回的都是set.from.task.debugAppIdProducerTask。

重写 Manifest 文件

abstract class GitVersionTask extends DefaultTask 

    @OutputFile
    abstract RegularFileProperty getGitVersionOutputFile()

    @TaskAction
    void taskAction() 
        // this would be the code to get the tip of tree version,
        // String gitVersion = "git rev-parse --short HEAD".execute().text.trim()
        // if (gitVersion.isEmpty()) 
        //    gitVersion="12"
        //
        getGitVersionOutputFile().get().asFile.write("1234")
    


abstract class ManifestProducerTask extends DefaultTask 
    @InputFile
    abstract RegularFileProperty getGitInfoFile()

    @OutputFile
    abstract RegularFileProperty getOutputManifest()

    @TaskAction
    void taskAction() 
        String manifest = """<?xml version="1.0" encoding="utf-8"?>
                <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                    package="com.android.build.example.minimal"
                    android:versionName="$new String(getGitInfoFile().get().asFile.readBytes())"
                    android:versionCode="1" >

                    <application android:label="Minimal">
                        <activity android:name="MainActivity">
                            <intent-filter>
                                <action android:name="android.intent.action.MAIN" />
                                <category android:name="android.intent.category.LAUNCHER" />
                            </intent-filter>
                        </activity>
                    </application>
                </manifest>
                    """
        println("Writes to " + getOutputManifest().get().getAsFile().getAbsolutePath())
        getOutputManifest().get().getAsFile().write(manifest)
    


androidComponents 
    onVariants(selector().all(), 
        TaskProvider gitVersionProvider = tasks.register(it.getName() + 'GitVersionProvider', GitVersionTask) 
            task ->
                task.gitVersionOutputFile.set(
                        new File(project.buildDir, "intermediates/gitVersionProvider/output")
                )
                task.outputs.upToDateWhen  false 
        

        TaskProvider manifestProducer = tasks.register(it.getName() + 'ManifestProducer', ManifestProducerTask) 
            task ->
                task.gitInfoFile.set(gitVersionProvider.flatMap  it.getGitVersionOutputFile() )
        
        it.artifacts.use(manifestProducer)
                .wiredWith( it.outputManifest )
                .toCreate(SingleArtifact.MERGED_MANIFEST.INSTANCE)
    )


执行 assembleDebug 后会自动触发 debugManifestProducer 任务,而 debugManifestProducer 任务的输入依赖于 debugGitVersionProvider 的输出,因此 debugGitVersionProvider 任务先被执行,在 build/intermediates/gitVersionProvider/output 文件中生成版本号。然后会执行 debugManifestProducer 任务,在 build\\intermediates\\merged_manifest\\debug\\debugManifestProducer 目录下生成被覆写的AndroidManifest.xml 文件,其中android:versionName的值被替换为上面output 文件中生成的版本号:

<?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.build.example.minimal"
        android:versionName="1234"
        android:versionCode="1" >
        <application android:label="Minimal">
            <activity android:name="MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    </manifest>

修改 Manifest 文件内容

abstract class GitVersionTask extends DefaultTask 

    @OutputFile
    abstract RegularFileProperty getGitVersionOutputFile()

    @TaskAction
    void taskAction() 
        // this would be the code to get the tip of tree version,
        // String gitVersion = "git rev-parse --short HEAD".execute().text.trim()
        // if (gitVersion.isEmpty()) 
        //    gitVersion="12"
        //
        getGitVersionOutputFile().get().asFile.write("8888")
    


abstract class ManifestTransformerTask extends DefaultTask 

    @InputFile
    abstract RegularFileProperty getGitInfoFile()

    @InputFile
    abstract RegularFileProperty getMergedManifest()

    @OutputFile
    abstract RegularFileProperty getUpdatedManifest()

    @TaskAction
    void taskAction() 
        String gitVersion = new String以上是关于AGP 3.5.3升级到4.2.2问题记录的主要内容,如果未能解决你的问题,请参考以下文章

Android Studio Arctic Fox | 2020.3.1Gradle 7.0升级记录

Android Studio Arctic Fox | 2020.3.1Gradle 7.0升级记录

Android Studio Arctic Fox | 2020.3.1Gradle 7.0升级记录

低版本AndroidStudio项目升级到高版本

友盟SDK升级记录

Unity记录几个5.x升级到2018问题