自動化打包資源混淆集成python實踐----打包

一、自動化打包方案html

  1)友盟多渠道多渠道打包java

    2)gradle productFlavors系統的條件編譯python

    3)美團打包android

    4)APK文件註釋寫入渠道號git

二、各打包方案簡介github

       1)友盟多渠道多渠道打包(window 綠色版,gradle版本 如今過期)算法

        

        原理:拆包分解apk,修改AndroidManifest.xml二進制文件後,再從新打包shell

        耗時:較短(多渠道打包時,避免了屢次dex過程,aapt過程)編程

        渠道號保存方式:保存在AndroidManifest.xml 文 件 meta 數據中微信

        不足:較難保證AndroidManifest.xml二進制修改正確,可能會出現兼容性問題;多渠道apk 命名不能預約,須要額外處理重命名apk文件。

     

 

      2).gradle productFlavors系統的條件編譯

  

      原理: 每一個渠道包,都走完整個打包(appt、混淆、dex,簽名)流程

      耗時:長(跟渠道包量成正比)

      渠道號保存方式:保存在AndroidManifest.xml 文 件 meta 數據中

 

     3)美團方案

     

     原理:在APK文件的META-INF目裏增長渠道文件

     耗時:快(多個渠道包,只有一次完整打包流程)

     渠道號保存方式:mtchannel_yybcpd文件名中

     

    4)APK文件註釋寫入渠道號

     

    

 原理:Android 使用的apk包的壓縮方式是zip,與zip有相同的文件結構,正確寫入 File Comment 部分,不破壞壓縮包、不用從新打包前提下,寫入本身想要的數據。

 耗時:快

 渠道號保存方式:保存在zip 註釋中。

 

三、android 打包流程和簽名機制:

  1)android 打包流程

 

   ps:代碼混淆在dx 生成dex 以前進行。

    

  2)簽名機制

    (1)生成MANIFEST.MF文件 遍歷apk包中的全部文件(entry),對非文件夾非簽名 文件的文件,逐個生成SHA1的數字簽名信息,再用 Base64進行編碼

    (2)生成CERT.SF文件 對生成的Manifest,使用SHA1-RSA算法,用私鑰進 行簽名

    (3)生成CERT.RSA文件 對CERT.SF文件作簽名,內容存檔(公鑰、所採用的加 密算法)到中CERT.RSA

     ps:從第一步規則源碼,/build/tools/signapk/SignApk.java ,關鍵源碼代碼以下:

     

    從源碼中,能夠看出空文件夾免簽名,並看不出來美團方案怎樣規避簽名機制。

    從apk安裝過程簽名校驗關鍵類:PackageParser.java   collectCertificates()方法:

   

 

  從上圖能夠看空文件夾和META-INFO文件夾中的文件、AndroidManifest.xml免簽名檢驗的,美團就是經過在META-INFO文件夾

      新增渠道號文件,實現多渠道打包,固然不須要進行zipalign操做(經過zipalign -c -v 4 application.apk檢驗包是否已經對齊)。 

 

四、python實現方案3和方案4(python2.7 windos環境):

  1)思路:1.執行gradle 打包命令

     2.監聽gradle 打包進程,打包結束後

      方案3:拷貝apk,對apk進行zipfile 文件操做,在META-INFO文件夾中新增多渠道文件。

      方案4:拷貝apk,對apk添加zip comment.

    

 

  2)python代碼實現:

         (1)執行gradle 打包命令     

  cmd = 'gradle assembleInnerRelease ' #假設 builde.gradle productFlavors 中配置inner
  pro = subprocess.Popen(cmd,shell = True)

  (2)監聽進程(作了簡單的封裝)

   

#監聽進程 用來監聽gradle 打包進程,後文微信資源混淆進程等
def func_listen_process(Process,listener):
    if listener == None or not isinstance(listener,ProcessListener):
        print 'func_listen_process: ' + process + ' listener is null or not processListener interface'
        return
    
    listener.start()
    
    while (True):   
        time.sleep(1)  
        retCode = subprocess.Popen.poll(pro)   
        if retCode is not None:
            listener.end()
            break
        else:
            listener.doing()


