Skip to content

AndroidStudio开发gradle插件开发,gradle基本应用介绍,Transform使用介绍,javassist使用介绍

Notifications You must be signed in to change notification settings

BruZhang/GradlePlugin

 
 

Repository files navigation

Gradle插件开发介绍

1.使用Android Studio开发Gradle插件

  • 项目创建

    • 创建一个Android工程

    • 创建一个Android Library类型的Moudle

    • 将此Module的java修改改成groovy

    • 包名自己可以修改

    • 此Moudle下build.gradle内容清空,添加如下代码

      apply plugin: 'groovy'

      apply plugin: 'maven'

      dependencies {

      compile gradleApi()
      compile localGroovy()
      

      }

      repositories {

      mavenCentral()
      

      }

      //group和version在后面使用自定义插件的时候会用到 可以随便起 group='com.micky'

      version='1.0.0' //上传本地仓库的task, uploadArchives {

      repositories {
          mavenDeployer {
          //本地仓库的地址,自己随意选,但使用的时候要保持一致,这里就是当前项目目录
              repository(url: uri('../repo'))
          }
      }
      

      }

  • 在groovy路径下创建一个MyPlugin.groovy,新建文件一定要带后缀名

    package com.hc.plugin

    import org.gradle.api.Plugin import org.gradle.api.Project

    public class MyPlugin implements Plugin {

      void apply(Project project) {
          System.out.println("========================");
          System.out.println("hello gradle plugin!");
          System.out.println("========================");
      }
    

    }

  • (6) 现在,我们已经定义好了自己的gradle插件类,接下来就是告诉gradle,哪一个是我们自定义的插件类,因此,需要在main目录下新建resources目录,然后在resources目录里面再新建META-INF目录,再在META-INF里面新建gradle-plugins目录。最后在gradle-plugins目录里面新建properties文件,注意这个文件的命名,你可以随意取名,但是后面使用这个插件的时候,会用到这个名字。比如,你取名为com.hc.gradle.properties,而在其他build.gradle文件中使用自定义的插件时候则需写成:

    apply plugin: 'com.hc.gradle'

  • 然后在com.hc.gradle.properties文件里面指明你自定义的类

    implementation-class=com.hc.plugin.MyPlugin

  • 执行 gradle uploadArchives 上传到本地仓库会生成jar

  • 然后在项目的app目录下的build.gradle 使用插件

buildscript {

repositories {
    maven {//本地Maven仓库地址
        url uri('D:/repos')
    }
}
dependencies {
    //格式为-->group:module:version
    classpath 'com.hc.plugin:myplugin:1.0.0'
}

}

//com.hc.gradle为resources/META-INF/gradle-plugins //下的properties文件名称

apply plugin: 'com.hc.gradle'

  • 最后 先clean project(很重要!),然后再make project.从messages窗口打印如下信息

新增Gradle Transform

监听文件编译结束,通过 javasist实现字节码修改,实现代码插入,通过这种插件化的AOP 和代码中使用Aspectj 区别就是,避免代码碎片化,添加一个功能修改多处代码,即使用了Aspectj 也许要在修改的地方添加注解,当修改处很多的时候很不方便,通过transform和javassist 可以遍历整个工程,按照满足条件的一次性修改,并且以后我们可以写成通用性的组建,比如自动注册一些组建在所有Activity,里面Javassist用了反射原理,但是这是编译器,不损失效率,Javassist非常强大,需要仔细学习

1.新建一个MyTransform 再新建一个插件MyPlugin注册这个Transform

Mytransform 重写transform方法 里面要将输入内容复制给输出,否者报错,这是第一步,其实就是相当于在运行我们给拦截了,必须再把内容输出出去才能打包成dex

里面遍历

// Transform的inputs有两种类型,一种是目录,一种是jar包,要分开遍历 inputs.each { TransformInput input -> //对类型为“文件夹”的input进行遍历 input.directoryInputs.each { DirectoryInput directoryInput -> //文件夹里面包含的是我们手写的类以及R.class、BuildConfig.class以及R$XXX.class等

            /**
             * 这里就统一处理一些逻辑,避免代码分散,碎片化
             */

            println("transform transformsalkfjdl;kajf#####################*********")
            println(directoryInput.file.absolutePath)
            MyInject.injectDir(directoryInput.file.absolutePath,"com\\wangpos\\test",project)

            // 获取output目录
            def dest = outputProvider.getContentLocation(directoryInput.name,
                    directoryInput.contentTypes, directoryInput.scopes,
                    Format.DIRECTORY)

            // 将input的目录复制到output指定目录
            FileUtils.copyDirectory(directoryInput.file, dest)
        }
        //对类型为jar文件的input进行遍历
        input.jarInputs.each { JarInput jarInput ->

            //jar文件一般是第三方依赖库jar文件

            // 重命名输出文件(同目录copyFile会冲突)
            def jarName = jarInput.name
            def md5Name = DigestUtils.md5Hex(jarInput.file.getAbsolutePath())
            if (jarName.endsWith(".jar")) {
                jarName = jarName.substring(0, jarName.length() - 4)
            }
            //生成输出路径
            def dest = outputProvider.getContentLocation(jarName + md5Name,
                    jarInput.contentTypes, jarInput.scopes, Format.JAR)
            //将输入内容复制到输出
            FileUtils.copyFile(jarInput.file, dest)
        }

}

里面都是groovy代码,也可以使用java代码,看哪个方便吧

