某些情况发布SDK时,需要提供Demo的代码,通常将其打包成zip文件(如腾讯X5)。右键压缩一个文件夹是我们平时最常用的方法,Demo代码文件夹也可以通过右键压缩。在Demo.zip只需要提供一次的情况下,右键压缩无疑是最好最快的方法,当需要经常改动代码且频繁发布Demo.zip时,右键压缩可能就不是最好的解决方案了。下面将介绍如何借助Gradle打包Demo代码的方法。
项目结构
项目目录结构
我的Android项目目录结构如下所示:
.
├── app
├── build.gradle
├── demo
├── sdk
└── settings.gradle
整个项目包含三个模块,sdk是可以对外发布的库模块;app为主要业务模块,是公司对外发布的产品,可以编译出对应的apk;demo作为使用sdk的样例模块,依赖于sdk,合作方接入sdk时可以作为参考。
demo模块目录结构
demo模块目录结构如下所示:
.
├── build
├── build.gradle
├── demo.iml
├── proguard-rules.pro
└── src
├── androidTest
│ └── java
├── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── res
└── test
└── java
对demo文件进行打包时,只需要包含build.gradle、proguard-rules.pro和src/main/这三个文件或目录,如果存在单元测试,可以把src/androidTest/和src/test/两个目录也包含进去。
build.gradle文件中有如下依赖:1
2
3
4
5dependencies {
... ...
implementation project(':sdk')
... ...
}
对demo文件进行打包时,需要将implementation project(':sdk')
替换为implementation files('libs/sdk.aar')
或者implementation 'com.xxx.xxx:sdk:1.0.0'
。
demo.zip结构
为了使demo.zip解压后,可以直接使用AndroidStudio打开demo项目,demo压缩包至少应该包含如下文件或目录:
.
├── README.md
├── build.gradle
├── demo
│ ├── build.gradle
│ ├── libs
│ │ └── sdk-R.1.0.0.aar
│ ├── proguard-rules.pro
│ └── src
│ └── main
└── settings.gradle
其中README.md为文档,帮助sdk使用者快速上手;build.gradle和settings.gradle是AndroidStudio导入demo时必需的gradle文件;demo/libs/sdk-R.1.0.0.aar是通过编译sdk模块时生成的;demo/目录下的文件都是从原来demo模块里面直接拷贝过来的。
build.gradle文件内容为:
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. |
和新建项目时自动生成的build.gradle一样。settings.gradle文件内容也可以认为是自动生成的:1
include ':demo'
现在已经了解原来项目的目录结构,和生成demo.zip所需要包含的文件夹以及文件内容,接下来需要完成拷贝文件/文件夹、生成文件、修改文件和压缩demo包的工作。
打包demo.zip
现在需要依次完成拷贝文件/文件夹、生成文件、修改文件和压缩demo包。
拷贝demo模块
在原项目的根目录下新建genDemo.gradle文件,然后在原项目的根目录下的build.gradle文件中添加如下代码:1
apply from: './genDemo.gradle'
临时目录为原项目根目录下的SDKDemo,每次打包时都要清理这个目录,如同make clean一样:1
2
3
4
5
6String sdkDemoName = 'SDKDemo'
String demoProjectRootDir = sdkDemoName
task cleanDemo {
delete demoProjectRootDir
}
将原项目的demo模块下的文件拷贝到SDKDemo/demo目录下:1
2
3
4
5
6
7
8
9
10
11
12
13task copyDemoSoruceToSDKDemo(type: Copy) {
from('demo') {
exclude '**/*.iml'
exclude '**/*.gitignore'
exclude '**/build'
exclude '**/androidTest'
exclude '**/test'
exclude '**/build.gradle'
}
into demoProjectRootDir + "/demo"
includeEmptyDirs false
}
这里没有拷贝demo/build.gradle文件,因为要对它进行特殊处理:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22task genModuleBuildGradle {
File buildGradleFile = new File(demoProjectRootDir + '/demo/build.gradle')
if (!buildGradleFile.exists()) {
buildGradleFile.getParentFile().mkdirs()
buildGradleFile.createNewFile()
}
buildGradleFile.withWriter('UTF-8') { writer ->
new File(projectDir.absolutePath + '/demo/build.gradle').withReader('UTF-8') { reader ->
reader.eachLine {
if (it.contains("implementation project(':sdk')")) {
writer.writeLine(''' File[] libFiles = new File('demo/libs').listFiles()
for (File file : libFiles) {
implementation files("libs/${file.name}")
}'''
)
} else {
writer.writeLine(it)
}
}
}
}
}
这一步主要是将implementation project(':sdk')
这一句替换为:1
2
3
4File[] libFiles = new File('demo/libs').listFiles()
for (File file : libFiles) {
implementation files("libs/${file.name}")
}'
拷贝sdk-1.0.0.aar
现在需要将sdk模块生成的aar文件拷贝到SDKDemo/demo/libs/目录下:1
2
3
4
5
6
7
8
9
10
11
12
13
14ext {
sdkVersionName = '1.0.0'
sdkArtifactId = 'sdk'
}
task copySDKLibToSDKDemoLibs(type: Copy) {
from('sdk/build/outputs/aar') {
include '**/*.aar'
}
eachFile {
it.path = sdkArtifactId + '-' + sdkVersionName + ".aar"
}
into demoProjectRootDir + "/demo/libs"
}
当编译sdk模块时,生成的aar名字为sdk-release.aar,需要根据版本号重新命名。
生成项目gradle文件
如果要让AndroidStudio直接打开SDKDemo就可以运行,至少需要在SDKDemo目录下生成build.gradle和settings.gradle两个文件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46task genSettingsGradle {
File settingsGradleFile = new File(demoProjectRootDir + '/settings.gradle')
if (!settingsGradleFile.exists()) {
settingsGradleFile.getParentFile().mkdirs()
settingsGradleFile.createNewFile()
}
settingsGradleFile.withWriter('UTF-8') { writer ->
writer.writeLine('''include ':demo' ''')
}
}
task genBuildGradle {
File buildGradleFile = new File(demoProjectRootDir + '/build.gradle')
if (!buildGradleFile.exists()) {
buildGradleFile.getParentFile().mkdirs()
buildGradleFile.createNewFile()
}
buildGradleFile.withWriter('UTF-8') { writer ->
writer.writeLine('''// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1\'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
''')
}
}
这里生成的build.gradle和settings.gradle文件内容和新建项目时自动生成的两个文件内容基本一致。
打包SDKDemo
目前为止,SDKDemo目录下已经有了所有需要打包的文件:
.
├── build.gradle
├── demo
│ ├── build.gradle
│ ├── libs
│ │ └── sdk-1.0.0.aar
│ ├── proguard-rules.pro
│ └── src
│ └── main
└── settings.gradle
现在要做的是配置打包任务:
1 | task zipDemo(type: Zip) { |
为了避免多次使用gradlew
执行前面定义的任务,现在把这些任务集合在一起:1
2
3
4
5
6
7
8
9
10tasks.create(name: "genDemo", dependsOn: [
cleanDemo,
copyReadMeToSDKDemo,
copyDemoSoruceToSDKDemo,
copySDKLibToSDKDemoLibs,
genModuleBuildGradle,
genSettingsGradle,
genBuildGradle,
zipDemo
])
最后只需要执行命令:1
./gradlew sdk:assemble genDemo
就会在原项目根目录下生成SDKDemo.zip文件了,可以将SDKDemo.zip文件上传到服务器或者直接发给用户了。
如果到这里还无法理解或运用此方法,可以在这里查看完整的项目代码。
总结
这篇文章主要介绍如何利用gradle在发布sdk时,如何方便快捷的打包demo模块的代码。学会如何使用gradle,在以后的工作学习中可以节省大量的开发时间来提升工作效率。
参考文档
[1] 记SDK发布