Android AspectJX 适配Gradle 4.10.1

2,345 阅读2分钟

问题

前段时间Android Studio的版本升级到了3.x,Gradle 的版本也升级到了4.x +,问题来了,之前在项目中使用了Aspectjx这个gradle插件,但在新的环境中,sync gradle的时候,报错了:

WARNING: API 'variant.getJavaCompile()' is obsolete and has been replaced with 'variant.getJavaCompileProvider()'.
It will be removed at the end of 2019.
For more information, see https://d.android.com/r/tools/task-configuration-avoidance
Affected Modules: app

这是由于Gradle升级后,getJavaCompile()方法已经被废弃,所以在新的版本里会提示出使用新的API的警告,虽然是Warning,但其实已经无法正常构建脚本了,问题脚本如下:

variants.all { variant ->
    //--------------------------------问题位置-------------------------
    JavaCompile javaCompile = variant.javaCompile //******问题代码
    //--------------------------------问题位置-------------------------
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo",
                         "-1.8",
                         "-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
        log.debug "ajc args: " + Arrays.toString(args)
    }
}

解决

0、了解这个Warning发生的位置,源码如下:

@Override
@NonNull
public JavaCompile getJavaCompile() {
    BaseVariantData variantData = getVariantData();
    variantData
            .getScope()
            .getGlobalScope()
            .getDslScope()
            .getDeprecationReporter()
            .reportDeprecatedApi(
                    "variant.getJavaCompileProvider()",
                    "variant.getJavaCompile()",
                    TASK_ACCESS_DEPRECATION_URL,
                    DeprecationReporter.DeprecationTarget.TASK_ACCESS_VIA_VARIANT);
    return variantData.getTaskContainer().getJavacTask().get();
}

就是说在Gradle 4.10.1版本中,当使用getJavaCompile(),会直接执行reportDeprecatedApi(),发出一个警告,后面的retrun也就不会正常执行了。

1、显然需要将使用variant.getJavaCompile()的地方改为variant.getJavaCompileProvider() 首先,我找到getJavaCompileProvider()的源码,发现返回值不是直接返回JavaCompile对象,而是TaskProvider<JavaCompile>对象:

@NonNull
@Override
public TaskProvider<JavaCompile> getJavaCompileProvider() {
    //noinspection unchecked
    return (TaskProvider<JavaCompile>) getVariantData().getTaskContainer().getJavacTask();
}

这是一个JavaCompile的封装类,可以通过get()方法获取到JavaCompile对象:

TaskProvider<JavaCompile> provider =  variant.javaCompileProvider
javaCompile = provider.get()

2、所以之前出问题的脚本可以修改如下:

variants.all { variant ->
    //--------------------------------问题位置-------------------------
    JavaCompile javaCompile = variant.javaCompile //******问题代码
    //--------------------------------修复后的代码-------------------
    JavaCompile javaCompile = null
        if (variant.hasProperty('javaCompileProvider')) {
            //gradle 4.10.1 +
            TaskProvider<JavaCompile> provider =  variant.javaCompileProvider
            javaCompile = provider.get()
        } else {
            javaCompile = variant.hasProperty('javaCompiler') ? variant.javaCompiler : variant.javaCompile
        }
    //--------------------------------修复后的代码-----------------------
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo",
                         "-1.8",
                         "-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
        log.debug "ajc args: " + Arrays.toString(args)
    }
}

首先,判断是否存在javaCompileProvider,如果存在就使用新的API,如果不存在就说明脚本的运行环境还是老的Gradle版本,这里又加了一个判断是否有javaCompiler,这是适配更老的版本,这样写起来更加严谨一些。

以上就是Aspectj适配Gradle4.x的部分,但是,我的项目使用了Aspectjx这个插件,当时只是为了让gradle脚本看起来干净些,也不用维护,但目前这个项目貌似并没有修复这个问题,如果换成自己写,但也可以,就是折腾,我这人懒,习惯一劳永逸,于是决定自己改AspectJx的源码,然后自己打包上传到maven上,目前已经完成,源码如下:

/**
 * class description here
 * @author simon
 * @version 1.0.0
 * @since 2018-04-20
 */
class AJXProcedure extends AbsProcedure {

    Project project
    AJXCache ajxCache

    AJXProcedure(Project proj) {
        super(proj, null, null)

        project = proj
        ajxCache = new AJXCache(project)

        System.setProperty("aspectj.multithreaded", "true")

        def configuration = new AJXConfig(project)

        project.afterEvaluate {

            configuration.variants.all { variant ->
                JavaCompile javaCompile = null
                if (variant.hasProperty('javaCompileProvider')) {
                    //gradle 4.10.1 +
                    TaskProvider<JavaCompile> provider =  variant.javaCompileProvider
                    javaCompile = provider.get()
                } else {
                    javaCompile = variant.hasProperty('javaCompiler') ? variant.javaCompiler : variant.javaCompile

                }
                ajxCache.encoding = javaCompile.options.encoding
                ajxCache.bootClassPath = configuration.bootClasspath.join(File.pathSeparator)
                ajxCache.sourceCompatibility = javaCompile.sourceCompatibility
                ajxCache.targetCompatibility = javaCompile.targetCompatibility
            }


            AJXExtension ajxExtension = project.aspectjx
            //当过滤条件发生变化,clean掉编译缓存
            if (ajxCache.isExtensionChanged(ajxExtension)) {
                project.tasks.findByName('preBuild').dependsOn(project.tasks.findByName("clean"))
            }

            ajxCache.putExtensionConfig(ajxExtension)

            ajxCache.ajcArgs = ajxExtension.ajcArgs
        }

        //set aspectj build log output dir
        File logDir = new File(project.buildDir.absolutePath + File.separator + "outputs" + File.separator + "logs")
        if (!logDir.exists()) {
            logDir.mkdirs()
        }

        Dump.setDumpDirectory(logDir.absolutePath)
    }
}

我目前上传到了公司的私服在使用,有时间修改一个可以开源的版本(公司管的严格)。