美文网首页安卓ITBOXAndroid构建相关
Android多渠道打包飞一般的感觉

Android多渠道打包飞一般的感觉

作者: 沈同学 | 来源:发表于2016-06-28 17:56 被阅读1841次

    上一篇《Android多渠道打包没你想的那么复杂》中说了用gradle方法进行多渠道打包,这个方法简单也好理解,但是速度不敢恭维。今天跟大家说说用Python的方法来打包,那感觉...

    1437707079_452x562.png

    1.添加渠道

    info目录下的channel.txt中添加要上传的渠道名。一定以回车分隔,就是每个名字占一行。

    2.Python脚本

    其实方法来自于美团。就是将apk解压,在META-INF目录下添加一个以渠道名channel_渠道名为前缀的空文件。如图:


    创建一个名为empty.txt的空文件
    # 空文件 便于写入此空文件到apk包中作为channel文件
    src_empty_file = 'info/empty.txt'
    # 创建一个空文件(不存在则创建)
    f = open(src_empty_file, 'w')
    f.close()
    

    获取目录下所有的apk(所以,可以同时多个apk打包哦~)

    src_apks = []
    # python3 : os.listdir()即可,这里使用兼容Python2的os.listdir('.')
    for file in os.listdir('.'):
        if os.path.isfile(file):
            extension = os.path.splitext(file)[1][1:]
            if extension in 'apk':
                src_apks.append(file)
    

    获取渠道列表

    channel_file = 'info/channel.txt'
    f = open(channel_file)
    lines = f.readlines()
    f.close()
    

    解压,读写等操作

    for src_apk in src_apks:
        # file name (with extension)
        src_apk_file_name = os.path.basename(src_apk)
        # 分割文件名与后缀
        temp_list = os.path.splitext(src_apk_file_name)
        # name without extension
        src_apk_name = temp_list[0]
        # 后缀名,包含.   例如: ".apk "
        src_apk_extension = temp_list[1]
    
        # 创建生成目录,与文件名相关
        output_dir = 'output_' + src_apk_name + '/'
        # 目录不存在则创建
        if not os.path.exists(output_dir):
            os.mkdir(output_dir)
    
        # 创建临时目录,与文件名相关
        temp_dir = 'temp' + src_apk_name + '/'
        # 目录不存在则创建
        if not os.path.exists(temp_dir):
            os.mkdir(temp_dir)
    
    
        out_temp_apk = temp_dir + src_apk_name+'temp'+src_apk_extension;
        #copy一份没有渠道信息的apk
        zin = zipfile.ZipFile (src_apk, 'a', zipfile.ZIP_DEFLATED)
        zout = zipfile.ZipFile (out_temp_apk, 'w')
        for item in zin.infolist():
            buffer = zin.read(item.filename)
            if (item.filename[0:16:] != 'META-INF/channel'):
                zout.writestr(item, buffer)
        zout.close()
        zin.close()
    
    
        # 遍历渠道号并创建对应渠道号的apk文件
        for line in lines:
            # 获取当前渠道号,因为从渠道文件中获得带有\n,所有strip一下
            target_channel = line.strip()
            # 拼接对应渠道号的apk
            target_apk = output_dir + src_apk_name + "_" + target_channel + src_apk_extension
            # 拷贝建立新apk
            shutil.copy(out_temp_apk, target_apk)
            # zip获取新建立的apk文件
            zipped = zipfile.ZipFile(target_apk, 'a', zipfile.ZIP_DEFLATED)
            # 初始化渠道信息
            empty_channel_file = "META-INF/channel_{channel}".format(channel=target_channel)
    
    
            for item in zipped.infolist():
                if (item.filename[0:16:] == 'META-INF/channel'):
                    print (item.filename)
            # 写入渠道信息
    
            zipped.write(src_empty_file, empty_channel_file)
            # 关闭zip流
            zipped.close()
    

    3.第三方统计平台设置对应渠道名

    美团有说过友盟的设置方法,由于我用的是腾讯分析,我在这里就说下腾讯的,在MainActivityonCreate方法里添加:

     StatConfig.setInstallChannel(ChannelUtils.getChannel(this));
    

    ChannelUtils.java文件:

    import android.app.Activity;
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.pm.ApplicationInfo;
    import android.util.Log;
    
    import java.io.IOException;
    import java.util.Enumeration;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipFile;
    
    /**
     * 渠道工具类
     * Created by shd on 2016/6/28.
     */
    public class ChannelUtils {
        public static final String Version = "version";
    
        public static final String Channel = "channel";
    
        public static final String DEFAULT_CHANNEL = "yunxiao";
    
        public static final String Channel_File = "channel";
    
        public static String getChannelFromMeta(Context context) {
            ApplicationInfo appinfo = context.getApplicationInfo();
            String sourceDir = appinfo.sourceDir;
            String ret = "";
            ZipFile zipfile = null;
            try {
                zipfile = new ZipFile(sourceDir);
                Enumeration<?> entries = zipfile.entries();
                while (entries.hasMoreElements()) {
                    ZipEntry entry = ((ZipEntry) entries.nextElement());
                    String entryName = entry.getName();
                    if (entryName.startsWith("META-INF") && entryName.contains("channel_")) {
                        ret = entryName;
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (zipfile != null) {
                    try {
                        zipfile.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            String[] split = ret.split("_");
            if (split != null && split.length >= 2) {
                return ret.substring(split[0].length() + 1);
            } else {
                return DEFAULT_CHANNEL;
            }
        }
    
        /**
         * 得到渠道名
         *
         * @param mContext
         * @return
         */
        public static String getChannel(Context mContext) {
            String channel = "";
            if (isNewVersion(mContext)) {//是新版本
                Log.e("isNewVersion  %s", "isNewVersion");
                saveChannel(mContext);//保存当前版本
                channel = getChannelFromMeta(mContext);
            } else {
                channel = getCachChannel(mContext);
            }
            return channel;
        }
    
        /**
         * 保存当前的版本号和渠道名
         *
         * @param mContext
         */
        public static void saveChannel(Context mContext) {
            SharedPreferences mSettinsSP = mContext.getSharedPreferences(Channel_File, Activity.MODE_PRIVATE);
            SharedPreferences.Editor mSettinsEd = mSettinsSP.edit();
            mSettinsEd.putString(Version, PhoneInformationUtils.getAppVersionName(mContext));
            mSettinsEd.putString(Channel, getChannelFromMeta(mContext));
            //提交保存
            mSettinsEd.commit();
        }
    
        private static boolean isNewVersion(Context mContext) {
            SharedPreferences mSettinsSP = mContext.getSharedPreferences(Channel_File, Activity.MODE_PRIVATE);
            String version = PhoneInformationUtils.getAppVersionName(mContext);
            Log.e("version%s", version);
            return !mSettinsSP.getString(Version, "").equals(version);
        }
    
        private static String getCachChannel(Context mContext) {
            SharedPreferences mSettinsSP = mContext.getSharedPreferences(Channel_File, Activity.MODE_PRIVATE);
            return mSettinsSP.getString(Channel, DEFAULT_CHANNEL);
        }
    }
    
    

    源代码在Github上,需要的可以拿走:https://github.com/shd188/MultiChannel


    在此感谢美团cyning

    相关文章

      网友评论

      • 嘿张开心:这个是用的开源框架 还是你自己写的啊? 美团的那个Walle可以实现这个功能吗
        XiuBryant:@Aimerd 请问这种快速写入文件的方式可以实现不同应用名称的打包吗
        沈同学:推荐使用Walle,对7.0兼容好。这个是美团之前的一个方法
      • e21f624bb270:我也是按照美团的打包方式批量打包的,但是会出现有一部分渠道不能统计到的问题,请问楼主有没有遇到相似的问题
      • BKQ_SYC:这个好
        BKQ_SYC: @Aimerd 我也是被上面逼疯了,38个渠道,8个要闪屏,以前手动打没一个小时都不够
        沈同学:@frag 还是谢谢你提醒我闪屏的替换,之前没有想到还有这个用途:+1:

      本文标题:Android多渠道打包飞一般的感觉

      本文链接:https://www.haomeiwen.com/subject/zdmtjttx.html