前言
之前我写过一篇博客,介绍使用同一套代码打多个APP,既然是多个app,那么每一个App的applicationId不一样,App的名字也不一样,图标也可以不一样。但在上次的介绍中,我们看到,其实有一个东西是没有改变的,那就是包名,包名不是指manifest中的package,而是指com.xxx.xxx,这个是没有改变的,如果我们项目需要在修改applicationId的同时也需要修改包名,一般情况下那么我们还需要手动修改包名。手动修改比较麻烦,涉及到的相关类很多,修改起来就不那么放心。这里将介绍使用gradle脚本帮助我们完成这个工作。
实现思路
实现的思路和简单,我将其分为几步
- 替换app/src/main目录下的所有package,比如将life.bill.com.myapplication替换成com.cs,并且替换proguard-rules.pro和build.gradle中相关内容
- 将app/src/main/java/life/bill/com/myapplication目录下的文件复制到app/src/main/java/com.cs目录下,
- 删除之前的目录app/src/main/java/life
具体实现
首先得在项目根目录下新建一个config.gradle文件,然后在根目录下build.gradle文件中导入这个文件apply from: this.file('config.gradle')
,在config.gradle中写入脚本,然后在Terminal中中执行这个脚本就可以了。
首先我们看我们使用Demo的例子,大家注意看包名和Test类中导入的包名。在执行完脚本后就都更改,接下来直接看脚本
ext {
//复制代码的目录
fromPath = 'app/src/main/java/life/bill/com/myapplication'
//复制要放到的新目录
intoPath = 'app/src/main/java/com.cs'
//删除以前的目录
deletePath = 'app/src/main/java/life'
//修改前的package
packageName = 'package life.bill.com.myapplication'
//修改后的package
toPackageName = 'package com.cs'
//修改前的applicationId
applicationIds = 'life.bill.com.myapplication'
//修改后的applicationId
toApplicationIds = 'com.cs'
}
//替换每一个java文件中的引用路径
task replaceImportPath {
doFirst {
//生成一个文件树,替换import后面的路径
FileTree tree = fileTree('app/src/main') {
//需要包含xml,AndroidManifest.xml
include '**/*.java'
include '**/*.xml'
}
//遍历文件树
tree.each { File mfile ->
fileReader(mfile.path, toApplicationIds)
}
//单独替换混淆文件
fileReader("app/proguard-rules.pro", toApplicationIds)
fileReader("app/build.gradle", toApplicationIds)
}
}
def fileReader(path, target_package) {
def readerString = "";
def hasReplace = false
file(path).withReader('UTF-8') { reader ->
reader.eachLine {
if (it.find(applicationIds)) {
it = it.replace(applicationIds, target_package)
hasReplace = true
}
readerString <<= it
readerString << '\n'
}
if (hasReplace) {
//打印替换过的文件名字
println(path + " has replace package.")
file(path).withWriter('UTF-8') {
within ->
within.append(readerString)
}
}
return readerString
}
}
task copyFile(type: Copy) {
//首先调用replacePackageName
dependsOn replaceImportPath
//进行文件替换
from fromPath
into intoPath
//替换文件 package后面路径
filter { String line ->
if (line.find(packageName)) {
//替换字符串
line = line.replace(packageName, toPackageName)
}
"$line"
}
//删除原目录
doLast {
File file1 = new File(deletePath);
file1.deleteDir();
}
}
下面的执行脚本后的打印
下面是执行完脚本后的目录结构,这里可以看到包名直接就被更改了
如果你有这样的需求,相信使用这个脚本能帮助都到你,但是如果你对gradle 一点了解也没有,那么你将只会用,如果需求有改动却不会修改成自己想要的。所以后面我将写几篇关于gradle的博客,介绍下这个脚本里面的知识点,以及gradle其他相关知识。
Gradle从入门到实战 - Groovy基础
全面理解Gradle - 执行时序
全面理解Gradle - 定义Task
Gradle 使用指南 – 基础配置
Gradle入门系列(三)——初识Gradle与Project
Gradle入门系列(五)——Gradle其它模块与Plugin插件
gradle配置优化及dependencies中各种依赖方式说明
buildscript中的repositories和allprojects的repositories的作用和区别
Gradle项目中gradle.build文件中的buildScript代码块
浅谈Gradle(二)与SourceSets
Gradle之SourceSet
Gradle学习
Gradle 使用指南 – 基础配置
Gradle Plugin入门使用
从源码角度分析 Gradle 插件对 Android 的扩展