700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Gradle实战:发布aar包到maven仓库

Gradle实战:发布aar包到maven仓库

时间:2022-07-06 21:41:33

相关推荐

Gradle实战:发布aar包到maven仓库

查看原文:/u0108184...

Gradle实战系列文章:

《Gradle基本知识点与常用配置》

《Gradle实战:Android多渠道打包方案汇总》

《Gradle实战:不同编译类型的包同设备共存》

《Gradle实战:执行sql操作hive数据库》

aar简介

aar文件是Google为Android开发所设计的一种library格式,全名为Android Archive Library,与Java Jar Library不同的是,aar除了java code之外还包含资源文件,即xml文件、图片、文字等。

本文着重介绍发布过程和遇到的一些坑及其解决方案,文中的maven仓库是指公司搭建的maven仓库,如果要发布到jCenter或maven central,可以参考文章最后的“深入学习“。

1. 准备工作

开发工具:Android Studio;

复习《Gradle基本知识点与常用配置》,本文会用到gradle中全局属性设置、文件读取、shell指令执行等相关知识点;

工程必须是lib工程,即该工程对应的build.gradle文件中要引用:

apply plugin: 'com.android.library'

在根目录的build.gradle文件中添加

allprojects {

apply plugin: 'idea'apply plugin: 'maven'configurations {deployerJars}

}

configurations.all {

resolutionStrategy.cacheChangingModulesFor 0, 'seconds'//不使用缓存,使用仓库中最新的包

}

subprojects { //表示除主工程外所有子模块

dependencies {deployerJars "org.apache.maven.wagon:wagon-http:2.2"}

}

ext { //仓库选择标记

repoType = "remote" //发布到远程仓库(下文中会用到)

// repoType = "local" //发布到本地仓库,方便调试,避免调试期间频繁上传到maven仓库(下文中会用到)

}

在gradle.properties文件中添加:

releaseRepositoryUrl=xxx //正式包仓库地址(下文中会用到)

snapshotRepositoryUrl=xxx //测试包仓库地址(下文中会用到)

repositoryGroup=pany.appname // 定义要上传的aar所在仓库的Group,可自定义,但后续引用处要与此一致

在工程根目录下新建一个名为“mavenAccount.properties”文件,并将该文件加入到ignore 中,该文件用于存放访问maven仓库的账户和密码以及本地仓库地址,只有该模块的开发者才有权发布该aar包。

repositoryUserName=xxx

repositoryPassword=xxx

localRepositoryUrl=file:///Users/admin/Documents/Android/repo/

2. 编写上传脚本

生成aar包

> 在工程根目录下新建一个名为“release-as-aar.gradle”的文件,其中脚本如下:

