Android Gradle学习记录6 代码记录(持续补充)
来源:互联网 发布:韩国工业 知乎 编辑:程序博客网 时间:2024/05/16 13:47
本篇博客主要记录一些,自己觉得比较有价值的Gradle代码片段。
1、生成doc文档:
ext { sdkDocOption = ['encoding' : 'utf-8', 'locale' : 'en_US', 'docEncoding' : 'utf-8', 'charSet' : 'utf-8', 'header' : 'AVLSDK API', 'footer' : 'AVLSDK API', 'windowTitle' : 'AVLSDK API', 'title' : 'AVLSDK API', 'include' : 'com/avl/engine/*.java', 'destinationDir' : 'sdk/doc']}//继承Javadoc类型的Task//为source对应的文件生成Java Doctask buildSdkDoc(type: Javadoc, dependsOn: 'copyClasses') { source = android.sourceSets.main.java.srcDirs classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) options.encoding = sdkDocOption.get('encoding') options.locale = sdkDocOption.get('locale') options.docEncoding = sdkDocOption.get('docEncoding') options.charSet = sdkDocOption.get('charSet') options.header = sdkDocOption.get('header') options.footer = sdkDocOption.get('footer') options.windowTitle = sdkDocOption.get('windowTitle') title = sdkDocOption.get('title') include(sdkDocOption.get('include')) destinationDir = reporting.file(sdkDocOption.get('destinationDir')) failOnError false}
2、生成Jar包并混淆
ext { //Decide class files that will not be added into jar excludeFilesWhenBuildJar = [ 'com/example/**/BuildConfig.class', 'com/example/**/R.class', 'com/example/**/R$*.class'] as String[] //proguard file configurationFile = [file('proguard.txt'),] as File[] needPackageObfuscation = false sdkJarName = 'ExampleSDK.jar' proguardSdkJarName = 'ExampleSDK-proguard.jar'}//继承Jar类型的Task//将build/sdk/classes下的文件,打包成Jar//除去excludeFilesWhenBuildJar中的文件task buildSdkJar(type: Jar, dependsOn: ['copyClasses', 'buildSdkDoc'], description: "build sdk jar") { from 'build/sdk/classes' for (String fileName : excludeFilesWhenBuildJar) { exclude(fileName) } includeEmptyDirs false archiveName sdkJarName}//继承ProGuardTask类型的Task//根据混淆文件,混淆Jar包task buildProGuardJar(type: ProGuardTask, dependsOn: buildSdkJar) { doFirst { def proguardDir = file("$buildDir/libs/proguard") proguardDir.mkdirs() } //未混淆的Jar包 injars file("${buildDir}/libs/${sdkJarName}") //混淆后Jar的存储地址 outjars file("${buildDir}/libs/${proguardSdkJarName}") //指定其它需要文件的地址 libraryjars android.getBootClasspath() + ";" + file("libs/android-support-v4.jar") printseeds file("${buildDir}/libs/proguard/seed.txt") printusage file("${buildDir}/libs/proguard/usage.txt") printmapping file("${buildDir}/libs/proguard/mapping.txt") dump file("${buildDir}/libs/proguard/dump.txt") //指定混淆需要的配置文件 //可以指定多个文件 configuration file(rootProject.getRootDir().getAbsolutePath() + '/SDKConfig/proguard-base.txt') configuration configurationFile if (needPackageObfuscation) { //指定package的模糊字典 packageobfuscationdictionary file("packageobfuscationdictionary.txt") } //NOTE:proguard has bug,dump file not generated in specified folder doLast { copy { from 'build/libs/dump.txt' into 'build/libs/proguard' } }}
3、copy闭包
普通的Task,即使不继承CopyTask,也可以使用copy闭包。
def copySdkDoctask test() { doLast { copySdkDoc() }}copySdkDoc = { ........ //定义好目的地址 def userDir = new File(user_path) if (userDir.exists()) { delete userDir } userDir.mkdirs() copy { //指定源文件地址 from("$projectDir/build/reports/sdk") { //指定包含的文件类型 include('**/*') } into(user_path) }}
copy的同时,可以重命名文件:
copyJarAndRepackage = { def sdkVer = getSdkVersionFromXml(); copy { from("$projectDir/build/libs") into(user_path) //sdkJarName和proguardSdkJarName //均是"$projectDir/build/libs"下的文件名 rename(sdkJarName, "${outputName}_unproguard.jar") rename(proguardSdkJarName, "${outputName}_" + sdkVer + '.jar') }}
4、解压zip包
//File表示源文件//newPath对应解压后的存储路径def static void unzipFile(File file, String newPath) { def zipFile = new ZipFile(file) def entries = zipFile.entries() while (entries.hasMoreElements()) { def entry = (ZipEntry) entries.nextElement() def zipEntryName = entry.getName() //必要是将路径中的"\"替换为"/" def outPath = (newPath + File.separator + zipEntryName).replaceAll("\\\\", "/") def outDir = new File(outPath.substring(0, outPath.lastIndexOf('/'))) if (!outDir.exists()) { outDir.mkdirs() } if (new File(outPath).isDirectory()) { continue } def input = zipFile.getInputStream(entry) def output = new FileOutputStream(outPath) def buf = new byte[1024] def len while ((len = input.read(buf)) > 0) { output.write(buf, 0, len) } input.close() output.close() }}
5、计算文件的md5
def static String generateMd5BaseFile(File file) { def md5 = MessageDigest.getInstance("MD5") def buffer = new byte[1024] def numRead def fis = new FileInputStream(file) while ((numRead = fis.read(buffer)) > 0) { md5.update(buffer, 0, numRead) } def HEX_DIGITS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'] def bArray = md5.digest() def sb = new StringBuilder(bArray.length * 2) for (byte b : bArray) { sb.append(HEX_DIGITS[(b & 0xf0) >>> 4]) sb.append(HEX_DIGITS[b & 0x0f]) } fis.close() return sb.toString()}
6、解析Json字符串
//info对应json字符串//key为需查找的keydef String getValueFromJsonString(String key, String info) { def parsedJson = new groovy.json.JsonSlurper().parseText(info) return parsedJson.get(key)}
参考:
http://groovys.readthedocs.io/zh/latest/Groovy-module-guides/Parsing-and-producing-JSON.html
http://docs.groovy-lang.org/latest/html/gapi/groovy/json/JsonBuilder.html#call(java.util.Map)
7、使用Jar包
在Gradle中,通过命令使用Jar包时,需要注意这是一个异步操作,
即命令将在单独的线程中执行。
def void encryptBaseConfAseJar(String srcFilePath, String outFilePath, String flagPath) { .............. //这种方式是靠控制台命令来执行jar包的 //指定jar路径,并提供参数即可 def cmd = 'java -jar ' + jarPath + ' -encrypt '+ srcFilePath + ' ' + outFilePath + ' ' + keyDir + ' ' + flagPath cmd.execute()}
8、正则表达式
def static String getVersionBasePattern(String path) { def file = new File(path) def input = new FileInputStream(file) def bytes = new byte[input.available()] input.read(bytes) input.close() def info = new String(bytes, "GB2312") def p = Pattern.compile("Build \\d+") def m = p.matcher(info) def target = [] while (m.find()) { target.add(m.group()) } p = Pattern.compile("[^0-9]") def ret for (String str : target) { m = p.matcher(str) ret = m.replaceAll('').trim() if (ret != '') { return ret } } return ''}
9、AES加解密
加密过程如下:
//srcFilePath源文件地址//destFilePath加密后的文件地址def void aesEncrypt(String srcFilePath, String destFilePath) { //16进制的AES_KEY def AES_KEY = ".........." def ALGORITHM = "AES" def TRANSFORMATION = "AES/ECB/PKCS5Padding" def sKeySpec = new SecretKeySpec(parseHexStr2Byte(AES_KEY), ALGORITHM) def encryptCipher = Cipher.getInstance(TRANSFORMATION) encryptCipher.init(Cipher.ENCRYPT_MODE, sKeySpec) FileInputStream inStream = new FileInputStream(new File(srcFilePath)) CipherOutputStream cipherOutputStream = new CipherOutputStream(new FileOutputStream(new File(destFilePath)), encryptCipher) def read while ((read = inStream.read()) != -1) { cipherOutputStream.write((byte) read) cipherOutputStream.flush() } inStream.close(); cipherOutputStream.close();}//将16进程变为byte数组def static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1) { return null } def len = hexStr.length() / 2 def result = new byte[len] for (int i = 0; i < len; i++) { def high = Integer.parseInt(hexStr.substring(i << 1, (i << 1) + 1), 16) def low = Integer.parseInt(hexStr.substring((i << 1) + 1, (i << 1) + 2), 16) result[i] = (byte) (high * 16 + low) } return result;}
解密过程如下:
def static String decrypt(byte[] rawByte) { //加(解)密时使用的key def KEY = [.......] as byte[] //处理KEY byte[] key = messKey(KEY) SecretKeySpec sKey = new SecretKeySpec(key, "AES") //加(解)密时使用的AES def AES = [.......] as byte[] Cipher cipher = Cipher.getInstance(new String(messKey(AES))) cipher.init(Cipher.DECRYPT_MODE, sKey) return new String(cipher.doFinal(rawByte))}def static byte[] messKey(byte[] bArray) { def ret = new byte[bArray.length] //定义key,作用类似于混淆,转换原始的key byte key = .... for (int i = 0; i < bArray.length; ++i) { ret[i] = (byte) (bArray[i] ^ key) } return ret}
10、Zip压缩
//inputPath源文件路径//outPath目的文件路径def void zipFile(String inputPath, String outPath) { def inputFile = new File(inputPath) if (!inputFile.exists()) { println 'inputFile not exist: ' + inputPath } def outFile = new File(outPath) if (outFile.exists()) { delete outFile } outFile.createNewFile() ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outFile)) zipUtil(out, inputFile, '') out.close()}//递归def void zipUtil(ZipOutputStream out, File f, String baseName) { if (f.name.startsWith('.')) { return } if (f.isDirectory()) { def fl = f.listFiles() if (fl.length == 0) { out.putNextEntry(new ZipEntry(baseName + "/")) out.closeEntry() return } def pre = baseName if (baseName != '') { pre = baseName + "/" } for (File file : fl) { zipUtil(out, file, pre + file.name) } } else { out.putNextEntry(new ZipEntry(baseName)) BufferedInputStream bi = new BufferedInputStream(new FileInputStream(f)) int num while ((num = bi.read()) != -1) { out.write(num) } bi.close() out.closeEntry() }}
11、向Zip包中添加文件
//srcFilePath代表待添加文件的路径//targetPath代表Zip包的路径//dirName为Zip中的目录,srcFilePath对应的文件将被加入到dirName下def void zipAdd(String[] srcFilePath, String targetPath, String dirName) { def destFile = new File(targetPath) if (!destFile.exists()) { println 'can not find file: ' + targetPath return } def targetFile = [] for (String src : srcFilePath) { def file = new File(src) if (file.exists()) { targetFile.add(file) } } zipAddUtil(targetFile, destFile, dirName)}def void zipAddUtil(ArrayList<File> srcFiles, File destFile, String dirName) { def tempFile = File.createTempFile(destFile.getName(), null, destFile.getParentFile()) if (tempFile.exists()) { delete tempFile } destFile.renameTo(tempFile) byte[] buf = new byte[1024] def zin = new ZipInputStream(new FileInputStream(tempFile)) def out = new ZipOutputStream(new FileOutputStream(destFile)) //First copy old files def entry = zin.getNextEntry() def name def len while (entry != null) { name = entry.getName() out.putNextEntry(new ZipEntry(name)) while ((len = zin.read(buf)) > 0) { out.write(buf, 0, len) } out.closeEntry() entry = zin.getNextEntry() } zin.close() //Then insert new files for (File srcFile : srcFiles) { InputStream input = new FileInputStream(srcFile) out.putNextEntry(new ZipEntry(dirName + "/" + srcFile.name)) while ((len = input.read(buf)) > 0) { out.write(buf, 0, len) } out.closeEntry() input.close() } out.close() delete tempFile}
12、获取当前的软件版本和TAG
def static int getGitVersionCode(String projectPath) { //其实就是调用控制台命令 def cmd = 'git -C ' + projectPath + ' rev-list HEAD --first-parent --count' def versionCodeStr = cmd.execute().text.trim() if ("" == versionCodeStr) { return 1 } return versionCodeStr.toInteger()}def static String getGitVersionTag(String projectPath) { def cmd = 'git -C ' + projectPath + ' describe --tags' def version = cmd.execute().text.trim() def pattern = "-(\\d+)-g" def matcher = (version =~ pattern) if (matcher) { version = version.substring(0, matcher.start()) } return version}
13、代码检查
Gradle中可以直接通过集成的方式,定义代码检查需要的task。
例如:
lint:
android { //android中直接支持lint检查 lintOptions { abortOnError false //定义输出格式为xml xmlReport true htmlReport false //定义lint的检测规则 lintConfig file("...../lint.xml") //定义lint结果输出路径 xmlOutput file(".../lint_result.xml") }}
checkStyle:
//为了进行代码检查,需要导入对应的插件apply plugin: 'checkstyle'task checkstyle(type: Checkstyle) { ignoreFailures = true //定义checkStyle的配置文件 configFile file("..../checkstyle.xml") //定义checkStyle的忽略配置 //可以指定某些文件,忽略特定的checkStyle规则 configProperties.checkstyleSuppressionsPath = file("......./suppressions.xml").absolutePath source = [android.sourceSets.main.java.srcDirs, 'src'] include '**/*.java' exclude '**/gen/**', '**/test/**' classpath = files() reports { //只能开启一个 xml.enabled = true html.enabled = false xml.destination "..../checkStyle_result.xml" }}
checkStyle的忽略文件类似于:
<suppressions> //R.java中的变量,不需要满足仅由小写字符、大写字符和数字构成 <suppress checks="[a-zA-Z0-9]*" files="R.java" /> ..........<suppressions>
findbugs:
apply plugin: "findbugs"task findBugs(type: FindBugs) { ignoreFailures = true effort = "max" //findBugs可以指定报告的输出等级 reportLevel = "low" //这里填写项目classes目录 classes = files("........./classes") source = [android.sourceSets.main.java.srcDirs, 'src'] classpath = files() includeFilter = file("......../findbugs-infilter.xml") reports { //只能开启一个 xml.enabled = true html.enabled = false xml.destination "..../findBugs_result.xml" }}
pmd:
apply plugin: 'pmd'task pmd(type: Pmd) { description 'Run pmd' group 'verification' ignoreFailures = true ruleSetFiles = files("......./pmd-ruleset.xml") ruleSets = [] source = [android.sourceSets.main.java.srcDirs, 'src'] include '**/*.java' exclude '**/gen/**', '**/test/**' reports { xml.enabled = true html.enabled = false xml.destination "...../pmd_result.xml" }}
14、defaultTasks
Gradle允许在脚本中定义一个或多个默认任务,如下:
defaultTasks 'clean', 'buildSdk'task clean << { println 'Default Cleaning!'}task run << { println 'Default build sdk!'}task other << { println "I'm not a default task!"}
此时直接调用gradle命令,不指定task,执行结果类似于:
Default Cleaning!Default build sdk!
需要注意的是:
必须要在定义defaultTasks的gradle文件对应Project的目录下,执行gradle命令。
defaultTasks可以为当前Project或子Project定义的task。
举例来说就是:
假设有个Project A,对应的gradle文件为buildA.gradle;
Project A有个子Project B,对应的gradle文件为buildB.gradle。
如果在buildA.gradle中定义defaultTasks,那么task可以定义在buildA.gradle、buildB.gradle中。
但执行gradle时,必须在Project A的目录下。
15、多任务调用及排除任务的命令
//依次执行多个任务gradle task1 task2 [...]//-x后接的任务将不被执行//例如,defaultTasks指定了task1, task2//此时,task1和task2不会执行了gradle -x task1 task2 [...]
16、文件树
文件树可以代表一个目录树结构或一个ZIP压缩文件的内容。
FileTree继承自FileCollection,我们可以像处理文件集合一样处理文件树。
FileTree的使用示例如下:
//以一个基准目录创建一个文件树FileTree tree = fileTree(dir: 'src/main')// 添加包含和排除规则tree.include '**/*.java'tree.exclude '**/Abstract*'// 使用路径创建一个树tree = fileTree('src').include('**/*.java')// 使用闭包创建一个树tree = fileTree('src') { include '**/*.java'}// 使用map创建一个树tree = fileTree(dir: 'src', include: '**/*.java')tree = fileTree(dir: 'src', includes: ['**/*.java', '**/*.xml'])tree = fileTree(dir: 'src', include: '**/*.java', exclude: '**/*test*/**')// 遍历文件树tree.each {File file -> println file}// 过滤文件树FileTree filtered = tree.matching { include 'org/gradle/api/**'}// 合并文件树AFileTree sum = tree + fileTree(dir: 'src/test')// 访问文件树的元素tree.visit {element -> println "$element.relativePath ------ $element.file"}
我们还可以使用ZIP或TAR等压缩文件的内容作为文件树,
Project.zipTree()和Project.tarTree()方法可以返回Project对应文件的FileTree实例。
示例用法如下:
// 使用路径创建一个ZIP文件FileTree zip = zipTree('someFile.zip')// 使用路径创建一个TAR文件FileTree tar = tarTree('someFile.tar')//TarTree可以根据文件扩展名得到压缩方式//如果我们想明确的指定压缩方式则可以如下操作FileTree someTar = tarTree(resources.gzip('someTar.ext'))
17、文件同步任务
同步任务(Sync)继承自复制任务(Copy)。
当执行时会复制源文件到目标目录,然后从目标目录删除所有非复制文件。
如下:
//将libs中的文件复制到test//最终test目录中的内容与libs一模一样task syncTask(type: Sync) { from 'libs' into 'test'}
- Android Gradle学习记录6 代码记录(持续补充)
- Android Gradle学习记录5 Gradle补充说明
- Android学习笔记(持续记录)
- Android Gradle学习记录1 基本特点
- Android 学习记录(持续更新)
- android学习总结(持续记录点点滴滴)
- gradle学习记录
- Gradle学习记录
- 记录Gradle学习
- gradle学习记录
- Gradle学习记录
- Gradle学习记录
- gradle 学习记录
- 【备份】持续学习记录
- 持续集成学习记录
- Android Gradle学习记录4 Gradle概念及工作流程
- Android Gradle学习记录4 Gradle概念及工作流程
- AndroidStudio、Gradle 问题记录(记录解决方案,持续更新)
- LeetCode——Hamming Distance
- 设计模式之适配器模式(Adapter):类适配器、对象适配器
- Java 通过JDBC进行数据操作(增删改查)
- 魔漫相机面试心得
- 物理层——计算机网络原理(三)
- Android Gradle学习记录6 代码记录(持续补充)
- XRecycleView的下拉,多条目加载
- 数据库优化
- 网络共享服务FTP
- TinySpring学习(Step1)
- ftp /etc/vsftpd.conf 配置
- 项目的版本介绍
- Unsupported major.minor version 51.0和52.0错误解决
- ASCII GBK Unicode UTF-8 区别和关系 编码关系