问题总结

1.找不到依赖库,需要在repositories种添加jcenter() 2.还有javassist找不到jar包,就是需要javassist引入jar包 3.发现生成的apk没有变化,删除了build目录重新build,仍然无变化,点击Android Studio setting 清理缓存,重新启动

Gradle介绍

  • 1.删除无用资源 shrinkResources true 一般在release里配置

  • 2.zipalign优化 zipAlignEnabled true zipalign优化的最根本目的是帮助操作系统更高效率的根据请求索引资源 一般在release里配置

  • 3.混淆 minifyEnabled false

  • 4.pseudoLocalesEnabled true //

  • 如果没有提供混淆规则文件,则设置默认的混淆规则文件 (SDK/tools/proguard/proguard-android.txt)

  • 5.proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'

  • 6.配置签名 signingConfig signingConfigs.debug

  • 7.配置多渠道打包productFlavors

    1)为什么要多渠道打包?

    安卓应用商店(一个商店也叫做一个渠道,如360,baidu,xiaomi)众多,大大小小几百个,我们发布应用之后需要统计各个渠道的用户下载量,所以才有了多渠道打包。 现在有比较成熟的第三方应用帮我们实现统计功能(比如友盟),统计的本质就是收集用户信息传输到后台,后台生成报表,帮助我们跟踪分析并完善app。通过系统的方法已经可以获取到, 版本号,版本名称,系统版本,机型,地区等各种信息,唯独应用商店(渠道)的信息我们是没有办法从系统获取到的,所以我们就人为的在apk里面添加渠道信息(其实就用一个字段进行标识,如360,baidu), 我们只要把这些信息打包到apk文件并将信息传输到后台,后台根据这个标识,可以统计各个渠道的下载量了,并没有多么的高大上。

    说了那么多,其实多渠道打包只需要关注两件事情:

    将渠道信息写入apk文件

    将apk中的渠道信息传输到统计后台

    添加配置,以友盟的方式,传到友盟来统计,他需要UMENG_CHANNEL_VALUE来区分

    android { productFlavors { xiaomi { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"] } _360 { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "_360"] } baidu { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"] } wandoujia { manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"] } } }

    然后在Android左下角可以通过Build Variants选择构建不同渠道应用

  • 8.添加不同buildType,默认我们只有debug 和Realse

  • 9.每种渠道都对应这些buildType 在选择buildVarient时候会全部显示出来

  • 10.通过不同的打包渠道,我们还可以将框架层抽离,比如我们的开发两个app图标和应用名字不一样,应用也不一样,可以通过这种,来实现多个apk

      oea {
              applicationId "com.janus.oea.advancedgradledemo"
              applicationIdSuffix ".plus"
              //这样最终的包名是 com.janus.oea.advancedgradledemo.plus
              versionCode 1
              versionName "1.0.0"
              manifestPlaceholders = [APP_NAME: "APP_OEA"]
              buildConfigField 'String', 'OEM', '"OEA"'
          }
      oeb {
              applicationId "com.janus.oeb.advancedgradledemo"
              versionCode 2
              versionName "1.2.0"
              manifestPlaceholders = [APP_NAME: "APP_OEB"]
              buildConfigField 'String', 'OEM', '"OEB"'
          }
    

    依赖一下

    oeaCompile project(':oea') oebCompile project(':oeb')

  • 11.gradle动态注入属性

通过${name},使得你可以在你的Manifest插入一个占位符。看下面的例子:

<activity android:name=".Main">
    <intent-filter>
        <action android:name="${applicationId}.foo">
        </action>
    </intent-filter>
</activity>

通过上面的代码,${applicationId}会被替换成真实的applicationId,例如对于branchOne这个variant,它会变成:

<action android:name="com.example.branchOne.foo">

这是非常有用的,因为我们要根据variant用不同的applicationId填充Manifest.

如果你想创建自己的占位符,你可以在manifestPlaceholders定义,语法是:

productFlavors {
    branchOne {
        manifestPlaceholders = [branchCustoName :"defaultName"]
    }
    branchTwo {
        manifestPlaceholders = [branchCustoName :"otherName"]
    }
}

12.如果你想做更复杂的事情,你可以applicationVariants.all这个task中添加代码进行执行。

假设,我想设置一个applicationId给branchTwo和distrib结合的variant,我可以在build.gradle里面这样写:

applicationVariants.all { variant ->
    def mergedFlavor = variant.mergedFlavor
    switch (variant.flavorName) {
        case "brancheTwoDistrib":
            mergedFlavor.setApplicationId("com.example.oldNameBranchTwo")
            break
    }
}

有时某些buildTypes-flavor结合没有意义,我们想告诉Gradle不要生成这些variants,只需要用variant filter就可以做到

variantFilter { variant ->
    if (variant.buildType.name.equals('release')) {
        variant.setIgnore(!variant.getFlavors().get(1).name.equals('distrib'));
    }
    if (variant.buildType.name.equals('debug')) {
        variant.setIgnore(variant.getFlavors().get(1).name.equals('distrib'));
    }
}

在上面的代码中,我们告诉Gradle buildType=debug不要和flavor=distrib结合而buildType=release只和flavor=distrib结合,生成的Variants

About

AndroidStudio开发gradle插件开发,gradle基本应用介绍,Transform使用介绍,javassist使用介绍

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Groovy 83.6%
  • Java 16.4%