Android 在Gradle中上傳AAR, APK至Maven/FTP的指令碼
阿新 • • 發佈:2018-12-15
Android Studio Gradle Maven 上傳AAR,APK,JavaDoc,Source
在Gradle中上傳Android AAR, APK的Maven指令碼
說明
用於在構建基於Gradle的Android Application/Library時,向APK/AAR中新增構建資訊,打包JavaDoc,JavaSource,
ProgruardMapping,並向Maven倉庫提交.
注:為提高開發效率,僅當構建過程滿足isExpectBuild()方法的判定條件時,上述過程才會執行.
使用方法
在build.gradle中新增
apply from: ‘maven.gradle’
在buildscript依賴中新增
classpath ‘com.netflix.nebula:gradle-info-plugin:3.7.1’
最終可能如下所示:
apply plugin: 'com.android.application' //或者 apply plugin: 'com.android.library'
apply from: '../maven.gradle' //Maven上傳以及VCS資訊生成.
buildscript {
repositories {
google()
maven {
url "http://192.168.108.60/nexus/content/groups/public/"
}
jcenter( )
}
dependencies {
classpath "com.android.tools.build:gradle:$androidGradleVersion"
classpath 'com.netflix.nebula:gradle-info-plugin:3.7.1'
classpath "com.house365.build:android-shade-plugin:$shadeVersion"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
引數配置
並在gradle.properties中配置下列引數
#控制開關
publish_is_upload_remote = false //true:提交到遠端倉庫,false:提交到${project.rootDir}/repo目錄下
publish_is_build_javadoc = true //是否生成JavaDoc以及打包Source
#版本相關設定
publish_group_id=com.house365 //your group_id
publish_artifact_id=365TaoFang //your artifact_id
publish_version=6.1.5-SNAPSHOT //your version
publish_version_code=615
#倉庫相關設定
release_repository_url=ftp://192.168.108.42/projects/
snapshot_repository_url=ftp://192.168.108.42/projects/
nexus_username=your_username
nexus_password=your_password
實現指令碼
maven.gradle 指令碼內容如下,目前Android Gradle Plugin 3.1.4測試可用,如發現不相容,可留言說明。
Github地址:https://github.com/zawn
import java.lang.reflect.Field
import java.text.SimpleDateFormat
/**
* 用於在構建基於Gradle的Android Application/Library時,向APK/AAR中新增構建資訊,打包JavaDoc,JavaSource,
* ProgruardMapping,並向Maven倉庫提交.
* 注:為提高開發效率,僅當構建過程滿足isExpectBuild()方法的判定條件時,上述過程才會執行.
*
* 使用方法,在build.gradle中新增
* apply from: 'maven.gradle'
* 並在gradle.properties中配置下列引數
#控制開關
publish_is_upload_remote = false //true:提交到遠端倉庫,false:提交到${project.rootDir}/repo目錄下
publish_is_build_javadoc = true //是否生成JavaDoc以及打包Source
#版本相關設定
publish_group_id=com.myapp //your group_id
publish_artifact_id=365TaoFang //your artifact_id
publish_version=6.1.5-SNAPSHOT //your version
publish_version_code=615
#倉庫相關設定
release_repository_url=ftp://192.168.108.42/projects/
snapshot_repository_url=ftp://192.168.108.42/projects/
nexus_username=your_username
nexus_password=your_password
*/
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
}
}
apply plugin: 'maven'
apply plugin: 'nebula.info'
configurations {
deployerJars
}
dependencies {
deployerJars 'org.apache.maven.wagon:wagon-ftp:2.2'
}
def groupId = project.publish_group_id
def artifactId = project.publish_artifact_id
def version = project.publish_version
def localReleaseDest = "${project.getRootDir()}/repo"
@groovy.transform.Field private final java.util.Date date = new Date()
def getReleaseRepositoryUrl() {
return hasProperty('release_repository_url') ? release_repository_url
: "http://192.168.108.60/nexus/content/repositories/releases/"
}
def getSnapshotRepositoryUrl() {
return hasProperty('snapshot_repository_url') ? snapshot_repository_url
: "http://192.168.108.60/nexus/content/repositories/snapshots/"
}
def getRepositoryUsername() {
return hasProperty('nexus_username') ? nexus_username : ""
}
def getRepositoryPassword() {
return hasProperty('nexus_password') ? nexus_password : ""
}
def isUploadRemoteMaven() {
return hasProperty('publish_is_upload_remote') ? publish_is_upload_remote.toBoolean() : false
}
def isBuildJavaDoc() {
return hasProperty('publish_is_build_javadoc') ? publish_is_build_javadoc.toBoolean() : false
}
def getAndroidGradlePluginVersion() {
Class<?> clazz = Class.forName("com.android.builder.model.Version", false, project.getBuildscript().getClassLoader());
Field field = clazz.getField("ANDROID_GRADLE_PLUGIN_VERSION");
String androidGradlePluginVersion = (String) field.get(clazz);
String[] strings = androidGradlePluginVersion.split("-");
return strings[0];
}
clean.doFirst {
delete "file://${localReleaseDest}"
}
uploadArchives
{
repositories.mavenDeployer {
//新增FTP協議支援.
addProtocolProviderJars configurations.deployerJars.files
pom.groupId = groupId
pom.artifactId = artifactId
pom.version = version
// Add other pom properties here if you want (developer details / licenses)
repository(url: "file://${localReleaseDest}")
if (isUploadRemoteMaven()) {
// 關閉上傳至私有Maven倉庫
repository(url: getReleaseRepositoryUrl()) {
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
}
snapshotRepository(url: getSnapshotRepositoryUrl()) {
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
}
}
}
}
/**
* 歸檔APK檔案.
*/
private String defArchiveApkTasks(variant) {
def variantData = variant.variantData
final configuration = variantData.variantConfiguration
def archiveApkTaskName = "archive${variant.name.capitalize()}Apk"
def writeManifestPropertiesTask = tasks.getByName("writeManifestProperties")
task(archiveApkTaskName, dependsOn: writeManifestPropertiesTask) {
group "archive"
description = 'APK file archiving. '
Map<String, ?> manifest = writeManifestPropertiesTask.getManifest()
for (Map.Entry<String, ?> entry : manifest.entrySet()) {
String fieldName = entry.getKey();
if (entry != null && fieldName != null) {
fieldName = fieldName.replace("-", "_");
final boolean matches = fieldName.matches("^[a-zA-Z_\$][a-zA-Z_\$0-9]*\$");
if (matches) {
String fieldValue = entry.getValue() != null ? entry.getValue().toString() : "";
fieldValue = fieldValue.replace("\\", "\\\\");
fieldValue.replace("\"", "\\\"");
configuration.addBuildConfigField("String", fieldName, "\"" + fieldValue + "\"");
} else {
logger.log(LogLevel.WARN, "Lost BuildConfigField,illegal name :" + fieldName)
}
}
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
configuration.addBuildConfigField("String", "Build_Date", "\"" + sdf.format(date) + "\"");
String revision = manifest.get("Change");
variant.outputs.each { output ->
ext.destFile = output.outputFile
if (revision == null)
revision = ""
ext.destRevision = revision
}
}
variantData.generateBuildConfigTask.dependsOn(archiveApkTaskName)
return archiveApkTaskName
}
def defJavaDocAndJavaSourceTasks = { dependsOnTaskName, variant, variantPrefix ->
task("generate${variant.name.capitalize()}Javadoc", type: Javadoc, dependsOn: dependsOnTaskName) {
description "Generates Javadoc for $project.name."
group "javadoc"
source = variant.javaCompile.source
// compatible android gradle plugin 3.1
def taskName = variant.variantData.getScope().getTaskName("compile", "JavaWithJavac")
def classFiles = project.tasks.findByName(taskName).getClasspath()
options {
failOnError false
encoding "utf-8"
charSet "utf-8"
links "http://docs.oracle.com/javase/7/docs/api/"
linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference"
}
// fix java 8 very strict.
if (JavaVersion.current().isJava8Compatible()) {
options.addStringOption('Xdoclint:none', '-quiet')
}
// exclude '**/BuildConfig.java'
exclude '**/R.java'
}
if (variantPrefix != null) {
variantPrefix = variantPrefix + "-"
} else {
variantPrefix = ""
}
task("jar${variant.name.capitalize()}Javadoc", type: Jar, dependsOn: "generate${variant.name.capitalize()}Javadoc") {
group "archive"
description "Jar Javadoc for $project.name."
classifier = "${variantPrefix}javadoc"
from tasks.getByName("generate${variant.name.capitalize()}Javadoc").destinationDir
}
task("jar${variant.name.capitalize()}Sources", type: Jar, dependsOn: dependsOnTaskName) {
group "archive"
description "Jar sources for $project.name."
classifier = "${variantPrefix}sources"
from variant.javaCompile.source
}
}
def defZipProgruardMappingTask = { dependsOnTaskName, variant ->
if (variant.buildType.minifyEnabled) {
String variantPrefix = variant.buildType.name
if (variant.flavorName != null
&& !"".equals(variant.flavorName))
variantPrefix = variant.flavorName + "-" + variantPrefix
task("zip${variant.name.capitalize()}ProguardMapping", type: Zip, dependsOn: dependsOnTaskName) {
group "archive"
description = 'Assembles a ZIP archive containing the Proguard files of $variant.name..'
classifier "${variantPrefix}-proguard"
destinationDir = new File("$project.buildDir/libs/") // 設定和Jar預設路徑一致.
from "$project.buildDir/outputs/mapping/${variant.getDirName()}"
}
}
}
def defGenerateManifestTask = { dependsOnTaskName, variant ->
final configuration = variant.variantData.variantConfiguration
def writeManifestPropertiesTask = tasks.getByName("writeManifestProperties")
def processJavaRes = tasks.getByName("process${configuration.fullName.capitalize()}JavaRes")
def manifestOutputDir = project.file(new File(project.buildDir, "generated/resources/manifest"))
def manifestOutput = new File(manifestOutputDir, variant.dirName)
processJavaRes.from(manifestOutput)
def generateManifestTask = task("generate${variant.name.capitalize()}ManifestProperties").doLast {
Properties properties = new Properties() {
@Override
public synchronized Enumeration<Object> keys() {
return Collections.enumeration(new TreeSet<Object>(super.keySet()));
}
};
FileInputStream inputStream = new FileInputStream(writeManifestPropertiesTask.getPropertiesFile())
properties.load(inputStream)
inputStream.close()
properties.put("X-Android-PackageName", configuration.applicationId + "")
properties.put("X-Android-VersionName", configuration.getVersionName() + "")
properties.put("X-Android-VersionCode", configuration.getVersionCode() + "")
properties.put("X-Android-FullName", configuration.fullName)
properties.put("X-Android-BuildType", variant.buildType.name)
properties.put("X-Android-FlavorName", variant.flavorName)
properties.put("X-Android-MinSdkVersion", configuration.minSdkVersion.getApiString())
properties.put("X-Android-TargetSdkVersion", configuration.targetSdkVersion.getApiString())
File outputFile
if (variant.variantData.getClass().name.contains("ApplicationVariantData"))
outputFile = new File("${manifestOutput}/META-INF/build-info.properties")
else {
outputFile = new File("${manifestOutput}/META-INF/${configuration.applicationId}.properties")
}
if (outputFile.exists()) {
Properties oldProp = new Properties();
FileInputStream fileInputStream = new FileInputStream(outputFile)
oldProp.load(fileInputStream)
oldProp.remove("Build-Date");
final buildDate = properties.remove("Build-Date");
if (!oldProp.equals(properties)) {
properties.put("Build-Date", buildDate)
}
fileInputStream.close()
} else {
if (!outputFile.getParentFile().exists())
outputFile.getParentFile().mkdirs()
outputFile.createNewFile()
}
if (properties.containsKey("Build-Date")) {
try {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(outputFile))
properties.store(bufferedWriter, "\nAutomatic generated.\n\[email protected] ZhangZhenli\n")
bufferedWriter.flush()
bufferedWriter.close()
} catch (IOException e) {
throw e
}
}
}
generateManifestTask.dependsOn writeManifestPropertiesTask
processJavaRes.dependsOn generateManifestTask
project.tasks.findByName("generate${variant.name.capitalize()}Resources").dependsOn generateManifestTask
}
/**
* 針對Android Library Module 打包AAR,Jar,JavaDoc,JavaSource。
*
* 注意:不支援變種.
*/
if (android.getClass().name.contains("LibraryExtension")) {
android.libraryVariants.all { variant ->
final configuration = variant.variantData.variantConfiguration
String dependsOnTaskName = "assemble${configuration.fullName.capitalize()}"
boolean isBuild = isExpectBuild(configuration)
if (!"".equals(variant.flavorName)) {
throw new GradleException("Do not set flavors ,the current maven.gradle script does not support multiple flavors!")
}
if (isBuild || variant.buildType.name.equals("release")) {
if (isBuildJavaDoc()) {
String variantPrefix = null
defJavaDocAndJavaSourceTasks(dependsOnTaskName, variant, variantPrefix)
}
defZipProgruardMappingTask(dependsOnTaskName, variant)
defGenerateManifestTask(dependsOnTaskName, variant)
/**
* 打包當前程式碼為Jar檔案.
* 你在使用該Jar檔案的時候可能會出錯,因為該Jar檔案不包含需要的R檔案,如果確需引用請確保你在類
* 中沒有對R的引用,如果你的Android Library Module不包含任何資原始檔或沒有對其進行引用則可放
* 心使用。
*/
def jarClassesWithoutRTaskName = "jar${variant.name.capitalize()}ClassesWithoutR"
task(jarClassesWithoutRTaskName, dependsOn: dependsOnTaskName) {
group "archive"
description = 'Assemble a JAR file, the same as the Jar file included with the AAR,does not include class R.'
if (project.getPlugins().hasPlugin("com.android.library")) {
String leaf;
String variantName = configuration.fullName;
String stringVersion = getAndroidGradlePluginVersion();
if (stringVersion.matches('^2.3.(\\*|\\d+)$')) {
// version match
if (android.getPublishNonDefault() ||
!variantName.equals(android.getDefaultPublishConfig())) {
leaf = variantName;
} else {
leaf = "default";
}
} else {
leaf = variantName;
}
ext.destFile = project.file("${project.buildDir}/intermediates/bundles/${leaf}/classes.jar")
if (stringVersion.matches('^3.1.(\\*|\\d+)$')) {
ext.destFile = project.file("${project.buildDir}/intermediates/packaged-classes/${leaf}/classes.jar")
}
} else {
ext.destFile = project.file("${project.buildDir}/intermediates/classes-proguard/${variant.getDirName()}/classes.jar")
}
}
artifacts {
archives file: tasks.getByName(jarClassesWithoutRTaskName).destFile, classifier: 'jar', builtBy: tasks.getByName(jarClassesWithoutRTaskName)
if (variant.buildType.minifyEnabled) {
archives tasks.getByName("zip${variant.name.capitalize()}ProguardMapping")