├── JavaUtil └── ChannelUtil.java ├── LICENSE ├── PythonTool ├── MultiChannelBuildTool.py └── info │ ├── channel.txt │ └── czt.txt └── README.md /JavaUtil/ChannelUtil.java: -------------------------------------------------------------------------------- 1 | package com.czt.util; 2 | 3 | import java.io.IOException; 4 | import java.util.Enumeration; 5 | import java.util.zip.ZipEntry; 6 | import java.util.zip.ZipFile; 7 | 8 | import android.content.Context; 9 | import android.content.SharedPreferences; 10 | import android.content.SharedPreferences.Editor; 11 | import android.content.pm.ApplicationInfo; 12 | import android.content.pm.PackageManager.NameNotFoundException; 13 | import android.preference.PreferenceManager; 14 | import android.text.TextUtils; 15 | 16 | public class ChannelUtil { 17 | 18 | private static final String CHANNEL_KEY = "cztchannel"; 19 | private static final String CHANNEL_VERSION_KEY = "cztchannel_version"; 20 | private static String mChannel; 21 | /** 22 | * 返回市场。 如果获取失败返回"" 23 | * @param context 24 | * @return 25 | */ 26 | public static String getChannel(Context context){ 27 | return getChannel(context, ""); 28 | } 29 | /** 30 | * 返回市场。 如果获取失败返回defaultChannel 31 | * @param context 32 | * @param defaultChannel 33 | * @return 34 | */ 35 | public static String getChannel(Context context, String defaultChannel) { 36 | //内存中获取 37 | if(!TextUtils.isEmpty(mChannel)){ 38 | return mChannel; 39 | } 40 | //sp中获取 41 | mChannel = getChannelBySharedPreferences(context); 42 | if(!TextUtils.isEmpty(mChannel)){ 43 | return mChannel; 44 | } 45 | //从apk中获取 46 | mChannel = getChannelFromApk(context, CHANNEL_KEY); 47 | if(!TextUtils.isEmpty(mChannel)){ 48 | //保存sp中备用 49 | saveChannelBySharedPreferences(context, mChannel); 50 | return mChannel; 51 | } 52 | //全部获取失败 53 | return defaultChannel; 54 | } 55 | /** 56 | * 从apk中获取版本信息 57 | * @param context 58 | * @param channelKey 59 | * @return 60 | */ 61 | private static String getChannelFromApk(Context context, String channelKey) { 62 | //从apk包中获取 63 | ApplicationInfo appinfo = context.getApplicationInfo(); 64 | String sourceDir = appinfo.sourceDir; 65 | //默认放在meta-inf/里, 所以需要再拼接一下 66 | String key = "META-INF/" + channelKey; 67 | String ret = ""; 68 | ZipFile zipfile = null; 69 | try { 70 | zipfile = new ZipFile(sourceDir); 71 | Enumeration entries = zipfile.entries(); 72 | while (entries.hasMoreElements()) { 73 | ZipEntry entry = ((ZipEntry) entries.nextElement()); 74 | String entryName = entry.getName(); 75 | if (entryName.startsWith(key)) { 76 | ret = entryName; 77 | break; 78 | } 79 | } 80 | } catch (IOException e) { 81 | e.printStackTrace(); 82 | } finally { 83 | if (zipfile != null) { 84 | try { 85 | zipfile.close(); 86 | } catch (IOException e) { 87 | e.printStackTrace(); 88 | } 89 | } 90 | } 91 | String[] split = ret.split("_"); 92 | String channel = ""; 93 | if (split != null && split.length >= 2) { 94 | channel = ret.substring(split[0].length() + 1); 95 | } 96 | return channel; 97 | } 98 | /** 99 | * 本地保存channel & 对应版本号 100 | * @param context 101 | * @param channel 102 | */ 103 | private static void saveChannelBySharedPreferences(Context context, String channel){ 104 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); 105 | Editor editor = sp.edit(); 106 | editor.putString(CHANNEL_KEY, channel); 107 | editor.putInt(CHANNEL_VERSION_KEY, getVersionCode(context)); 108 | editor.commit(); 109 | } 110 | /** 111 | * 从sp中获取channel 112 | * @param context 113 | * @return 为空表示获取异常、sp中的值已经失效、sp中没有此值 114 | */ 115 | private static String getChannelBySharedPreferences(Context context){ 116 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); 117 | int currentVersionCode = getVersionCode(context); 118 | if(currentVersionCode == -1){ 119 | //获取错误 120 | return ""; 121 | } 122 | int versionCodeSaved = sp.getInt(CHANNEL_VERSION_KEY, -1); 123 | if(versionCodeSaved == -1){ 124 | //本地没有存储的channel对应的版本号 125 | //第一次使用 或者 原先存储版本号异常 126 | return ""; 127 | } 128 | if(currentVersionCode != versionCodeSaved){ 129 | return ""; 130 | } 131 | return sp.getString(CHANNEL_KEY, ""); 132 | } 133 | /** 134 | * 从包信息中获取版本号 135 | * @param context 136 | * @return 137 | */ 138 | private static int getVersionCode(Context context){ 139 | try{ 140 | return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode; 141 | }catch(NameNotFoundException e) { 142 | e.printStackTrace(); 143 | } 144 | return -1; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /PythonTool/MultiChannelBuildTool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding=utf-8 3 | import zipfile 4 | import shutil 5 | import os 6 | 7 | # 空文件 便于写入此空文件到apk包中作为channel文件 8 | src_empty_file = 'info/czt.txt' 9 | # 创建一个空文件(不存在则创建) 10 | f = open(src_empty_file, 'w') 11 | f.close() 12 | 13 | # 获取当前目录中所有的apk源包 14 | src_apks = [] 15 | # python3 : os.listdir()即可,这里使用兼容Python2的os.listdir('.') 16 | for file in os.listdir('.'): 17 | if os.path.isfile(file): 18 | extension = os.path.splitext(file)[1][1:] 19 | if extension in 'apk': 20 | src_apks.append(file) 21 | 22 | # 获取渠道列表 23 | channel_file = 'info/channel.txt' 24 | f = open(channel_file) 25 | lines = f.readlines() 26 | f.close() 27 | 28 | for src_apk in src_apks: 29 | # file name (with extension) 30 | src_apk_file_name = os.path.basename(src_apk) 31 | # 分割文件名与后缀 32 | temp_list = os.path.splitext(src_apk_file_name) 33 | # name without extension 34 | src_apk_name = temp_list[0] 35 | # 后缀名,包含. 例如: ".apk " 36 | src_apk_extension = temp_list[1] 37 | 38 | # 创建生成目录,与文件名相关 39 | output_dir = 'output_' + src_apk_name + '/' 40 | # 目录不存在则创建 41 | if not os.path.exists(output_dir): 42 | os.mkdir(output_dir) 43 | 44 | # 遍历渠道号并创建对应渠道号的apk文件 45 | for line in lines: 46 | # 获取当前渠道号,因为从渠道文件中获得带有\n,所有strip一下 47 | target_channel = line.strip() 48 | # 拼接对应渠道号的apk 49 | target_apk = output_dir + src_apk_name + "-" + target_channel + src_apk_extension 50 | # 拷贝建立新apk 51 | shutil.copy(src_apk, target_apk) 52 | # zip获取新建立的apk文件 53 | zipped = zipfile.ZipFile(target_apk, 'a', zipfile.ZIP_DEFLATED) 54 | # 初始化渠道信息 55 | empty_channel_file = "META-INF/cztchannel_{channel}".format(channel = target_channel) 56 | # 写入渠道信息 57 | zipped.write(src_empty_file, empty_channel_file) 58 | # 关闭zip流 59 | zipped.close() 60 | -------------------------------------------------------------------------------- /PythonTool/info/channel.txt: -------------------------------------------------------------------------------- 1 | samsungapps 2 | hiapk 3 | anzhi 4 | 360cn 5 | xiaomi 6 | myapp 7 | 91com 8 | gfan 9 | appchina 10 | nduoa 11 | 3gcn 12 | mumayi 13 | 10086com 14 | wostore 15 | 189store 16 | lenovomm 17 | hicloud 18 | meizu 19 | baidu 20 | googleplay 21 | wandou 22 | -------------------------------------------------------------------------------- /PythonTool/info/czt.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HongQiQu/AndroidMultiChannelBuildTool/647ba86eb15a4761b9f89ab501c43c4a84dfa73f/PythonTool/info/czt.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AndroidMultiChannelBuildTool 2 | ============================ 3 | 4 | 安卓多渠道打包工具。 5 | 实现思路讲解: [Android批量打包提速 - GavinCT](http://www.cnblogs.com/ct2011/p/4152323.html) 6 | 7 | 使用本工具,Android程序员仅需将ChannelUtil.java放入到工程里使用,以后打包的事情就不用自己动手了。 8 | 安装个Python环境,双击一下MultiChannelBuildTool.py,谁都可以打包了! 9 | # 目录介绍及使用注意 10 | ## PythonTool 11 | Python2 与 Python3 都能正常使用 12 | 13 | - info目录下的channel用来存放渠道,多个渠道之间用换行隔开。 14 | 注意: 15 | fork后通过Github clone,这个channel文件在Windows端是正常的,以换行隔开(`\r\n`)。 16 | 直接点击右侧的download下载zip,可能你在windows端看到的就不是以换行隔开的(`\n`)。 17 | 这是Github造成的。但不会影响程序最后的运行效果。 18 | 你可以粘贴下面的渠道到channel.txt中保持它在windows端的可读性。 19 | 20 | ``` 21 | samsungapps 22 | hiapk 23 | anzhi 24 | 360cn 25 | xiaomi 26 | myapp 27 | 91com 28 | gfan 29 | appchina 30 | nduoa 31 | 3gcn 32 | mumayi 33 | 10086com 34 | wostore 35 | 189store 36 | lenovomm 37 | hicloud 38 | meizu 39 | baidu 40 | googleplay 41 | wandou 42 | ``` 43 | 也可以自己来写入自己需要的市场,并以换行隔开 44 | - MultiChannelBuildTool.py是多渠道打包的脚本。 45 | 46 | ## JavaUtil 47 | ChannelUtil.java 用来解析渠道,直接拷贝到Android工程中使用即可。 48 | ChannelUtil中的getChannel方法可以方便的获取渠道。 49 | 50 | # 常见问题答疑 51 | 52 | 这部分问题是由美团大神丁志虎在微博上答复的,摘录如下: 53 | 54 | - 这个方案没法解决不同渠道使用渠道自己SDK的问题,友盟的SDK提供了在代码中设置渠道的方式,所以再获取到渠道号后再调用SDK相关设置渠道的方法就可以了 55 | - apk用的是java那一套签名,放在META-INF文件夹里的文件原则上是不参与签名的。如果Google修改了apk的签名规则,这一套可能就不适用了。 56 | 57 | # License 58 | 59 | Copyright 2014 GavinCT 60 | 61 | Licensed under the Apache License, Version 2.0 (the "License"); 62 | you may not use this file except in compliance with the License. 63 | You may obtain a copy of the License at 64 | 65 | http://www.apache.org/licenses/LICENSE-2.0 66 | 67 | Unless required by applicable law or agreed to in writing, software 68 | distributed under the License is distributed on an "AS IS" BASIS, 69 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 70 | See the License for the specific language governing permissions and 71 | limitations under the License. 72 | 73 | 74 | --------------------------------------------------------------------------------