记得我以前曾经发布过一篇发布类库到jCenter的文章:Android开发发布lib到jcenter,发布成功之后,只需要在gradle写一行compile…就可以把类库导进来。当然,你如果觉得麻烦也可以使用第三方的工具,如jitpack,可以很方便把你在GitHub上的项目发布为类库。
好了,言归正传,今天主要说一下和发布类库很相似的发布gradle插件教程,你可能见过很多项目除了通过compile…导进,还有不少是这样的,比如greendao:
// In your root build.gradle file:
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.1'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
// In your app projects build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
implementation 'org.greenrobot:greendao:3.2.2' // add library
}
在讲gradle插件开发之前,先了解一下Gradle插件开发支持Java、Groovy、Scala三种语言开发,Groovy用于实现与 Gradle 构建生命周期(如 task 的依赖)有关的逻辑,Java用于核心逻辑,表现为 Groovy 调用 Java 的代码。我们平时所使用的只有一行compile…的类库主要是用Java开发的实现功能的模块,之所以会出现稍复杂的插件开发,是因为gradle插件可以很好地控制构建项目的生命周期,如task的依赖等。
我们如果想在一个AndroidStudio项目导入一个jar/aar有好几种方式:
① 直接放到lib目录,配合
implementation fileTree(include: ['*.jar'], dir: 'libs')
如果是aar,可能还需要在build.gradle(app)的android{}括号里添加
repositories {
flatDir {
dirs 'libs'
}
}
dependencies{}括号里添加
implementation (name:'aar文件名', ext:'aar')
② File>New>New Module -> Import .JAR/.AAR Package,导入你想添加的jar或aar文件成为一个module,然后在你项目添加该module为依赖即可。
③ 直接在builde.gradle(app)里写代码
def getSDKPlatformPath() {
def rootDir = project.rootDir
def localProperties = new File(rootDir, "local.properties")
if (localProperties.exists()) {
Properties properties = new Properties()
localProperties.withInputStream {
instr -> properties.load(instr)
}
// "${android.getSdkDirectory().getAbsolutePath()}"
def sdkDir = properties.getProperty('sdk.dir')
//def compileSdkVersion = android.compileSdkVersion
// 这里使用17的来编译(Android 4.2)
def compileSdkVersion = "android-17"
Console.println("app compileSdkVersion : " + compileSdkVersion)
def path = sdkDir + "/platforms/" + compileSdkVersion
return path
}
return rootDir
}
// 导入layoutlib.jar
def getLayoutlibJarPath() {
def path = getSDKPlatformPath()
def layoutlibPath = path + "/data/layoutlib.jar"
Console.println("layoutlib-path : " + layoutlibPath)
return layoutlibPath
}
// 导入android.jar
def getAndroidJar() {
def path = getSDKPlatformPath()
def androidPath = "${path}${File.separator}android.jar"
return androidPath
}
然后在dependencies{}里添加:
// 方式①:使用到了一些@hide的类库和方法,如删除缓存的IPackageDataObserver
//provided files(getLayoutlibJarPath())
以上做法,都是比较简单的:
方式①没有明显的缺点,compile/implementation语句虽然会增加,但尚在可以接收的范围之内,需要拷贝jar/aar到项目lib文件夹下,如果依赖仅在本项目使用,建议使用此方式;
方式②有点小题大作了,我本想导入一个jar包,结果要做成一个module;
方式③太臃肿,如果需要做的逻辑越来越多,那么gradle文件里的代码也越来越多,这样肯定是不行的。
于是,针对需要公开为类库,且需要控制项目构建声明周期(环境配置)的情况,我们引入了gradle插件开发。
resources/META-INF/gradle-plugins
这个文件夹结构是强制要求的,否则不能识别成插件├── build.gradle
└── src
└── main
├── groovy
│ └── com.smartdevice.dtv.tvmanager.hidelib
│ ├── HideApiPlugin.groovy
│
└── resources
└── META-INF
└── gradle-plugins
└── hide_api.properties
build.gradle内容:
apply plugin: 'groovy'
apply plugin: 'maven'
repositories {
mavenLocal()
jcenter()
}
dependencies {
compile gradleApi()
}
//发布到本地目录
def versionName = "1.0.0"
group "com.itant.hide.plugin"
version versionName
uploadArchives{
//当前项目可以发布到本地文件夹中
repositories {
mavenDeployer {
repository(url: uri('./repo')) //定义本地maven仓库的地址
}
}
}
HideApiPlugin.groovy内容:
package com.smartdevice.dtv.tvmanager.hidelib
import org.gradle.api.Project
import org.gradle.api.Plugin
public class HideApiPlugin implements Plugin{
private Project mProject
@Override
void apply(Project project) {
mProject = project
initAndroidSDK(project)
}
private void initAndroidSDK(Project project) {
// 导入D:\software\assdk\android-sdk-windows\platforms\android-17\data\layoutlib.jar
// 这样我们就可以在开发的过程中使用很多@hide的方法了,注意,我们仅仅需要编译时使用,所以使用插件的时候
// 需要通过provided files(gradle.ext.layoutlibJar)导入
project.rootProject.gradle.ext.layoutlibJar = getLayoutlibJar()
}
private String getLayoutlibJar() {
def path = getSDKPath()
//def layoutlibPath = "${path}${File.separator}data${File.separator}layoutlib.jar"
def layoutlibPath = "${path}${File.separator}data${File.separator}layoutlib.jar"
return layoutlibPath
}
/*private String getSDKPath() {
def path = "${android.getSdkDirectory().getAbsolutePath()}";
return path
}*/
private String getSDKPath() {
def android_home = System.getenv()['ANDROID_HOME']
if (android_home == null || android_home.equals("")) {
android_home = getSDKPathFromLocalProperty()
}
if (android_home == null || android_home.equals(""))
return 'not found android.jar'
//def compileSdkVersion = 'android-' + API_LEVEL
def compileSdkVersion = 'android-17'
def path = "${android_home}${File.separator}platforms${File.separator}${compileSdkVersion}"
return path
}
private String getSDKPathFromLocalProperty() {
def rootDir = mProject.rootDir
def localProperties = new File(rootDir, "local.properties")
if (localProperties.exists()) {
Properties properties = new Properties()
localProperties.withInputStream {
instr -> properties.load(instr)
}
return properties.getProperty('sdk.dir')
}
return ""
}
}
hide_api.properties内容:
implementation-class=com.smartdevice.dtv.tvmanager.hidelib.HideApiPlugin
gradlew uploadArchives
repositories {
google()
jcenter()
maven{
url '/hidelib/repo/'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// 这里与我们上面生成的repo文件夹下的maven-metadata.xml对应,不要写错了
classpath "com.itant.hide.plugin:hidelib:1.0.0"
}
在build.gradle(app)里顶部使用我们开发的插件,hide_api就是我们上面定义的文件名,不能写错了:
apply plugin: 'hide_api'
最后,在build.gradle(app)的dependencies{}里添加
// 使用gradle插件形式,不需要依赖module,“ext.layoutlibJar”只是我们在HideApiPlugin.groovy里定义的一个变量名称
provided files(gradle.ext.layoutlibJar)
就可以使用我们开发的插件,并且导进了layoutlib类库了,不需要在File–>Project Structure–>dependencies里添加对该module的引用。
注意:
如果开发过程中,你修改了groovy文件,或者module里的配置文件,需要先删除repo文件夹,重新执行gradlew uploadArchives
命令生成新的repo文件。
参考:
https://www.jianshu.com/p/3191c3955194
https://www.jianshu.com/p/3c59eded8155