android 多渠道打包工具 可打包libs和.so文件

android應用上傳時,需要區分開每個渠道。一般都會在配置文件中更改一個渠道id,如果有多個渠道,手動修改並生成apk的話會非常麻煩,而且增大出錯概率。

在這分享一個打包工具類。網上也有類似的,我是在它的基礎上做的優化,特別是打包so文件,一句小小的命令廢了好大勁。

我們項目中使用的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。

下面是工具類,直接運行即可.

  1. package com.yang.main;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileNotFoundException;  
  7. import java.io.FileOutputStream;  
  8. import java.io.IOException;  
  9. import java.io.InputStream;  
  10. import java.io.InputStreamReader;  
  11. import java.io.OutputStreamWriter;  
  12. /** 
  13.  * @description: android渠道打包工具類,確保路徑填寫無誤,渠道名稱填入channels中 
  14.  * @author: [email protected] 
  15.  * @time:    2012-10-23下午5:17:47 
  16.  */  
  17. public class CompiledApkUpdate {  
  18.   
  19.     private static final String androidSDK_PATH = "D:\\android\\android-sdk-windows\\";        //android SDK路徑  
  20.   
  21.     public static final String APK_NAME = "duitang.apk";  
  22.     public static final String PROJECT_LIBARY = "";  
  23.     public static final String PROJECT_PATH = "D:\\android\\workspace\\tmp\\duitang\\";        //要打包的工程路徑  
  24.     public static final String APK_PATH = "D:\\android\\workspace\\tmp\\apk\\duitang_";        //打包後存放apk的路徑  duitang_是前綴  
  25.       
  26.       
  27.     private static final String apk_PATH_keystore = "D:\\android\\keystore\\bb";        //apk簽名文件路徑  
  28.     private static final String channelFlag = "app_channel";  
  29.       
  30. //    public static String[] channels = {"duitang"};   
  31.     private static String currentChannelName = "";  
  32.     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"};   
  33.   
  34.     public static void main(String[] args) {   
  35.         replaceChannel();  
  36.     }  
  37.   
  38.     /** 
  39.      * 替換渠道名稱 
  40.      */  
  41.     public static void replaceChannel() {  
  42.         try {  
  43.             String outPath = PROJECT_PATH + "res\\values\\strings.xml"// 輸出文件位置  
  44.             String content = read(outPath);  
  45.             for(int channelid=0;channelid<channels.length;channelid++){  
  46.                 String tmpContent = content;  
  47.                 tmpContent = tmpContent.replaceFirst(channelFlag, channels[channelid]);  
  48.                 currentChannelName = channels[channelid];  
  49.                 write(tmpContent,outPath);  
  50.                 System.out.println("replace channel name over...");  
  51.                 packageRes(); // 一次渠道號的更改完成。可以進行打包了。  
  52.                 createUnsignedApk();  
  53.                 signedApk(channelid);  
  54.             }  
  55.             write(content,outPath);        //完成後還原channel_name  
  56.             System.out.println("execute over!");  
  57.         } catch (Exception e) {  
  58.             e.printStackTrace();  
  59.         }  
  60.     }  
  61.       
  62.     /** 
  63.      * class文件打包成classes.dex 
  64.      */  
  65.     public static void packageDex(){  
  66.         try {   
  67.             System.out.println("dx.bat start...");  
  68.             Process process = Runtime.getRuntime().exec(androidSDK_PATH  
  69.                     +"platform-tools\\dx.bat --dex --output="  
  70.                     +PROJECT_PATH+"bin\\classes.dex "  
  71.                     +PROJECT_PATH+"bin\\classes "  
  72.                     +PROJECT_PATH+"libs\\*.jar");   
  73.               
  74.             new MyThread(process.getErrorStream()).start();  
  75.   
  76.             new MyThread(process.getInputStream()).start();  
  77.               
  78.             process.waitFor();    
  79.             process.destroy();    
  80.             System.out.println("dx.bat over...");  
  81.         } catch (Exception e) {   
  82.             e.printStackTrace();   
  83.         }   
  84.     }  
  85.       
  86.     /** 
  87.      * res assets文件打包成res.zip 
  88.      */  
  89.     public static void packageRes(){  
  90.         try{  
  91.             System.out.println(currentChannelName+" create resources.ap");  
  92.             String library = "";  
  93.             if(PROJECT_LIBARY!=null&&!PROJECT_LIBARY.equals("")){  
  94.                 library = "-S " + PROJECT_LIBARY + "res ";  
  95.             }  
  96.             Process process = null;  
  97.             process = Runtime  
  98.                     .getRuntime()  
  99.                     .exec(  androidSDK_PATH  
  100.                             + "platform-tools\\aapt.exe package -f " +  
  101.                             "-M " + PROJECT_PATH + "AndroidManifest.xml " +            //-M 指定配置文件  
  102.                             "-S " + PROJECT_PATH + "res " +                            //-S 指定資源文件  
  103.                             library +  
  104.                             "-A " + PROJECT_PATH + "assets " +                        //-A 指定assets  
  105.                             "-I " + androidSDK_PATH + "platforms\\android-16\\android.jar " +    //-I 指定android類  
  106.                             "-F " + PROJECT_PATH + "bin\\resources.ap_ --auto-add-overlay"); // 將資源文件打包resources.ap_  
  107.             new MyThread(process.getErrorStream()).start();  
  108.             new MyThread(process.getInputStream()).start();  
  109.             process.waitFor();  
  110.             process.destroy();  
  111.             System.out.println(currentChannelName+" resources.ap over...");  
  112.         }catch(Exception e){  
  113.             e.printStackTrace();  
  114.         }  
  115.     }  
  116.       
  117.     /** 
  118.      * classes.dex res.zip AndroidManifest.xml組合成未簽名的apk 
  119.      */  
  120.     public static void createUnsignedApk(){  
  121.         try{  
  122.             System.out.println(currentChannelName+" createUnsignedApk start");  
  123.             Process process = null;  
  124.             process = Runtime.getRuntime().exec(  
  125.                     androidSDK_PATH+ "tools\\apkbuilder.bat "  
  126.                     + PROJECT_PATH + "bin\\"+APK_NAME+" -u -z "  
  127.                     + PROJECT_PATH + "bin\\resources.ap_ -f "  
  128.                     + PROJECT_PATH + "bin\\classes.dex"  
  129.                     +" -rj "+ PROJECT_PATH + "libs"     //這裏很重要如果要打包libs的jar包請加入到上面字符串  
  130.                     +" -nf "+ PROJECT_PATH + "libs"     //這裏是我試了好多次翻閱各種資料才成功的,給大家分享了。這樣打包纔可以把so文件也打包進去。  
  131.                     ); // 生成未簽名的apk.  
  132.             new MyThread(process.getErrorStream()).start();  
  133.             new MyThread(process.getErrorStream()).start();  
  134.             process.waitFor();  
  135.             process.destroy();  
  136.             System.out.println(currentChannelName+" createUnsignedApk over");  
  137.         }catch(Exception e){  
  138.             e.printStackTrace();  
  139.         }  
  140.     }  
  141.       
  142.     /** 
  143.      * 簽名apk 
  144.      */  
  145.     public static void signedApk(int channelid){  
  146.         try{  
  147.             System.out.println(currentChannelName+" signed apk start");  
  148.             Process process = null;  
  149.             String jarsigner;  
  150.             jarsigner = "jarsigner -keystore "+apk_PATH_keystore+" -storepass ***** -keypass ****** " +  
  151.                     "-signedjar "  
  152.                     + APK_PATH  
  153.                     + channels[channelid]  
  154.                     + ".apk "  
  155.                     + PROJECT_PATH  
  156.                     + "bin\\"+APK_NAME+" *****";            //簽名apk  
  157.             process = Runtime  
  158.                     .getRuntime()  
  159.                     .exec(jarsigner); // 對apk進行簽名  
  160.             new MyThread(process.getErrorStream()).start();  
  161.   
  162.             new MyThread(process.getInputStream()).start();  
  163.             process.waitFor();  
  164.             process.destroy();  
  165.             System.out.println(currentChannelName+" signed apk over"); // 一條渠道的打包完成。文件會輸出到指定目錄  
  166.         }catch(Exception e){  
  167.             e.printStackTrace();  
  168.         }  
  169.     }  
  170. /** 
  171.      * 這是google簽名的打包方式。跟上面一個方法差不多的   zipalign apk 
  172.      */  
  173.     public static void zipalignApk(int channelid){  
  174.         try{  
  175.             System.out.println(currentChannelName+":zipalign apk start");  
  176.             String apkPath=APK_PATH.replace("{c}", channels[channelid]);  
  177.             File file=new File(apkPath);  
  178.             if(!file.getParentFile().isDirectory()) file.getParentFile().mkdirs();  
  179.             Process process = null;  
  180.             String jarsigner;  
  181.             jarsigner = "cmd.exe /C "+androidSDK_PATH+"tools/zipalign.exe -v 4 "  
  182.                     + apkPath  
  183.                     + ".apk "  
  184.                     + apkPath  
  185.                     + "-z.apk";            //簽名apk  
  186.             process = Runtime  
  187.                     .getRuntime()  
  188.                     .exec(jarsigner); // 對apk進行簽名  
  189.             new MyThread(process.getErrorStream()).start();  
  190.   
  191.   
  192.             new MyThread(process.getInputStream()).start();  
  193.             process.waitFor();  
  194.             process.destroy();  
  195.             System.out.println(currentChannelName+":zipalign apk over"); // 一條渠道的打包完成。文件會輸出到指定目錄  
  196.         }catch(Exception e){  
  197.             e.printStackTrace();  
  198.             System.exit(0);  
  199.         }  
  200.     }  
  201.       
  202.       
  203.     public static String read(String path) {  
  204.         StringBuffer res = new StringBuffer();  
  205.         String line = null;  
  206.         try {  
  207.             BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path),"UTF-8"));  
  208.             while ((line = reader.readLine()) != null) {  
  209.                 res.append(line + "\n");  
  210.             }  
  211.             reader.close();  
  212.         } catch (FileNotFoundException e) {  
  213.             e.printStackTrace();  
  214.         } catch (IOException e) {  
  215.             e.printStackTrace();  
  216.         }  
  217.         return res.toString();  
  218.     }  
  219.   
  220.     public static boolean write(String cont, String dist) {  
  221.         try {  
  222.             OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(new File(dist)),"utf-8");  
  223.             writer.write(cont);  
  224.             writer.flush();  
  225.             writer.close();  
  226.             return true;  
  227.         } catch (IOException e) {  
  228.             e.printStackTrace();  
  229.             return false;  
  230.         }  
  231.     }  
  232.       
  233.       
  234.     public static class MyThread extends Thread{  
  235.         BufferedReader bf;  
  236.           
  237.         public MyThread(InputStream input) {  
  238.             bf = new BufferedReader(new InputStreamReader(input));  
  239.         }  
  240.   
  241.         public void run() {  
  242.             String line;  
  243.             try {  
  244.                 line = bf.readLine();  
  245.                 while (line != null) {  
  246.                     System.out.println(line);  
  247.                     line = bf.readLine();  
  248.                 }  
  249.             } catch (IOException e) {  
  250.                 e.printStackTrace();  
  251.             }  
  252.         }  
  253.     }  
  254. }  
發佈了4 篇原創文章 · 獲贊 4 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章