当前位置: 首页 > news >正文

适配 AGP8.5 版本,各种问题(三)

请添加图片描述

地点:深圳、西丽湖环湖碧道
时间:2025年2月23日

1. 签名创建 & 配置

应该说是 ktsgradle 的区别

build.gradle.kts

signingConfigs {
        create("myrelease") {
            storeFile = File(project.projectDir, "aa.keystore")
            storePassword = "aa"
            keyAlias = "aa"
            keyPassword = "aa"
        }

        create("mydebug") {
            storeFile = File(project.projectDir, "bb.keystore")
            storePassword = "bb"
            keyAlias = "bb"
            keyPassword = "bb"
        }
    }

    buildTypes {
        debug {
            signingConfig = signingConfigs["mydebug"]
        }
        release {
            signingConfig = signingConfigs["myrelease"]
        }
    }
} 

build.gradle

 signingConfigs {
        debug {
            keyAlias 'aa'
            keyPassword 'aa'
            storeFile file('aa.keystore')
            storePassword 'aa'
        }
        release {
            keyAlias 'bb'
            keyPassword 'bb'
            storeFile file('bb.keystore')
            storePassword 'bb'
        }
    }

    buildTypes {
        debug {
            signingConfig signingConfigs.release
        }
        release {
            signingConfig signingConfigs.release
        }
    }
}

2. Groovy 编译问题

问题: Groovy 代码写的类找不到,编译失败

我的插件里存在 Kotlin、Java、Groovy 代码(历史问题),升级到 AGP8+ 之后编译失败,在 AGP7+ 时没有发现问题,可能是那时候还没引入 Kotlin 代码。

我们看打包成功的例子,Kotlin、Java、Groovy 代码编译任务执行先后顺序是这样的:

  • compliteKotlin
  • compliteJava
  • compliteGroovy

我遇到的问题是:项目里面存在 Groovy 代码(位于 groovy 目录下),Kotlin 和 Java 代码(位于 java 目录下),当编译项目是发生了错误,Java 和 Kotlin 代码里找不到 Groovy 代码的类

看代码编译任务顺序可能理解了大概:Groovy 代码还没编译呢,就先编译引用了 Groovy 的 Java 代码肯定报错吧

解决:

  • 能不能把 Groovy 编译任务先于前面两个?(我不知道如何处理,未验证,只是一个猜想)
  • 把 Groovy 代码以 Kotlin 重写(是可以的,代码太多只是重写麻烦)

在这里插入图片描述

3. compliteGroovy 未执行

问题: Groovy 代码为打包进 jar 里

在插件发布时,发现项目里 java 目录下的 Groovy 代码没有生成到 jar 里面

再次打包也注意到运行的 Task 列表里面没有 compliteGroovy,说 Groovy 代码根本没有参与编译过程

后来关注到 main 下面可以创建者四个目录:

  • groovy:存放 Groovy 代码
  • java:存放 Java 代码
  • kotlin:存放 Kotlin 代码
  • resources:存放资源文件

解决:把 Groovy 代码移到 groovy 目录下重新编译,终于看到了 compliteGroovy 也编译正常

在 AGP7+ 时我的 Groovy 代码也是在 java 目录下却能正确编译,到 AGP8+ 就不行了

在这里插入图片描述

4. AsmClassVisitorFactory 编译失败

错误日志:Could not serialize value of type GameManagerClassVisitor

注意:他是运行时编译失败(就是引入插件后,在 app 目录打包 assembleRelease 执行时),不是插件发布编译成 jar 时

在这里插入图片描述

我的代码:

我有一个常量gameManagerClassname ,根据以往的编码习惯,直接接声明为对象的属性(感觉没问题啊),可以一开始编译就报错!(超乎想象,全是知识盲区)

abstract class GameManagerClassVisitor : AsmClassVisitorFactory<EmptyParam> {

    private val gameManagerClassname = "com.vimedia.game.GameManager"

    override fun createClassVisitor(
        classContext: ClassContext,
        nextClassVisitor: ClassVisitor
    ): ClassVisitor {
        return FindDispatchMethodVisitor(Opcodes.ASM9, nextClassVisitor)
    }

    override fun isInstrumentable(classData: ClassData): Boolean {
        return classData.className == gameManagerClassname
    }
}

根据前两篇文章,大概了解到 AsmClassVisitorFactory 的是一个接口:

interface AsmClassVisitorFactory<ParametersT : InstrumentationParameters> : Serializable {

    //这些参数可被实例化,并在实例化对象时注入
    @get:Nested
    val parameters: Property<ParametersT>

	//一些 asm 参数
    @get:Nested
    val instrumentationContext: InstrumentationContext

    // asm 工厂类,实际上委托给别的具体类实现操作
    fun createClassVisitor(
        classContext: ClassContext,
        nextClassVisitor: ClassVisitor
    ): ClassVisitor

    //返回布尔值,执行当前类是否需要处理
    fun isInstrumentable(classData: ClassData): Boolean
}

解决:所以我把这个 gameManagerClassname 转换为 InstrumentationParameters 实现,问题解决了