#抽象類加抽象方法就等於面向對象編程中的接口 from abc import ABCMeta,abstractmethod #定義接口 class ProcessListener: __metaclass__ = ABCMeta #指定這是一個抽象類 @abstractmethod #抽象方法 def start(self): pass @abstractmethod #抽象方法 def doing(self): pass @abstractmethod #抽象方法 def end(self): pass

 

   (3)監聽gradlle打包進程

#監聽gradle 打包進程
func_listen_process(pro,GradlePackProcessListener())
#gradle打包進程監聽器 class GradlePackProcessListener(ProcessListener): curTime = 0 apkCount = 0 def __init__(self): return def start(self): self.curTime = time.time() def doing(self): return def end(self):     apkCount = func_channelsReleasePack(workSpace) self.curTime = time.time() - self.curTime; print "\nandroid channels pack cost total time : " + str(int(self.curTime)) +'s , ' + str(apkCount) + ' apks' #多渠道打正式包 channelsFile.txt 每行一個渠道號 def func_channelsReleasePack(workSpace): apkPath = workSpace + '/build/outputs/apk' channelsFile = open(workSpace + '/channelsFile.txt', "r") apks = [] countApk = 0 global version print u"\nstart channle release pack\n" while True: channelName = channelsFile.readline() channelName = channelName.strip('\n').strip('\t') if channelName: channelApkName = apkPath + '/' + apkPrefix + '_' + channelName + '_' + version +'.apk' shutil.copyfile(apkPath+'/' + apkPrefix + '_inner_' + ''+ version +'.apk',channelApkName) apks.append(apkPrefix + '_' + channelName + '_' + version +'.apk') zipped = zipfile.ZipFile(channelApkName, 'a', zipfile.ZIP_DEFLATED) empty_channel_file = "META-INF/channel_{channel}".format(channel = channelName) newChannelFile = open(apkPath+'/channel_'+ channelName, 'w') newChannelFile.close() zipped.write(apkPath+'/channel_'+ channelName,empty_channel_file) zipped.close(); os.remove(apkPath+'/channel_'+ channelName) print '---> /' + apkPrefix +'_' + channelName + '_' + version +'.apk' countApk = countApk + 1; else: channelsFile.close() #刪除出多餘的文件 func_delFiles(apkPath,apks) break print u"\nend channle release pack" #func_zipalignApks(apks) return countApk;

 

 (4)獲取應用獲取渠道號(這裏只給出方案3渠道號獲取方法,方案四渠道號獲取方法見一種爲 Apk 動態寫入信息的方案):

 

/**
     * 獲取友盟渠道
     * #app安裝後,拷貝保存在/data/app/目錄下
     * @return
     */
    public static String getChannel(Context mContext) {
        ApplicationInfo appinfo = mContext.getApplicationInfo();
        String sourceDir = appinfo.sourceDir;
        String ret = "";
        ZipFile zipfile = null;
        try {
            Log.d("sihaixuan", "app source dir : " + sourceDir);
            zipfile = new ZipFile(sourceDir);
            Enumeration<?> entries = zipfile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = ((ZipEntry) entries.nextElement());
                String entryName = entry.getName();
                Log.d("sihaixuan",entryName + "");
                if (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 "";
        }
    }


 

(5)打包測試

 

 

 五、總結

  

 ps:gradle 定義 task 也能夠實現以上方案,新一代Android渠道打包工具:1000個渠道包只須要5秒實現了apk 註釋添加渠道號

github:AndroidPackCi

參考資料:

   團Android自動化之旅—生成渠道包

   新一代Android渠道打包工具:1000個渠道包只須要5秒

         友盟渠道打包工具

        Android簽名機制之---簽名過程詳解

       Android源碼查看網址http://androidxref.com/

      一種爲 Apk 動態寫入信息的方案

相關文章
相關標籤/搜索