在网上看到一篇多渠道打包APK的,思路是没问题的,原文地址:/yyyyy5101/archive//10/23/2735912.html
下面是具体内容:
android应用上传时,需要区分开每个渠道。一般都会在配置文件中更改一个渠道id,如果有多个渠道,手动修改并生成apk的话会非常麻烦,而且增大出错概率。
在这分享一个打包工具类.
我们项目中使用的umeng做统计分析工具, umeng在分渠道打包的时候需要修改manifest.xml中的
<meta-data android:name="UMENG_CHANNEL" android:value="@string/channel_name" /> value值。
该值放到了strings.xml中<string name="channel_name">app_channel</string>,所以在编译的时候只需修改app_channel。
下面是工具类,直接运行即可.
package com.yang.main;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStreamWriter;/*** @description: android渠道打包工具类,确保路径填写无误,渠道名称填入channels中* @author: yangyang@* @time: -10-23下午5:17:47*/public class CompiledApkUpdate {private static final String androidSDK_PATH = "D:\\android\\android-sdk-windows\\"; //android SDK路径public static final String APK_NAME = "duitang.apk";public static final String PROJECT_LIBARY = "";public static final String PROJECT_PATH = "D:\\android\\workspace\\tmp\\duitang\\"; //要打包的工程路径public static final String APK_PATH = "D:\\android\\workspace\\tmp\\apk\\duitang_"; //打包后存放apk的路径 duitang_是前缀private static final String apk_PATH_keystore = "D:\\android\\keystore\\bb"; //apk签名文件路径private static final String channelFlag = "app_channel";// public static String[] channels = {"duitang"}; private static String currentChannelName = "";public static String[] channels = {"duitang","91","360","QQ","jifeng","anzhuo","anzhi","youyi","appchina","wangyi","baidu","souhu","3g","nduo","xiaomi","huawei","meizu","lianxiang","aliyun","taobao","google","nearme","mumayi","wandoujia","crosscat","dangle","maopao","feiliu"}; public static void main(String[] args) { replaceChannel();}/*** 替换渠道名称*/public static void replaceChannel() {try {String outPath = PROJECT_PATH + "res\\values\\strings.xml"; // 输出文件位置String content = read(outPath);for(int channelid=0;channelid<channels.length;channelid++){String tmpContent = content;tmpContent = tmpContent.replaceFirst(channelFlag, channels[channelid]);currentChannelName = channels[channelid];write(tmpContent,outPath);System.out.println("replace channel name over...");packageRes(); // 一次渠道号的更改完成。可以进行打包了。createUnsignedApk();signedApk(channelid);}write(content,outPath); //完成后还原channel_nameSystem.out.println("execute over!");} catch (Exception e) {e.printStackTrace();}}/*** class文件打包成classes.dex*/public static void packageDex(){try { System.out.println("dx.bat start...");Process process = Runtime.getRuntime().exec(androidSDK_PATH+"platform-tools\\dx.bat --dex --output="+PROJECT_PATH+"bin\\classes.dex "+PROJECT_PATH+"bin\\classes "+PROJECT_PATH+"libs\\*.jar"); new MyThread(process.getErrorStream()).start();new MyThread(process.getInputStream()).start();process.waitFor(); process.destroy(); System.out.println("dx.bat over...");} catch (Exception e) { e.printStackTrace(); } }/*** res assets文件打包成res.zip*/public static void packageRes(){try{System.out.println(currentChannelName+" create resources.ap");String library = "";if(PROJECT_LIBARY!=null&&!PROJECT_LIBARY.equals("")){library = "-S " + PROJECT_LIBARY + "res ";}Process process = null;process = Runtime.getRuntime().exec( androidSDK_PATH+ "platform-tools\\aapt.exe package -f " +"-M " + PROJECT_PATH + "AndroidManifest.xml " + //-M 指定配置文件"-S " + PROJECT_PATH + "res " + //-S 指定资源文件library +"-A " + PROJECT_PATH + "assets " + //-A 指定assets"-I " + androidSDK_PATH + "platforms\\android-16\\android.jar " + //-I 指定android类"-F " + PROJECT_PATH + "bin\\resources.ap_ --auto-add-overlay"); // 将资源文件打包resources.ap_new MyThread(process.getErrorStream()).start();new MyThread(process.getInputStream()).start();process.waitFor();process.destroy();System.out.println(currentChannelName+" resources.ap over...");}catch(Exception e){e.printStackTrace();}}/*** classes.dex res.zip AndroidManifest.xml组合成未签名的apk*/public static void createUnsignedApk(){try{System.out.println(currentChannelName+" createUnsignedApk start");Process process = null;process = Runtime.getRuntime().exec(androidSDK_PATH+ "tools\\apkbuilder.bat "+ PROJECT_PATH + "bin\\"+APK_NAME+" -u -z "+ PROJECT_PATH + "bin\\resources.ap_ -f "+ PROJECT_PATH + "bin\\classes.dex"); // 生成未签名的apknew MyThread(process.getErrorStream()).start();new MyThread(process.getErrorStream()).start();process.waitFor();process.destroy();System.out.println(currentChannelName+" createUnsignedApk over");}catch(Exception e){e.printStackTrace();}}/*** 签名apk*/public static void signedApk(int channelid){try{System.out.println(currentChannelName+" signed apk start");Process process = null;String jarsigner;jarsigner = "jarsigner -keystore "+apk_PATH_keystore+" -storepass ***** -keypass ****** " +"-signedjar "+ APK_PATH+ channels[channelid]+ ".apk "+ PROJECT_PATH+ "bin\\"+APK_NAME+" *****"; //签名apkprocess = Runtime.getRuntime().exec(jarsigner); // 对apk进行签名new MyThread(process.getErrorStream()).start();new MyThread(process.getInputStream()).start();process.waitFor();process.destroy();System.out.println(currentChannelName+" signed apk over"); // 一条渠道的打包完成。文件会输出到指定目录}catch(Exception e){e.printStackTrace();}}public static String read(String path) {StringBuffer res = new StringBuffer();String line = null;try {BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path),"UTF-8"));while ((line = reader.readLine()) != null) {res.append(line + "\n");}reader.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return res.toString();}public static boolean write(String cont, String dist) {try {OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(new File(dist)),"utf-8");writer.write(cont);writer.flush();writer.close();return true;} catch (IOException e) {e.printStackTrace();return false;}}public static class MyThread extends Thread{BufferedReader bf;public MyThread(InputStream input) {bf = new BufferedReader(new InputStreamReader(input));}public void run() {String line;try {line = bf.readLine();while (line != null) {System.out.println(line);line = bf.readLine();}} catch (IOException e) {e.printStackTrace();}}}}
注意事项:
1. 正确设置各个path路径.
2. channelFlag的值要与 strings.xml 中channel_name的value一致.
3. 运行java文件是先运行一下android工程,确保bin目录下有最新的apk.
4. 运行过程中不要手动停止,如手动停止,再次运行时请检查strings.xml中channel_name的value值,如不为app_channel,请修改
5. 如有error: Error parsing XML: not well-formed (invalid token)类似错误,注意设置字符编码