abstract class GameManagerClassVisitor : AsmClassVisitorFactory<GameManagerClassVisitor.P> {

    override fun createClassVisitor(
        classContext: ClassContext,
        nextClassVisitor: ClassVisitor
    ): ClassVisitor {
        return FindDispatchMethodVisitor(Opcodes.ASM9, nextClassVisitor)
    }

    interface P : InstrumentationParameters {
        @get:Input
        val gameManagerClassname: Property<String>
    }
}

如何传递参数:

    private fun registerTransform(project: Project) {
        project.plugins.withType(AppPlugin::class.java) {
            val androidExt =
                project.extensions.getByType(AndroidComponentsExtension::class.java)
            androidExt.onVariants { variants ->

                variants.instrumentation.transformClassesWith(
                    GameManagerClassVisitor::class.java,
                    InstrumentationScope.ALL
                ) { params ->
                    params.gameManagerClassname.set("com.vimedia.game.GameManager")
                }
            }
        }
    }

5. 添加 Http Maven 仓库

AGP7+

 maven {
	allowInsecureProtocol true
    url 'http://developer.huawei.com/repo/'
}

AGP8+

 maven {
	isAllowInsecureProtocol = true
    url = uri("http://developer.huawei.com/repo/")
}

6. 添加 Manifest 占位符

AGP7+

//先获取 Android 扩展
if (isAppExtension(mProject)) {
    android = mProject.extensions.findByName("android")
} else {
    android = null
}

//placeInMap 就是一个 Map<String, Object>
android.defaultConfig.manifestPlaceholders = placeInMap

AGP8+

val manifestPlaceholder = mapOf(
    "PRJID" to "333",
    "CHANNEL" to "222",
    "APPID" to "111",
    "APPKEY" to "123"
 )

private fun setManifestPlaceholders(
    project: Project,
    manifestPlaceholder: Map<String, String>
) {
    project.plugins.withType(AppPlugin::class.java) {
        val appAndroidExt =
            project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java)
        appAndroidExt.onVariants { variant ->
        	//如果存在多个变体,会执行多次,可根据需要调整
            manifestPlaceholder.forEach { (k, v) ->
                CmdColorPrintUtils.outputGreen("添加 Manifest 参数:$k  ->  $v")
                variant.manifestPlaceholders.put(k, v)
            }
        }
    }
}

7. 获取所有依赖项

AGP7+

static void loadAddDependencies(Project project, DependenciesCallback callback) {
    def dp = new ArrayList()
    project.configurations.all {
        resolutionStrategy.eachDependency { DependencyResolveDetails details ->
            String module = details.requested.module.group + ":" + details.requested.module.name + ":" + details.requested.version
            if (!dp.contains(module)) {
                dp.add(module)
            }
            callback.onResult(dp)
        }
    }
}

AGP8+

@JvmStatic
fun loadAddDependencies(project: Project, callback: DependenciesCallback) {
    val dp = ArrayList<String>()
    val androidExt =
        project.extensions.getByType(AndroidComponentsExtension::class.java)
    androidExt.onVariants { variants ->
        variants.components.forEach { component ->
            component.runtimeConfiguration.resolutionStrategy.eachDependency {
                val details = it as DefaultDependencyResolveDetails
                val module =
                    details.requested.module.group + ":" + details.requested.module.name + ":" + details.requested.version
               	//如果存在多个变体,会执行多次,可以去重
                if (!dp.contains(module)) {
                    dp.add(module)
                }
                callback.onResult(dp)
            }
        }
    }
}

相关文章:

  • vue3.0将后端返回的word文件流转换为pdf并导出+html2pdf.js将页面导出为pdf
  • C#快速调用DeepSeek接口,winform接入DeepSeek查询资料 C#零门槛接入DeepSeek C#接入DeepSeek源代码下载
  • self-attention部分代码注释
  • Pi-hole v6释出
  • android系统 使用哪些工具可以分析组件间的依赖
  • Dubbo RPC 原理
  • 在WINDOWS系统使用CMake gui编译NLopt配合VSCode使用
  • llaMa模型的创新
  • Python 处理状态更新逻辑
  • 绩效管理与业务流程
  • MongoDB安装与配置 导入导出
  • 监听load和hashchange事件
  • 从电子管到量子计算:计算机技术的未来趋势
  • 双足肌肉骨骼机器人 VS 传统钢铁结构机器人:科技新趋势与跨界创新
  • PyCharm Professional 2025 安装配置全流程指南(Windows平台)
  • vue2项目打包后js文件过大, 首次加载缓慢
  • Fisher散度:从信息几何到机器学习的隐藏利器
  • 【DeepSeek开源:会带来多大的影响】
  • LeetCode详解之如何一步步优化到最佳解法:前100题目录(更新中...)
  • ELK搭建初入
  • 专门做海报的网站/百度网站首页网址
  • 如何用WordPress建小说站/cps推广接单平台
  • 河北青山建设集团有限公司网站/互联网广告平台排名
  • 可以免费下载ppt模板的网站/个人网页制作成品欣赏
  • 建湖人才网/seo优化技术是什么
  • 做网站外包公司名称/软文代写平台有哪些