本文根据网络上的文章以及个人实践,综合整理而成。
做这件事的目的,是为了缩短APP的编译时间。
记得接手公司项目的时候,项目已经使用了当时流行的组件化方案,当时项目刚起步,组件不多,比较轻量化,编译一次正式版用时大概五分钟左右。这几年随着项目和技术的发展,组件化方案中间重构更换了一次,项目中的组件也发展到了二十多个,现在编译一次正式版,不算加固时间,用时十七分钟左右。
开发调试阶段目前也饱受困扰。由于所有组件都依赖base_lib,只要base中改了一个字符,debug调试编译时所有组件就会重新编译一遍,及其浪费时间。
要正常安装使用 maven 私服,需要几个前置条件,如果你的服务器都满足的话,可以跳过这几个配置:
Download jdk 11这里我下载的是Linux x64 Compressed Archive-jdk-11.0.22这个版本

使用sftp上传到服务器/opt/jdk目录

解压到当前目录
cd /opt/jdk
tar -zxvf jdk-11.0.22_linux-x64_bin.tar.gz

使用sftp修改环境配置文件:/etc/profile
#jdk config(在文档结尾插入)
export JAVA_HOME=/opt/jdk/jdk-11.0.22
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HIOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

重启 /etc/profile 使之重新生效:
source /etc/profile
验证 JDK 是否安装成功
java --version

Download Sonatype Nexus Repository根据安装的java版本选择对应的安装包,这里我下载的是/nexus-3.68.1-02-java11-unix这个版本,对应java11

使用sftp上传到服务器/opt/nexus目录
解压到当前目录
cd /opt/nexus
tar -zxvf nexus-3.68.1-02-java11-unix.tar.gz

使用sftp编辑配置文件/opt/nexus/nexus-3.68.1-02/bin/nexus.rc
run_as_user="root"

查看并开放8081端口
# 查看防火墙某个端口是否开放
firewall-cmd --query-port=8081/tcp
# 开放防火墙端口 8081
firewall-cmd --add-port=8081/tcp --permanent
# 重新加载防火墙规则
firewall-cmd --reload
# 再次查看防火墙某个端口是否开放
firewall-cmd --query-port=8081/tcp

进入bin目录启动nexus
cd /opt/nexus/nexus-3.68.1-02/bin
./nexus start

浏览器进入管理页面,http://[服务器ip]:8081

登录账号,admin 的密码在/opt/nexus/sonatype-work/nexus3/admin.password文件中

创建存储点
默认存储点是default,你也可以直接用默认的,不创建新的
登录账号,依次进入Setting->Repository->Blob Stores

创建仓库
在创建仓库前,先介绍一下仓库的三种存储类型Release、Snapshot和Mixed,创建仓库时会使用到
Release(正式版): 正式版,适合项目稳定后正式发布使用,特性看下面的原理简介。
Snapshot(快照版): 快照版,适合项目在开发调试中使用,特性看下面的原理简介。
Mixed(混合版): 可包含release和snapshot版本
Release与Snapshot的原理简介:
它们的主要区别在于本地获取这些依赖的机制不同。
-SNAPSHOT结尾,英文字母必须大写。依次进入Setting->Repository->Repositories


在module的 build.gradle 同级创建publish.gradle
apply plugin: "maven-publish"
afterEvaluate {
def ext = rootProject.ext
publishing {
publications {
release(MavenPublication) {
groupId 'com.wln100.future'
artifactId 'fragmentation'
version '1.0.0-SNAPSHOT'
if (isAndroidEnv(project)) {
from project.components.release
} else {
from project.components.java
}
pom {
name = 'fragmentation'
description = 'fragmentation'
url = ext.nexusMavenUrl
}
}
}
repositories {
maven {
allowInsecureProtocol true
url = ext.nexusMavenUrl
credentials {
username ext.nexusMavenUsername
password ext.nexusMavenPassword
}
}
}
}
}
static def isAndroidEnv(Project project) {
return project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library')
}
在 module 的 build.gradle 引入 publish.gradle
apply plugin: 'com.android.library'
...
android {
compileSdk compileVersion
defaultConfig {
...
}
buildTypes {
...
}
...
}
dependencies {
...
}
//引入自动发布gradle
apply from: project.file('publish.gradle')
同步代码,运行GradleTask

之后在仓库管理页面可以看到上传成功的module

管理页面进入Upload->android-examonline-hosted

上传aar,填写必要参数