uploadArchives() {

repositories {mavenDeployer {configuration = configurations.deployerJarsprintln 'repoType : ' + rootProject.ext.repoTypeif ((rootProject.ext.repoType).equals("remote")) { //发布到远程仓库snapshotRepository(url: snapshotRepositoryUrl) { // 测试包//从本地文件读取仓库账号和密码def File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('repositoryUserName') && props.containsKey('repositoryPassword')) {def repositoryUserName = props['repositoryUserName']def repositoryPassword = props['repositoryPassword']authentication(userName: repositoryUserName, password: repositoryPassword)println '上传到远程仓库'} else {println '没有发布权限'}} else {println '没有发布权限'}}repository(url: releaseRepositoryUrl) { // 正式包def File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('repositoryUserName') && props.containsKey('repositoryPassword')) {def repositoryUserName = props['repositoryUserName']def repositoryPassword = props['repositoryPassword']authentication(userName: repositoryUserName, password: repositoryPassword)println '上传到远程仓库'} else {println '没有发布权限'}} else {println '没有发布权限'}}} else { // 发布到本地仓库def localRepositoryUrldef File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('localRepositoryUrl')) {localRepositoryUrl = props['localRepositoryUrl']snapshotRepository(url: localRepositoryUrl)repository(url: localRepositoryUrl)println '上传到本地仓库'} else {println '没有发布权限'}} else {println '没有发布权限'}}}}

}

生成jar包

> 在工程根目录下新建一个名为“release-as-jar.gradle”的文件,其中脚本如下:

task androidJavadocs(type: Javadoc) {

failOnError = falsesource = android.sourceSets.main.java.srcDirsext.androidJar = "${android.sdkDirectory}/platforms/${pileSdkVersion}/android.jar"classpath += files(ext.androidJar)

}

task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {

classifier = 'javadoc'from androidJavadocs.destinationDir

}

task androidSourcesJar(type: Jar) {

classifier = 'sources'from android.sourceSets.main.java.srcDirs

}

uploadArchives {

repositories {mavenDeployer {configuration = configurations.deployerJarsprintln 'repoType : ' + rootProject.ext.repoTypeif ((rootProject.ext.repoType).equals("remote")) { //发布到远程仓库snapshotRepository(url: snapshotRepositoryUrl) {def File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('repositoryUserName') && props.containsKey('repositoryPassword')) {def repositoryUserName = props['repositoryUserName']def repositoryPassword = props['repositoryPassword']authentication(userName: repositoryUserName, password: repositoryPassword)println '上传到远程仓库'} else {println 'sorry,你没有上传aar包的权限'}} else {println 'sorry,你没有上传aar包的权限'}}repository(url: releaseRepositoryUrl) {def File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('repositoryUserName') && props.containsKey('repositoryPassword')) {def repositoryUserName = props['repositoryUserName']def repositoryPassword = props['repositoryPassword']authentication(userName: repositoryUserName, password: repositoryPassword)println '上传到远程仓库'} else {println 'sorry,你没有上传aar包的权限'}} else {println 'sorry,你没有上传aar包的权限'}}} else {//发布到本地仓库def localRepositoryUrldef File propFile = new File('../mavenAccount.properties')if (propFile.canRead()) {def Properties props = new Properties()props.load(new FileInputStream(propFile))if (props != null && props.containsKey('localRepositoryUrl')) {localRepositoryUrl = props['localRepositoryUrl']snapshotRepository(url: localRepositoryUrl)repository(url: localRepositoryUrl)println '上传到本地仓库'} else {println 'sorry,本地仓库路径不存在'}} else {println 'sorry,本地仓库路径不存在'}}}}

}

artifacts {

archives androidSourcesJararchives androidJavadocsJar

}

3. 子模块中相关配置

在子模块的build.gradle文件中添加:

group repositoryGroup

//version '0.0.1'

version '0.0.1-SNAPSHOT' //表示测试版,正式发版时去掉“-SNAPSHOT”

//打成aar格式

apply from: '../release-as-aar.gradle' //引用上传插件

//打成jar格式

//apply from: '../release-as-jar.gradle'

4. 打包上传

编译通过后,打开android studio自带的终端,进入相应的module目录下,输入:gradle uploadArchives

5. 使用aar

在需要引用aar包的工程中,根目录的build.gradle文件中进行如下配置:

allprojects {

repositories {

// jcenter(); //注释jcenter,表示不直接从jcenter仓库获取,而是通过公司私服仓库去获取

maven {name 'xxx' //key与value之间有空格url 'xxx' //key与value之间有空格}mavenLocal();}

}

在子模块的build.gradle文件中进行如下引用:

dependencies {

compile group: repositoryGroup, name: 'xxx', version: '0.0.1', ext: 'aar', changing: true

}

6. 踩到的坑

问题一:上传时找不到服务器

上传时需关闭android studio的翻墙代理设置,且注释settings.gradle中自动生成的代理服务器相关配置,否则上传时会报找不到仓库服务器的错误。

问题二:aar包无法更新

有时上传了最新的snapshot包,引用的地方也sync、clean了,但引用的还是旧的包,此时需要删除“~/.gradle”中的相关记录。为方便执行,我们可以在应用工程根目录的build.gradle文件中,采用shell命令删除,该命令会在你执行clean操作时先执行:

task deleteDescriptors(type: Exec) { //执行shell命令executable "sh"args "-c", "rm -rf ~/.gradle/caches/modules-2/metadata-2.16/descriptors/pany.appname" //此处的“pany.appname“就是之前定义的“repositoryGroup“。}task clean(type: Delete, dependsOn: deleteDescriptors) { //clean工程时顺带执行上述任务delete rootProject.buildDir}

此时,再clean一下,引用的就是最新的aar包了。

问题三:无法设置debug编译类型

在lib工程中无论怎么设置编译类型,最后生成的aar包中始终都是release版本,该问题见google反馈。既然不可设置编译类型,我们可以在aar包代码中通过反射来获取应用的编译类型:

private Object getBuildConfigValue(Context context, String fieldName) {try {Class<?> clazz = Class.forName(context.getPackageName() + ".BuildConfig");Field field = clazz.getField(fieldName);return field.get(null);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return null;}//使用String buildType = getBuildConfigValue(ctx,"BUILD_TYPE").toString();if (!TextUtils.isEmpty(buildType) && buildType.equals("debug")) { // debug...} else { // release...}

但是,这里面还有一个坑,系统版本在4.4以下的设备中,该方法无法获得包名,会抛空指针错误。以下我们给出完整的解决方案:

public class BuildConfigProvider {private static Context sContext;private static String packageName;public static String getBuildType() {String buildType = (String) getBuildConfigValue("BUILD_TYPE");if ("debug".equals(buildType)) {buildType = "debug";}if ("release".equals(buildType)) {buildType = "release";}return buildType;}public static final boolean isDebug() {return BuildConfig.DEBUG;}/*** 通过反射获取ApplicationContext** @return*/private static Context getContext() {if (sContext == null) {try {final Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");final Method currentActivityThread = activityThreadClass.getDeclaredMethod("currentActivityThread");final Object activityThread = currentActivityThread.invoke(null);final Method getApplication = activityThreadClass.getDeclaredMethod("getApplication");final Application application = (Application) getApplication.invoke(activityThread);sContext = application.getApplicationContext();} catch (Exception e) {e.printStackTrace();}}return sContext;}/*** 通过反射获取包名** @return*/private static String getPackageName() {if (packageName == null) {try {final Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");final Method currentPackageName = activityThreadClass.getDeclaredMethod("currentPackageName");packageName = (String) currentPackageName.invoke(null);} catch (Exception e) {packageName = getContext().getPackageName();}}return packageName;}public static Object getBuildConfigValue(String fieldName) {try {Class<?> clazz = Class.forName(packageName + ".BuildConfig");Field field = clazz.getField(fieldName);return field.get(null);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (IndexOutOfBoundsException e) {e.printStackTrace();}return "";}}

当然,有人可能会说,既然可以通过反射得到ApplicationContext,就没必要再去反射获得包名了,这里只是提供不同的解决方案以作参考。

问题四:多包共存模式下获得编译类型为空

在上一篇博客《 Gradle实际应用(二):同名包共存》中,我们可以在一个设备中安装同一个应用不同编译类型的包。但是,非release包中我们获得的包名是带有编译类型后缀的(如“pany.appname.debug“),而编译类型我们是通过反射获取,“BuildConfig“所在的包名还是原始的、不加后缀的包名(如“pany.appname“),此时我们拿到的编译类型为空,那么我们可以在获取包名后做一个检查:

private static String checkPackageName(String packageName) {String[] temp = packageName.split("\\.");String sub = temp[temp.length - 1];//如果多包共存模式,剔除包名中的后缀if (sub.equals("debug")) {StringBuilder sb = new StringBuilder();for (int i = 0; i < temp.length - 1; i++) {sb.append(temp[i]);if (i != temp.length - 2) {sb.append(".");}}packageName = sb.toString();}return packageName;}

深入学习

同步aar到jCenter与maven central

Android Studio使用Gradle上传AAR至Maven

aar无法设置debug问题解决参考

查看原文:/u0108184...

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。