android 多渠道打包

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: [email protected]

 * @time:    2012-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_name

            System.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"); // 生成未签名的apk

            new 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+" *****";            //签名apk

            process = 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)类似错误,注意设置字符编码

你可能感兴趣的:(android)