打包流程
具体实现
Gradle配置文件归类
分类需要同步和不需要同步的配置文件,解决多分支模型下切换分支更改版本号等不需要同步的操作,gralde仍提示同步的问题,让真正需要同步的变更才提示。
新建version.gradle文件,添加变更时不需要同步的参数;
123456789101112131415161718192021ext {// 打生产包命令:./gradlew assembleReleaseChannels// 打patch包命令:./gradlew buildTinkerPatchRelease// 当前编译状态,生产环境必须配置为falseisDebug=true// 标识是否为补丁模式isPatchModel=false// 是否上传符号表uploadMappingEnable=false// 补丁模式,补丁文件对应的基准apk文件夹patchBaseApkDir=""version_name="1.1.0.100"// 规则,年+月+日+当日发版次数version_code=17041501}
将version.gradle添加到项目根目录build.gradle顶部;
1apply from: 'version.gradle'
将变更时必须同步的参数统一添加到gradle.properties;
12345678910111213141516171819202122232425262728293031323334353637383940414243444546# =====================================以下为第三方账号配置=====================================// debugDEBUG_BUGLY_APPID="xxx"DEBUG_TALKINGDATA_APPID="xxx"DEBUG_MEIQIA_APPID="xxx"// releaseRELEASE_BUGLY_APPID="xxx"RELEASE_TALKINGDATA_APPID="xxx"RELEASE_MEIQIA_APPID="xxx"# =====================================以下为多dex配置=====================================MULTIDEX_KEEP_PROGUARD_FILE=multiDexKeep.proMULTIDEX_ENABLED=true# =====================================以下为签名配置=====================================SIGNING_STORE_FILE=xxx.keystore.jksSIGNING_STORE_PASSWORD=xxxSIGNING_KEY_ALIAS=xxxSIGNING_KEY_PASSWORD=xxx# =====================================以下为应用配置=====================================APPLICATION_ID=xxx# Sdk and toolsMIN_SDK_VERSION=16TARGET_SDK_VERSION=22COMPILE_SDK_VERSION=23BUILD_TOOLS_VERSION=25.0.0MULTIDEX_VERSION=1.0.0# =====================================以下为依赖配置=====================================# App dependencies# https://developer.android.com/topic/libraries/support-library/features.htmlsupportLibraryVersion=25.0.1guavaVersion=18.0junitVersion=4.12mockitoVersion=1.10.19powerMockito=1.6.2hamcrestVersion=1.3runnerVersion=0.4.1rulesVersion=0.4.1
检查multidex配置
Application启动时调用的类必须包含在主dex中,为此我们需要配置哪些类在主dex中。随着版本迭代或代码重构,可能导致配置的类包名发生改变或有新的类在Application中调用,为防止错误或遗漏,可在编译期引入自动检查机制,避免出错。
插件实现
|
|
插件使用
|
|
多渠道打包
使用walle作为多渠道打包方案,比AndroidStudio提供的productFlavors方案性能更高,使用更方便,同时提供命令行工具方便临时增加渠道包。
|
|
调整打包输出目录
项目中使用了bugly热修复和walle多渠道打包,打包输出的文件散落在各处,每次都需要手动归类备份;同时打正式包和Patch包需要备份的文件也不一样,比较繁琐容易出错。
插件实现
对外提供的配置类AdjustAssembleOutputConfig
1234567891011121314class AdjustAssembleOutputConfig {String outputBakPath = nullString outputBakDirName = nullboolean isPatchModelValuepublic String toString() {return "AdjustAssembleOutputConfig{" +"outputBakPath='" + outputBakPath + '\'' +", outputBakDirName='" + outputBakDirName + '\'' +", isPatchModelValue=" + isPatchModelValue +'}';}}插件实现类AdjustAssembleOutputPlugin,分别针对打正式包和Patch包不同备份需求单独处理;
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200public class AdjustAssembleOutputPlugin implements Plugin<Project> {void apply(Project project) {println("===================================================================");println("开始执行AdjustAssembleOutputPlugin,project.name:" + project.name);println("===================================================================");// 创建需要外部传入的配置文件project.extensions.create("adjustAssembleOutputConfig", AdjustAssembleOutputConfig)// 获取最后编译完成的variantdef targetVariant = nullproject.android.applicationVariants.all { variant ->def taskName = variant.nameproject.tasks.all {if ("assemble${taskName.capitalize()}".equalsIgnoreCase(it.name)) {it.doLast {targetVariant = variantprintln("${it.name} doLast=========================>")}}}}// build完成监听project.gradle.addListener(new BuildListener(){void buildStarted(Gradle gradle) {}void settingsEvaluated(Settings settings) {}void projectsLoaded(Gradle gradle) {}void projectsEvaluated(Gradle gradle) {println("projectsEvaluated==========>")}void buildFinished(BuildResult result) {def buildSuccess = result.getFailure() == nullprintln("buildFinished==========>" + buildSuccess)if (!buildSuccess.toBoolean()){return}AdjustAssembleOutputConfig config = project['adjustAssembleOutputConfig']def outputBakPath = config.outputBakPathdef outputBakDirName = config.outputBakDirNamedef isPatchModelValue = config.isPatchModelValueprintln("isPatchModelValue======================="+isPatchModelValue)println("outputBakPath======================="+outputBakPath)println("outputBakDirName======================="+outputBakDirName)if (isPatchModelValue){// 打补丁包模式adjustOutputForPatch(project, outputBakDirName, outputBakPath)deletePatchNewOfficialFile(project, outputBakDirName, outputBakPath)}else{adjustOutputForOfficial(project, outputBakDirName, outputBakPath, targetVariant.baseName)}}})}/*** 删除打patch包时,生成的新的正式包文件* @param project* @param outputBakDirName* @param outputBakPath* @return*/def deletePatchNewOfficialFile(Project project, outputBakDirName, outputBakPath){def newOfficialDir = findBuglyOutputFile(project, outputBakDirName, outputBakPath)if (newOfficialDir.exists()){println("delete newOfficialDir==========>" + newOfficialDir)newOfficialDir.deleteDir()}else{throw new RuntimeException("打patch包时,生成的新的正式包文件夹不存在:" + newOfficialDir)}}/*** 为patch包整理文件输出目录* @param project* @param outputBakDirName* @param outputBakPath* @return*/def adjustOutputForPatch(Project project, outputBakDirName, outputBakPath){def patchFile = project.file("${project.rootDir}/${project.name}/build/outputs/patch/release/patch_signed_7zip.apk")if (patchFile.exists()){// 目标文件目录def toFileDir = new File("${outputBakPath}", outputBakDirName)println("toFileDir==========>" + toFileDir)// 拷贝补丁文件到备份目录project.copy {from patchFileinto toFileDir}// 压缩outputs文件夹并备份def patchOutputFile = project.file("${project.rootDir}/${project.name}/build/outputs")println("patchOutputFile==========>" + patchOutputFile)if (patchOutputFile.exists()){FileUtils.compressedFile(patchOutputFile.getAbsolutePath(), toFileDir.getAbsolutePath())}else{throw new RuntimeException("补丁outputs文件夹不存在:" + patchOutputFile)}}else{throw new RuntimeException("补丁文件不存在:" + bakPath)}}/*** 为正式包整理文件输出目录* @param outputBakDirName 备份文件夹名* @param outputBakPath 备份目录* @param buildType 当前编译模式类型 release/debug* @return*/def adjustOutputForOfficial(Project project, outputBakDirName, outputBakPath, buildType){// 定义输入文件名def fromApkName = outputBakDirName + ".apk"def fromRName = outputBakDirName + "-R.txt"def fromMappingName = outputBakDirName + "-mapping.txt"def fromFileDir = findBuglyOutputFile(project, outputBakDirName, outputBakPath)println("fromFileDir==========>" + fromFileDir)// 目标文件目录def toFileDir = new File("${outputBakPath}", outputBakDirName)println("toFileDir==========>" + toFileDir)// 定义输出文件名def toFileNamePrefix = "${project.name}-${buildType}"def toApkName = toFileNamePrefix + ".apk"def toApkFile = new File(toFileDir, toApkName)def toRName = toFileNamePrefix + "-R.txt"def toMappingName = toFileNamePrefix + "-mapping.txt"// 拷贝源文件目录下所有资源到目标文件目录,并重命名project.copy {// 拷贝目录下所有文件from fromFileDirinto toFileDirrename { String fileName ->fileName.replace(fromApkName, toApkName)}rename { String fileName ->fileName.replace(fromRName, toRName)}rename { String fileName ->fileName.replace(fromMappingName, toMappingName)}}// 删除源文件目录if (toApkFile.exists()){def deleteSuccess = project.file("${fromFileDir}").deleteDir()println("delete fromFileDir==========>" + deleteSuccess)}}/*** 查找bugly tinker打包输出的文件夹* @param project* @param outputBakDirName* @param outputBakPath* @return*/def findBuglyOutputFile(Project project, outputBakDirName, outputBakPath){def fromApkName = outputBakDirName + ".apk"// 查找目标apk文件夹def tree = project.fileTree(outputBakPath) {include "**/${fromApkName}"}// 校验查找到的文件夹合法性if (tree.size() == 0){throw new RuntimeException("没有找到APK文件:" + fromApkName)}if (tree.size() > 1){throw new RuntimeException("存在多个APK文件:" + tree.toString())}// 源文件目录def fromFileDir = tree[0].getParentFile()return fromFileDir}}
插件使用
在application类型模块下build.gradle中添加以下配置;
1234567this.printlnLog("调整打包输出目录插件")apply plugin: com.zaozuo.plugins.adjustoutput.AdjustAssembleOutputPluginadjustAssembleOutputConfig{outputBakPath "${project.bakPath}"outputBakDirName "${project.tinkerIdValue}"isPatchModelValue "${project.isPatchModel}".toBoolean()}使用插件后,每次打包后输出的目录及文件;
检查生成的APK
检查渠道配置
come soon!
检查tinker配置
come soon!