首先需要在项目级的build.gradle中添加仓库地址:
buildscript {
...
repositories {
//本地私服仓
maven {
allowInsecureProtocol true
url 'http://[服务器ip]:8081/repository/[仓库名称]/'
}
...
}
...
}
...
allprojects {
repositories {
//本地私服仓
maven {
allowInsecureProtocol true
url 'http://[服务器ip]:8081/repository/[仓库名称]/'
}
...
}
}
...
dependencies {
//引入组件module
api 'com.wln100.future:fragmentation:1.0.0-SNAPSHOT'
//引入单个aar
api 'me.yokeyword.fragmentation:fragmentation_core:1.0'
}
我的解决方式为,发布module时,分别发布debug和release两包到两个仓库中;引入依赖时,根据编译命令动态切换对应的私服仓库:
//publish.gradle
afterEvaluate {
publishing {
publications {
release(MavenPublication) {
...
if (isAndroidEnv(project)) {
//打包release module
from project.components.release
} else {
from project.components.java
}
...
}
debug(MavenPublication) {
...
if (isAndroidEnv(project)) {
//打包debug module
from project.components.debug
} else {
from project.components.java
}
...
}
}
repositories {
maven {
allowInsecureProtocol true
//根据编译任务动态设置发布仓库
if (isReleaseBuild()) {
url = NEXUS_URL
} else {
url = NEXUS_DEBUG_URL
}
...
}
}
}
// 定义一个函数来判断是否为release版本
def isReleaseBuild() {
def taskNames = gradle.startParameter.taskNames
println "isReleaseBuild>>>>taskNames:$taskNames"
return taskNames.any { it.toLowerCase().contains("release") }
}
//project build.gradle
...
allprojects {
apply from: "$rootDir/gradle/maven-utils.gradle"
repositories {
...
//本地私服仓-自有组件
maven {
allowInsecureProtocol true
if (isReleaseBuild()) {
url NEXUS_URL
} else {
url NEXUS_DEBUG_URL
}
}
google()
...
maven { url 'https://jitpack.io' }
}
}
发布时配置发布参数withxml:
afterEvaluate {
publishing {
publications {
release(MavenPublication) {
...
pom {
...
withXml {
def dependenciesNode = asNode().getAt('dependencies')[0] ?:
asNode().appendNode('dependencies')
configurations.api.getDependencies().each {
dep -> addDependency(project, dependenciesNode, dep, "compile")
}
configurations.implementation.getDependencies().each {
dep -> addDependency(project, dependenciesNode, dep, "runtime")
}
}
}
}
debug(MavenPublication) {
...
pom {
...
withXml {
def dependenciesNode = asNode().getAt('dependencies')[0] ?:
asNode().appendNode('dependencies')
configurations.api.getDependencies().each {
dep -> addDependency(project, dependenciesNode, dep, "compile")
}
configurations.implementation.getDependencies().each {
dep -> addDependency(project, dependenciesNode, dep, "runtime")
}
}
}
}
}
...
}
}
private void addDependency(Project project, def dependenciesNode, Dependency dep, String scope) {
if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified") {
return
}
if (dep.version == 'unspecified') {
return
}
final dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('scope', scope)
dependencyNode.appendNode('groupId', dep.group)
dependencyNode.appendNode('artifactId', dep.name)
dependencyNode.appendNode('version', dep.version)
println("publish -> library <${dep.group}:${dep.name}:${dep.version}>")
if (!dep.transitive) {
// In case of non transitive dependency,
// all its dependencies should be force excluded from them POM file
final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
exclusionNode.appendNode('groupId', '*')
exclusionNode.appendNode('artifactId', '*')
} else if (!dep.properties.excludeRules.empty) {
// For transitive with exclusions, all exclude rules should be added to the POM file
final exclusions = dependencyNode.appendNode('exclusions')
dep.properties.excludeRules.each { ExcludeRule rule ->
final exclusionNode = exclusions.appendNode('exclusion')
exclusionNode.appendNode('groupId', rule.group ?: '*')
exclusionNode.appendNode('artifactId', rule.module ?: '*')
}
}
}
新建一个专门存放三方aar库的私服仓库,单独上传依赖三方aar。
//project build.gradle
...
allprojects {
apply from: "$rootDir/gradle/maven-utils.gradle"
repositories {
//本地私服仓-三方lib
maven{
allowInsecureProtocol true
url 'http://x.x.x.x:8081/repository/android-third-lib-hosted/'
}
...
google()
...
}
}
Centos开放端口以及查看端口和防火墙配置命令
centos7下搭建nexus
CentOS 7 安装 JDK11(注意版本号要与自己的版本一致)
centos7安装Nexus(Maven私服)与配置使用教程
【github】Blankj/AndroidUtilCode-publish.gradle