Last active
September 28, 2017 06:56
-
-
Save aJIEw/4c666af6c4f9b5fb8f9786e236c76073 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 有时候为了直接跑别人的Android Studio项目而不去下载gradle或者SDK Platform, | |
* 常常需要手动修改 build.gradle文件和 gradle-wrapper.properties文件, | |
* 当有很多个项目的时候,这种工作就很难忍受了(比如当你要跑很多Sample的时候), | |
* 所以写了这个工具类(使用正则表达式)来批量修改同一个文件夹下的多个项目。 | |
* <p> | |
* 调用 {@link #setupOneLevelProjects(String)} 修改只有单层的项目文件夹,或者 | |
* {@link #setupTwoLevelProjects(String, String, String[])} 修改具有两层目录的项目文件夹。 | |
* <p> | |
* 默认匹配的 module 为 app,可以在{@link #DEFAULT_MODULES}中继续添加。 | |
* <p> | |
* <p> | |
* Tips:使用前请先复制一个旧项目试验一下 | |
*/ | |
@SuppressWarnings({"ConstantConditions", "WeakerAccess"}) | |
public class ChangeGradleFiles { | |
public static void main(String[] args) { | |
ChangeGradleFiles change = new ChangeGradleFiles(); | |
// 修改只有一层的文件夹,即该目录下就是所有的 Android Studio 项目 | |
String path = "C:\\WorkSpace\\AndroidProject\\Library"; | |
change.setupOneLevelProjects(path); | |
// 修改具有两层的文件夹,即第一层是目录,第二层才是项目,后两个参数可以为空 | |
//change.setupTwoLevelProjects(path, null, null); | |
// 修改该文件夹下所有以数字开头的项目文件夹,并跳过“14_”开头的文件夹 | |
/* | |
path = "D:\\WorkSpace\\AndroidProject\\FirstLineOfCodes"; | |
String filterRule = "\\d+_.+"; | |
String[] skipDirs = {"14_.+"}; | |
change.setupTwoLevelProjects(path, filterRule, skipDirs); | |
*/ | |
} | |
/** | |
* 默认匹配的module名,在{@link #modifyModuleGradle(File)}方法中遍历并修改匹配上的module | |
*/ | |
private static final String[] DEFAULT_MODULES = { | |
"app", | |
"Application", | |
"lib", | |
"library", | |
"sample", | |
"demo", | |
}; | |
/** | |
* gradle wrapper版本 | |
*/ | |
private static final String NEW_GRADLE_WRAPPER_VERSION = "distributionUrl=https\\://services.gradle.org/distributions/gradle-3.3-all.zip"; | |
/** | |
* 需要用正则表达式匹配的内容 | |
*/ | |
private static final String MATCH_GRADLE_PLUGIN_VERSION = "\\s+classpath 'com.android.tools.build:gradle.+"; | |
private static final String MATCH_BUILD_TOOLS_VERSION = "\\s+buildToolsVersion.+"; | |
private static final String MATCH_COMPILE_SDK_VERSION = "\\s+compileSdkVersion.+"; | |
private static final String MATCH_TARGET_SDK_VERSION = "\\s+targetSdkVersion.+"; | |
/** | |
* 匹配上后用于替换的新内容 | |
* <i>为简单起见,直接复制一整行的内容<i/> | |
*/ | |
private static final String NEW_GRADLE_PLUGIN_VERSION = " classpath 'com.android.tools.build:gradle:2.3.3'"; | |
private static final String NEW_BUILD_TOOLS_VERSION = " buildToolsVersion \"25.0.3\""; | |
private static final String NEW_COMPILE_SDK_VERSION = " compileSdkVersion 25"; | |
private static final String NEW_TARGET_SDK_VERSION = " targetSdkVersion 25"; | |
/** | |
* ----💥重要内容💥----<BR /> | |
* 匹配的数组和用于替换的新内容的数组,这两个数组长度、添加顺序必须一致 | |
* -------------------- | |
*/ | |
private static String[] sMatchContent, sNewContent; | |
static { | |
sMatchContent = new String[]{ | |
MATCH_BUILD_TOOLS_VERSION, | |
MATCH_COMPILE_SDK_VERSION, | |
MATCH_TARGET_SDK_VERSION, | |
}; | |
sNewContent = new String[]{ | |
NEW_BUILD_TOOLS_VERSION, | |
NEW_COMPILE_SDK_VERSION, | |
NEW_TARGET_SDK_VERSION, | |
}; | |
} | |
private String mMatchModulesRegex; | |
private List<String> mMatchModules = new ArrayList<>(); | |
private Map<String, String> mWrapperMap = new TreeMap<>(); | |
private Map<String, String> mProjectGradleMap = new TreeMap<>(); | |
private Map<String, String> mModuleGradleMap = new TreeMap<>(); | |
/** | |
* 初始化待匹配的moduel名,待匹配的内容和用于替换的内容 | |
*/ | |
public ChangeGradleFiles() { | |
mMatchModules.addAll(Arrays.asList(DEFAULT_MODULES)); | |
mWrapperMap.put("distributionUrl.+", NEW_GRADLE_WRAPPER_VERSION); | |
mProjectGradleMap.put(MATCH_GRADLE_PLUGIN_VERSION, NEW_GRADLE_PLUGIN_VERSION); | |
for (int i = 0; i < sMatchContent.length; i++) { | |
mModuleGradleMap.put(sMatchContent[i], sNewContent[i]); | |
} | |
} | |
/** | |
* 添加待匹配的module名,也可以直接在{@link #DEFAULT_MODULES}中继续添加 | |
*/ | |
public void addMatchModules(String... modules) { | |
mMatchModules.addAll(Arrays.asList(modules)); | |
} | |
/** | |
* 根据正则匹配module | |
* */ | |
public void setMatchModulesRegex(String matchModulesRegex) { | |
mMatchModulesRegex = matchModulesRegex; | |
} | |
/** | |
* 修改只有一层的文件夹,即路径所在的目录下就是所有的Android项目 | |
*/ | |
public void setupOneLevelProjects(String path) { | |
File dir = new File(path); | |
if (dir.isDirectory()) setup(dir); | |
} | |
/** | |
* 修改有两层的项目,即路径下第一层还是目录,第二层才是Android项目 | |
* 对于第一层的目录可以添加过滤规则,前提是你的目录的命名是有规则的,比如都以数字开头 | |
* 另外还可以利用第三个参数跳过某些文件夹,注意也是针对第一层的目录的 | |
* | |
* @param path the directory of projects | |
* @param filterRule add filter rule to your first level directory, support regex | |
* @param skipDirs add directories you need to skip, support regex | |
*/ | |
public void setupTwoLevelProjects(String path, String filterRule, String[] skipDirs) { | |
for (File projectParentDir : new File(path).listFiles()) { | |
String rule = filterRule == null ? ".+" : filterRule; | |
if (projectParentDir.isDirectory() && projectParentDir.getName().matches(rule)) { | |
if (skipDirs == null || skipDirs.length == 0) { | |
setup(projectParentDir); | |
} else { | |
for (String projectName : skipDirs) { | |
if (projectName != null && projectParentDir.getName().matches(projectName)) { | |
System.out.println("Skipped " + projectName); | |
break; | |
} else { | |
setup(projectParentDir); | |
} | |
} | |
} | |
} | |
} | |
} | |
/** | |
* 遍历当前目录下所有安卓项目(默认所有文件夹都是安卓项目)并修改其中的文件 | |
* | |
* @param projectParentDir The parent directory of your android projects | |
*/ | |
protected void setup(File projectParentDir) { | |
for (File projectDir : projectParentDir.listFiles()) { | |
if (projectDir.isDirectory()) { | |
for (File rootFile : projectDir.listFiles()) { | |
modifyWrapper(rootFile); | |
modifyProjectGradle(rootFile); | |
modifyModuleGradle(rootFile); | |
} | |
} | |
} | |
} | |
/** | |
* 修改gradle文件夹下的gradle-wrapper.properties | |
*/ | |
private void modifyWrapper(File projectFile) { | |
if (projectFile.isDirectory() && projectFile.getName().matches("gradle")) { | |
File gradleWrapper = new File( | |
projectFile.getAbsolutePath() + "\\wrapper\\gradle-wrapper.properties"); | |
modifyFileAccord(gradleWrapper, mWrapperMap); | |
} | |
} | |
/** | |
* 修改项目根目录下的 gradle.build 文件 | |
*/ | |
private void modifyProjectGradle(File projectFile) { | |
if (projectFile.isFile() && projectFile.getName().matches("build\\.gradle")) { | |
modifyFileAccord(projectFile, mProjectGradleMap); | |
} | |
} | |
/** | |
* 修改module下的gradle.build文件 | |
*/ | |
private void modifyModuleGradle(File projectFile) { | |
String projectDir = projectFile.getParent(); | |
String moduleDir = projectFile.getName(); | |
/* | |
* 从github上下载下来的开源库的名字格式为:项目名-master | |
* 而很多库的module名都与项目名相同,所以首先先匹配这些module | |
* */ | |
int hyphenIndex = projectDir.indexOf("-"); | |
if (hyphenIndex != -1) { | |
String projectName = projectDir.substring(0, hyphenIndex); | |
if (projectFile.isDirectory() && moduleDir.equalsIgnoreCase(projectName)) { | |
// modify the matched module's build.gradle | |
File moduleGradle = new File(projectFile.getAbsolutePath() + "\\build.gradle"); | |
modifyFileAccord(moduleGradle, mModuleGradleMap); | |
} | |
} | |
// 匹配之前定义的module名 | |
if (projectFile.isDirectory()) { | |
for (String matchModule : mMatchModules) { | |
if (moduleDir.matches(matchModule)) { | |
File moduleGradle = new File(projectFile.getAbsolutePath() + "\\build.gradle"); | |
modifyFileAccord(moduleGradle, mModuleGradleMap); | |
} | |
} | |
} | |
if (projectFile.isDirectory() && mMatchModulesRegex != null) { | |
if (moduleDir.matches(mMatchModulesRegex)) { | |
File moduleGradle = new File(projectFile.getAbsolutePath() + "\\build.gradle"); | |
modifyFileAccord(moduleGradle, mModuleGradleMap); | |
} | |
} | |
} | |
/** | |
* 根据传入的Map修改文件,map中的key为待匹配的内容,value为用于替换的内容 | |
* | |
* @param file The file you need to change. Key is for the content you need to match, | |
* the value is for the new content to replace the matched content. | |
* @param matchReplaceMap the mWrapperMap contains regular expression as key and new content as values | |
*/ | |
private void modifyFileAccord(File file, Map<String, String> matchReplaceMap) { | |
if (!file.exists()) { | |
System.out.println("-------------" + file + " does not exists!----------"); | |
return; | |
} | |
StringBuilder result = new StringBuilder(); | |
BufferedReader gradleFile = null; | |
int replacedNum = 0; | |
try { | |
gradleFile = new BufferedReader(new FileReader(file)); | |
String[] regexs = convertToArray( | |
matchReplaceMap.keySet().iterator(), | |
matchReplaceMap.keySet().size()); | |
String[] replaces = convertToArray( | |
matchReplaceMap.values().iterator(), | |
matchReplaceMap.values().size()); | |
boolean changed = false; | |
String line; | |
while ((line = gradleFile.readLine()) != null) { | |
for (int i = 0; i < regexs.length; i++) { | |
if (line.matches(regexs[i])) { | |
changed = true; | |
result.append(replaces[i]).append(System.getProperty("line.separator")); | |
replacedNum++; | |
break; | |
} | |
} | |
if (!changed) result.append(line).append(System.getProperty("line.separator")); | |
changed = false; | |
} | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} finally { | |
close(gradleFile); | |
} | |
System.out.println("Replaced " + replacedNum + " line(s) in the " + file.getAbsolutePath()); | |
writeIntoFile(file, result.toString()); | |
} | |
private String[] convertToArray(Iterator<String> itr, int size) { | |
String[] result = new String[size]; | |
for (int i = 0; itr.hasNext(); i++) { | |
result[i] = itr.next(); | |
} | |
return result; | |
} | |
private void writeIntoFile(File file, String content) { | |
BufferedWriter bufferedWriter = null; | |
try { | |
bufferedWriter = new BufferedWriter(new FileWriter(file)); | |
bufferedWriter.write(content); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} finally { | |
close(bufferedWriter); | |
} | |
} | |
private static void close(Closeable file) { | |
try { | |
if (file != null) { | |
file.close(); | |
} | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment