使用Nexus搭建Maven私有仓库

Nexus 是一个类似 Maven RepositoryBintray 的类库分发工具,允许用户将公用的组件打包发布,搭配 Maven 或者 Gradle 等依赖管理工具,开发者可以很方便地使用网络上的公共类库。

当公司发展到一定程度,会有多个项目并行开发时,有很多可以公用的部分可以抽出来,以公共类库的方式分发给多个项目使用,避免重复开发轮子。同时,通过版本号的管理,可以自由迭代公共类库,类库使用者可以自主决定升级步伐大小。

Nexus 与 Gitlab 类似,可以创建用户,给用户分配不同的角色。稍微不同的是,Nexus 的角色需要 admin 自己创建,有更大的自由度。

下载安装

  1. 从官网下载对应系统的 Nexus
  2. 解压
  3. 使用cd命令进入bin目录cd nexus-3.0.1-01/bin 然后执行./nexus run[1]

启动过程耗时比较长,出现下列字样即代表启动完成:

-------------------------------------------------

Started Sonatype Nexus OSS 3.6.2-01

-------------------------------------------------

默认的账号密码是 admin 与 admin123,及时修改密码保证安全。默认端口是8081,可以通过http://localhost:8081访问。在界面的右侧,可以找到接下来需要的操作入口。

control_pannel.png

创建仓库

一路点击 Repository -> Repositories -> Create repository 可以选择要创建的项目类型,在这里我们希望可以分发 android 类库,所以选择 maven2 类型的,并且由于是我们自己创建的私有库,所以选择hosted类型。

group/hosted/proxy 的区别可以查看官方文档,简单来说:

  1. group 允许你整合多个不同来源的 Repository,用户通过一个url即可引用所有这些Repository。
  2. hosted 托管我们自己开发的类库。
  3. proxy 链接到外部Repository,起缓存作用。

项目创建成功之后,点击Repository -> Repositories然后选择刚刚创建的 Repository,复制URL:后面的内容。

创建角色

通过给指定用户的角色,可以进行用户控制权限,一路点击Security -> Roles -> Create role -> Nexus role

填写完ID和Name之后,配置角色拥有的 Privilleges 即可,建议起码创建两种角色:developer和user。 privilleges.png

创建用户

用户指定的是用户登陆和使用Nexus的账号和密码,通过点击Security -> Users -> Create local user可以看到创建用户的表单,表单的最后是用户角色分配部分。

因为我们是集团内部使用的私有库,因为安全的原因不希望被未授权的用户使用,所以创建用户之后,需将匿名用户访问关闭。

Security -> Anonymous -> Allow anonymous users to access the server (unchecked) -> Save anonymous.png

上传库

通常来说,我们会开发多个类库(Http/Image/Task等),然后上传到同一个Repository中,同时因为我们的类库是私有库,需要加上认证信息,账号密码这些敏感信息强烈建议存放在本地的项目级别的local.properties中,并且Git应该ignore这个文件。

gradle的脚本不能直接引用local.properties的配置,同时为了多个类库可以同时使用这些认证信息,所以我们还会另外创建一个auth.gradle文件,并且在每个类库的push.gradle中引用。

local.properties文件:

nexusUsername=创建用户步骤得到ID
nexusPassword=创建用户步骤得到Password
nexusRepoUrl=创建仓库步骤得到的URL

auth.gradle文件:

Properties localProperties = new Properties()
localProperties.load(project.rootProject.file('local.properties').newDataInputStream())

ext.getNexusUsername = { ->
    return localProperties.getProperty('nexusUsername')
}

ext.getNexusPassword = { ->
    return localProperties.getProperty('nexusPassword')
}

ext.getNexusRepoUrl = { ->
    return localProperties.getProperty('nexusRepoUrl')
}

类库开发完成后,就可以着手上传到 nexus 中。在需要推送的 module 目录下,我们新建一个 Gradle 脚本,命名为push.gradle,当然名字可以随意修改。然后在module级别的build.gradle脚本最后引用我们刚刚创建的push.gradle

push.gradle文件:

apply plugin: 'maven'

apply from: '../auth.gradle'

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: getNexusRepoUrl()) {
                authentication(userName: getNexusUsername(), password: getNexusPassword())
            }

            pom.groupId = 'com.whaledr'
            pom.artifactId = 'commons'
            pom.version = '0.0.2'
        }
    }
}

build.gradle文件:

apply plugin: 'com.android.library'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"

    defaultConfig {
        //...
    }
    buildTypes {
		//...
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:appcompat-v7:25.3.1'
}

//新增
apply from: './push.gradle'

配置好之后,通过命令行执行./gradlew uploadArchives即可开始将所有配置好的类库打包上传到Nexus,如果只喜欢上传某个module,则需要指定module名,执行./gradlew :moduleName:uploadArchives

命令执行成功之后,可以进入Nexus后台,进入Browse server contents -> Browse -> Components,选择你的创建的Repository,即可看到你上传的类库。

components.png

类库是需要不断迭代开发的,修改类库之后,改变push.gradlepom.version属性的值,然后执行上述命令上传,用户即可通过版本号拉去不同版本,不同版本共存。

使用库

使用类库的方法与平时开发时依赖的第三方库的方法基本是一样的,只不过我们用的不是jcenter()或mavenCentral(),而是私有的Maven仓库,所以需要在 project 的 build.gradle加上声明,让gradle会去我们的仓库中引用依赖。

allprojects {
	repositories {
		jcenter()

		//新增
		maven {
			credentials {
				username 'yourNexusUsername'
				password 'yourNexusPassword'
			}
			url "yourNexusRepoUrl"
		}
	}
}

然后在 module 的 build.gradle 声明需要引用的依赖:

dependencies {
	compile fileTree(include: ['*.jar'], dir: 'libs')

	//新增
	compile 'me.notnull:commons:0.0.1'
}

如同上传库步骤所说,涉及到的敏感信息最好还是放在local.properties中,具体操作不再赘述。

项目中有使用到第三方提供的aar包(例如极验证v3)时,我们会这样定义本地依赖:

在项目build.gradle:

flatDir {
    dirs 'libs'
}

然后在module的build.gradle

dependencies {
	compile(name: 'gt3geetest-sdk', ext: 'aar')
}

gradle首先去Nexus查询一次是否存在在线版本,然后再尝试使用本地文件系统的aar包,问题就出在这次查询中,这个查询请求会一直执行,没办法停止,原因不明。

forever.png

解决办法

删除flatDir部分的定义,compile(name: 'gt3geetest-sdk', ext: 'aar') 修改为 compile files("libs/gt3geetest-sdk.aar")

其他

  1. 执行命令./nexus时可以得到结果 shell Usage: ./nexus {start|stop|run|run-redirect|status|restart|force-reload}

run命令跑在前台,关闭命令行即结束,start命令跑在后台,关闭命令行也不会退出。

  1. 使用库 部分我们说到授权信息是放在 local.properties 的,如果不介意整个团队用同一个账号,这些信息也可以放在 ~/.gradle/gradle.properties 中,Gradle标准库提供有方法方便读取其中的信息。