├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── channel ├── channel_debug ├── config.json ├── key ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── meituan │ │ └── android │ │ └── walle │ │ └── sample │ │ ├── MainActivity.java │ │ └── MyApplication.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── config └── style │ └── checkstyle.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── build.gradle ├── gradle.properties └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── meituan │ └── android │ └── walle │ └── WalleChannelReader.java ├── maven-publish.gradle ├── maven-publish_libary.gradle ├── payload_reader ├── .gitignore ├── README.md ├── build.gradle ├── config │ └── checkstyle │ │ └── checkstyle.xml ├── gradle.properties └── src │ └── main │ └── java │ └── com │ └── meituan │ └── android │ └── walle │ ├── ApkUtil.java │ ├── ChannelInfo.java │ ├── ChannelReader.java │ ├── Pair.java │ ├── PayloadReader.java │ └── SignatureNotFoundException.java ├── payload_writer ├── .gitignore ├── README.md ├── build.gradle ├── config │ └── checkstyle │ │ └── checkstyle.xml ├── gradle.properties └── src │ └── main │ └── java │ └── com │ └── meituan │ └── android │ └── walle │ ├── ApkSigningBlock.java │ ├── ApkSigningPayload.java │ ├── ChannelWriter.java │ └── PayloadWriter.java ├── plugin ├── build.gradle ├── gradle.properties └── src │ └── main │ ├── groovy │ └── com │ │ └── meituan │ │ └── android │ │ └── walle │ │ ├── ChannelMaker.groovy │ │ ├── Extension.groovy │ │ └── GradlePlugin.groovy │ └── java │ └── com │ ├── android │ ├── apksigner │ │ └── core │ │ │ ├── ApkSignerEngine.java │ │ │ ├── ApkVerifier.java │ │ │ ├── DefaultApkSignerEngine.java │ │ │ ├── apk │ │ │ └── ApkUtils.java │ │ │ ├── internal │ │ │ ├── apk │ │ │ │ ├── v1 │ │ │ │ │ ├── DigestAlgorithm.java │ │ │ │ │ └── V1SchemeSigner.java │ │ │ │ └── v2 │ │ │ │ │ ├── ContentDigestAlgorithm.java │ │ │ │ │ ├── SignatureAlgorithm.java │ │ │ │ │ ├── V2SchemeSigner.java │ │ │ │ │ └── V2SchemeVerifier.java │ │ │ ├── jar │ │ │ │ ├── ManifestWriter.java │ │ │ │ └── SignatureFileWriter.java │ │ │ ├── util │ │ │ │ ├── ByteArrayOutputStreamSink.java │ │ │ │ ├── ByteBufferDataSource.java │ │ │ │ ├── ByteBufferSink.java │ │ │ │ ├── DelegatingX509Certificate.java │ │ │ │ ├── MessageDigestSink.java │ │ │ │ └── Pair.java │ │ │ └── zip │ │ │ │ └── ZipUtils.java │ │ │ ├── util │ │ │ ├── DataSink.java │ │ │ ├── DataSource.java │ │ │ └── DataSources.java │ │ │ └── zip │ │ │ └── ZipFormatException.java │ └── signapk │ │ └── SignApk.java │ └── meituan │ └── android │ └── walle │ └── WalleConfig.java ├── publish.sh ├── quality.gradle ├── settings.gradle └── walle-cli ├── README.md ├── build.gradle ├── config └── checkstyle │ └── checkstyle.xml └── src └── main └── java └── com └── meituan └── android └── walle ├── Main.java ├── WalleCommandLine.java ├── WalleConfig.java ├── commands ├── Batch2Command.java ├── BatchCommand.java ├── IWalleCommand.java ├── PutCommand.java ├── RemoveCommand.java └── ShowCommand.java └── utils ├── CommaSeparatedKeyValueConverter.java ├── Fun1.java └── Util.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | *.class 4 | 5 | # Mobile Tools for Java (J2ME) 6 | .mtj.tmp/ 7 | 8 | # Package Files # 9 | *.jar 10 | *.war 11 | *.ear 12 | 13 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 14 | hs_err_pid* 15 | ### Gradle template 16 | .gradle 17 | build/ 18 | 19 | # Ignore Gradle GUI config 20 | gradle-app.setting 21 | 22 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 23 | !gradle-wrapper.jar 24 | 25 | # Cache of project 26 | .gradletasknamecache 27 | 28 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 29 | # gradle/wrapper/gradle-wrapper.properties 30 | ### Android template 31 | # Built application files 32 | *.apk 33 | *.ap_ 34 | 35 | # Files for the ART/Dalvik VM 36 | *.dex 37 | 38 | # Java class files 39 | *.class 40 | 41 | # Generated files 42 | bin/ 43 | gen/ 44 | out/ 45 | 46 | # Gradle files 47 | .gradle/ 48 | build/ 49 | 50 | # Local configuration file (sdk path, etc) 51 | local.properties 52 | 53 | # Proguard folder generated by Eclipse 54 | proguard/ 55 | 56 | # Log Files 57 | *.log 58 | 59 | # Android Studio Navigation editor temp files 60 | .navigation/ 61 | 62 | # Android Studio captures folder 63 | captures/ 64 | 65 | # Intellij 66 | *.iml 67 | .idea/workspace.xml 68 | .idea 69 | 70 | # Keystore files 71 | *.jks 72 | 73 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Walle 2 | [![](https://jitpack.io/v/Petterpx/walle.svg)](https://jitpack.io/#Petterpx/walle) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Meituan-Dianping/walle/pulls) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://raw.githubusercontent.com/Meituan-Dianping/walle/master/LICENSE) 3 | 4 | ## 说明 5 | 6 | 源自 [美团 Walle](https://github.com/Meituan-Dianping/walle) ,因官方已许久未更新(近两年,上一次是2020.12),插件内部不少api都已过时或者需要更改逻辑,特fork这个库作为一个临时适配,并迁移到了jitpack。 7 | 8 | - 已适配到了 Agp7.0.4 ,理论上 7.x 都可以。 9 | 10 | 如有问题,提 issus 即可,看到后就会帮忙解决,如果可以的话。 11 | 12 | > 后续如果官方正常更新,那么正常迁移到官方即可,并不影响。 13 | > 14 | > 下面文档copy自walle,依赖方式部分已更新。 15 | 16 | ## Walle 17 | 18 | Walle(瓦力):Android Signature V2 Scheme签名下的新一代渠道包打包神器 19 | 20 | 瓦力通过在Apk中的`APK Signature Block`区块添加自定义的渠道信息来生成渠道包,从而提高了渠道包生成效率,可以作为单机工具来使用,也可以部署在HTTP服务器上来实时处理渠道包Apk的升级网络请求。 21 | 22 | ## 23 | 24 | ## Quick Start 25 | 26 | 为了方便大家的使用,我们提供了2种使用方式: 27 | 28 | * Gradle插件方式,方便快速集成 29 | * 命令行方式,最大化满足各种自定义需求 30 | 31 | ## Gradle插件使用方式 32 | **build.gradle** 33 | 34 | ```groovy 35 | allprojects { 36 | repositories { 37 | // ... 38 | maven { url 'https://jitpack.io' } 39 | } 40 | } 41 | buildscript { 42 | dependencies { 43 | classpath 'com.github.Petterpx.walle:plugin:1.0.5' 44 | } 45 | } 46 | ``` 47 | 48 | 并在当前App的 `build.gradle` 文件中apply这个插件,并添加上用于读取渠道号的AAR 49 | 50 | ```groovy 51 | apply plugin: 'walle' 52 | 53 | dependencies { 54 | implementation 'com.github.Petterpx.walle:library:1.0.5' 55 | } 56 | ``` 57 | 58 | #### 配置插件 59 | 60 | ```groovy 61 | walle { 62 | // 指定渠道包的输出路径 63 | apkOutputFolder = new File("${project.buildDir}/outputs/channels"); 64 | // 定制渠道包的APK的文件名称 65 | apkFileNameFormat = '${appName}-${packageName}-${channel}-${buildType}-v${versionName}-${versionCode}-${buildTime}.apk'; 66 | // 渠道配置文件 67 | channelFile = new File("${project.getProjectDir()}/channel") 68 | } 69 | ``` 70 | 71 | 配置项具体解释: 72 | 73 | * apkOutputFolder:指定渠道包的输出路径, 默认值为`new File("${project.buildDir}/outputs/apk")` 74 | * apkFileNameFormat:定制渠道包的APK的文件名称, 默认值为`'${appName}-${buildType}-${channel}.apk'` 75 | 可使用以下变量: 76 | 77 | ``` 78 | projectName - 项目名字 79 | appName - App模块名字 80 | packageName - applicationId (App包名packageName) 81 | buildType - buildType (release/debug等) 82 | channel - channel名称 (对应渠道打包中的渠道名字) 83 | versionName - versionName (显示用的版本号) 84 | versionCode - versionCode (内部版本号) 85 | buildTime - buildTime (编译构建日期时间) 86 | fileSHA1 - fileSHA1 (最终APK文件的SHA1哈希值) 87 | flavorName - 编译构建 productFlavors 名 88 | ``` 89 | * channelFile:包含渠道配置信息的文件路径。 具体内容格式详见:[渠道配置文件示例](app/channel),支持使用#号添加注释。 90 | 91 | #### 如何获取渠道信息 92 | 93 | 在需要渠道等信息时可以通过下面代码进行获取 94 | 95 | ```java 96 | String channel = WalleChannelReader.getChannel(this.getApplicationContext()); 97 | ``` 98 | 99 | #### 如何生成渠道包 100 | 101 | 生成渠道包的方式是和`assemble${variantName}Channels`指令结合,渠道包的生成目录默认存放在 `build/outputs/apk/`,也可以通过`walle`闭包中的`apkOutputFolder`参数来指定输出目录 102 | 103 | 用法示例: 104 | 105 | * 生成渠道包 `./gradlew clean assembleReleaseChannels` 106 | * 支持 productFlavors `./gradlew clean assembleMeituanReleaseChannels` 107 | 108 | #### 更多用法 109 | 110 | ##### 插入额外信息 111 | 112 | `channelFile`只支持渠道写入,如果想插入除渠道以外的其他信息,请在walle配置中使用`configFile` 113 | 114 | ``` 115 | walle { 116 | // 渠道&额外信息配置文件,与channelFile互斥 117 | configFile = new File("${project.getProjectDir()}/config.json") 118 | } 119 | ``` 120 | 121 | `configFile`是包含渠道信息和额外信息的配置文件路径。 122 | 配置文件采用json格式,支持为每个channel单独配置额外的写入信息。具体内容格式详见:[渠道&额外信息配置文件示例](app/config.json) 。 123 | 124 | 注意: 125 | 126 | - 此配置项与`channelFile`功能互斥,开发者在使用时选择其一即可,两者都存在时`configFile`优先执行。 127 | - extraInfo 不要出现以`channel`为key的情况 128 | 129 | 而对应的渠道信息获取方式如下: 130 | 131 | ```java 132 | ChannelInfo channelInfo= WalleChannelReader.getChannelInfo(this.getApplicationContext()); 133 | if (channelInfo != null) { 134 | String channel = channelInfo.getChannel(); 135 | Map extraInfo = channelInfo.getExtraInfo(); 136 | } 137 | // 或者也可以直接根据key获取 138 | String value = WalleChannelReader.get(context, "buildtime"); 139 | ``` 140 | 141 | ##### 临时生成某渠道包 142 | 143 | 我们推荐使用channelFile/configFile配置来生成渠道包,但有时也可能有临时生成渠道包需求,这时可以使用: 144 | 145 | - 生成单个渠道包: `./gradlew clean assembleReleaseChannels -PchannelList=meituan` 146 | - 生成多个渠道包: `./gradlew clean assembleReleaseChannels -PchannelList=meituan,dianping` 147 | - 生成渠道包&写入额外信息: 148 | 149 | `./gradlew clean assembleReleaseChannels -PchannelList=meituan -PextraInfo=buildtime:20161212,hash:xxxxxxx` 150 | 151 | 注意: 这里的extraInfo以`key:value`形式提供,多个以`,`分隔。 152 | - 使用临时channelFile生成渠道包: `./gradlew clean assembleReleaseChannels -PchannelFile=/Users/xx/Documents/channel` 153 | - 使用临时configFile生成渠道包: `./gradlew clean assembleReleaseChannels -PconfigFile=/Users/xx/Documents/config.json` 154 | 155 | 使用上述-P参数后,本次打包channelFile/configFile配置将会失效,其他配置仍然有效。 156 | `-PchannelList`,`-PchannelFile`, `-PconfigFile`三者不可同时使用。 157 | 158 | ### 命令行工具使用方式 159 | 160 | 可以使用命令行工具来支持各类自定义的需求,具体使用方式详见:[Walle CLI 使用说明](walle-cli/README.md) 161 | 162 | ### 其他使用方式 163 | 164 | 为了更好的满足大家的各类自定义需求,我们把对`APK Signing Block`区块进行读写操作的模块进行了封装。 165 | 166 | 读写模块的使用说明详见: 167 | 168 | * [APK Signing Block读取模块: payload_reader](payload_reader/README.md) 169 | * [APK Signing Block写入模块: payload_writer](payload_writer/README.md) 170 | 171 | ## Q&A 172 | - [360加固失效](https://github.com/Meituan-Dianping/walle/wiki/360%E5%8A%A0%E5%9B%BA%E5%A4%B1%E6%95%88%EF%BC%9F)? 173 | 174 | ## 原理介绍 175 | 176 | 对该工具的原理感兴趣的同学,可以移步[美团Android新一代渠道包生成工具](http://tech.meituan.com/2017/01/13/android-apk-v2-signature-scheme.html)进行了解。 177 | 178 | ## 注意事项 179 | 180 | * 使用apksigner重新对Apk签名会导致渠道信息丢失,需要再次写入渠道信息 181 | * walle支持对含有comment的apk进行渠道写入, 详见[issue 52](https://github.com/Meituan-Dianping/walle/issues/52) 182 | 183 | ## 技术支持 184 | 185 | * Read The Fucking Source Code 186 | * 通过提交issue来寻求帮助 187 | * 联系我们寻求帮助 188 | 189 | ## 贡献代码 190 | * 欢迎提交issue 191 | * 欢迎提交PR 192 | 193 | ## 参考 194 | * [APK Signature Scheme v2](https://source.android.com/security/apksigning/v2.html) 195 | * [Zip Format](https://en.wikipedia.org/wiki/Zip_(file_format)) 196 | * [Android Source Code: ApkSigner](https://android.googlesource.com/platform/build/+/8740e9d) 197 | * [Android Source Code: apksig](https://android.googlesource.com/platform/tools/apksig/) 198 | 199 | ## License 200 | 201 | ``` 202 | Copyright 2017 Meituan-Dianping 203 | 204 | Licensed under the Apache License, Version 2.0 (the "License"); 205 | you may not use this file except in compliance with the License. 206 | You may obtain a copy of the License at 207 | 208 | http://www.apache.org/licenses/LICENSE-2.0 209 | 210 | Unless required by applicable law or agreed to in writing, software 211 | distributed under the License is distributed on an "AS IS" BASIS, 212 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 213 | See the License for the specific language governing permissions and 214 | limitations under the License. 215 | ``` 216 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | 3 | /version.properties 4 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'walle' 3 | apply from: rootProject.file('quality.gradle') 4 | 5 | 6 | buildscript { 7 | repositories { 8 | google() 9 | mavenCentral() 10 | maven { url 'https://jitpack.io' } 11 | maven { url "https://maven.aliyun.com/repository/public" } 12 | } 13 | dependencies { 14 | classpath 'com.android.tools.build:gradle:7.0.2' 15 | classpath "com.github.Petterpx.walle:plugin:1.0.3" 16 | } 17 | } 18 | 19 | android { 20 | 21 | compileSdkVersion rootProject.ext.compileSdkVersion 22 | buildToolsVersion rootProject.ext.buildToolsVersion 23 | 24 | defaultConfig { 25 | minSdkVersion rootProject.ext.minSdkVersion 26 | targetSdkVersion rootProject.ext.targetSdkVersion 27 | 28 | versionCode 101 29 | versionName "1.0.1" 30 | applicationId "com.meituan.android.key.sample" 31 | } 32 | 33 | splits { 34 | abi { 35 | enable true 36 | reset() 37 | include 'armeabi', 'x86' 38 | universalApk false 39 | } 40 | } 41 | 42 | signingConfigs { 43 | config { 44 | storeFile file("key") 45 | storePassword "12345678" 46 | keyAlias "walle" 47 | keyPassword "12345678" 48 | } 49 | } 50 | 51 | buildTypes { 52 | release { 53 | minifyEnabled true 54 | shrinkResources true 55 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 56 | signingConfig signingConfigs.config 57 | } 58 | 59 | debug { 60 | minifyEnabled false 61 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 62 | signingConfig signingConfigs.config 63 | applicationIdSuffix 'debug' 64 | } 65 | } 66 | 67 | compileOptions { 68 | sourceCompatibility JavaVersion.VERSION_1_7 69 | targetCompatibility JavaVersion.VERSION_1_7 70 | } 71 | 72 | // productFlavors { 73 | // china { 74 | // } 75 | // international { 76 | // } 77 | // } 78 | } 79 | 80 | configurations.all { 81 | resolutionStrategy.cacheChangingModulesFor 0, 'seconds' 82 | } 83 | 84 | dependencies { 85 | implementation fileTree(dir: 'libs', include: ['*.jar']) 86 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 87 | implementation 'androidx.appcompat:appcompat:1.0.0' 88 | implementation "com.github.Petterpx.walle:library:1.0.3" 89 | } 90 | 91 | walle { 92 | apkOutputFolder = new File("${project.buildDir}/outputs/channels") 93 | apkFileNameFormat = '${appName}-${packageName}-${channel}-${buildType}-v${versionName}-${versionCode}-${buildTime}-${flavorName}.apk' 94 | //configFile与channelFile两者必须存在一个,否则无法生成渠道包。两者都存在时优先执行configFile 95 | channelFile = new File("${project.getProjectDir()}/channel") 96 | //configFile = new File("${project.getProjectDir()}/config.json") 97 | } 98 | 99 | 100 | -------------------------------------------------------------------------------- /app/channel: -------------------------------------------------------------------------------- 1 | meituan # 美团 2 | samsungapps #三星 3 | hiapk 4 | anzhi 5 | xiaomi # 小米 6 | 91com 7 | gfan 8 | appchina 9 | nduoa 10 | 3gcn 11 | mumayi 12 | 10086com 13 | wostore 14 | 189store 15 | lenovomm 16 | hicloud 17 | meizu 18 | wandou 19 | # Google Play 20 | # googleplay 21 | # 百度 22 | baidu 23 | # 24 | # 360 25 | 360cn 26 | # 27 | # 应用宝 28 | myapp -------------------------------------------------------------------------------- /app/channel_debug: -------------------------------------------------------------------------------- 1 | meituan # 美团 2 | samsungapps #三星 -------------------------------------------------------------------------------- /app/config.json: -------------------------------------------------------------------------------- 1 | { 2 | //extraInfo 不要出现以`channel`为key的情况 3 | /* 4 | 不声明extraInfo的channel默认使用的extraInfo 5 | 如果没有此项则没有默认extraInfo 6 | */ 7 | "defaultExtraInfo": { 8 | "key2": "20161213", 9 | "key": "20161212" 10 | }, 11 | 12 | /* 13 | strategy: 14 | 1. ifNone (默认适用此策略) : 仅当对应channel没有extraInfo时生效 15 | 2. always : 所有channel都生效,channel中extraInfo的key与defaultExtraInfo重复时,覆盖defaultExtraInfo中的内容。 16 | */ 17 | 18 | //"defaultExtraInfoStrategy": "always", 19 | 20 | "channelInfoList": [ 21 | { 22 | "channel": "meituan", 23 | // 此channel将使用自己声明的extraInfo 24 | /* 25 | 此alias可以做到写入apk的channel是meituan,而打包时输出的文件名是美团 26 | 注意:alias不声明时,walle配置apkFileNameFormat中channel就是channel,否则为alias 27 | */ 28 | "alias": "美团", 29 | "extraInfo": { 30 | "buildtime": "20161212", 31 | "hash": "123" 32 | } 33 | }, 34 | { 35 | "channel": "360cn", 36 | // 此channel将使用自己声明的extraInfo 37 | "extraInfo": { 38 | "key": "20161213" 39 | } 40 | }, 41 | { 42 | "channel": "googleplay" 43 | // 此channel将使用defaultExtraInfo 44 | }, 45 | { 46 | "channel": "xiaomi" 47 | // 此channel将使用defaultExtraInfo 48 | }, 49 | { 50 | "channel": "meizu" 51 | // 此channel将使用defaultExtraInfo 52 | }, 53 | { 54 | "channel": "wandoujia", 55 | "excludeDefaultExtraInfo": true 56 | //强制声明不使用defaultExtraInfo,默认false 57 | }, 58 | { 59 | "channel": "myapp", 60 | "excludeDefaultExtraInfo": true, 61 | //强制声明不使用defaultExtraInfo,默认false 62 | "extraInfo": { 63 | // 尽管exclude default,但也可以继续写入自己的。 64 | "key": "20161212" 65 | } 66 | } 67 | ] 68 | } -------------------------------------------------------------------------------- /app/key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Petterpx/walle/176543daa2f52e1ec8fd714b7beb22dda8c1bb77/app/key -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/zhangshaowen/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -keepattributes SourceFile,LineNumberTable 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/meituan/android/walle/sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.meituan.android.walle.sample; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.appcompat.app.AppCompatActivity; 6 | 7 | import android.view.View; 8 | import android.widget.TextView; 9 | import android.widget.Toast; 10 | 11 | //import com.meituan.android.walle.ChannelInfo; 12 | import com.meituan.android.walle.WalleChannelReader; 13 | 14 | 15 | public class MainActivity extends AppCompatActivity { 16 | @Override 17 | protected void onCreate(final Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | 21 | findViewById(R.id.read_channel).setOnClickListener(new View.OnClickListener() { 22 | @Override 23 | public void onClick(final View v) { 24 | readChannel(); 25 | } 26 | }); 27 | 28 | } 29 | 30 | private void readChannel() { 31 | final TextView tv = (TextView) findViewById(R.id.tv_channel); 32 | final long startTime = System.currentTimeMillis(); 33 | com.meituan.android.walle.ChannelInfo channelInfo = WalleChannelReader.getChannelInfo(this.getApplicationContext()); 34 | if (channelInfo != null) { 35 | tv.setText(channelInfo.getChannel() + "\n" + channelInfo.getExtraInfo()); 36 | } 37 | Toast.makeText(this, "ChannelReader takes " + (System.currentTimeMillis() - startTime) + " milliseconds", Toast.LENGTH_SHORT).show(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/meituan/android/walle/sample/MyApplication.java: -------------------------------------------------------------------------------- 1 | 2 | package com.meituan.android.walle.sample; 3 | 4 | import android.app.Application; 5 | 6 | public class MyApplication extends Application { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 |