Android 多渠道打包

我想,每當發布新版本時,大家都會對那么多發布渠道感到頭疼不已,本文主要介紹三種Android的多渠道打包方式。下面的例子我以 TalkingData 統計為例子。

1. Gradle 配置 Flavor

1.1 在 AndroidManifest.xml 中配置 meta-data 標簽:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="your.package.name">
 <application>
   <meta-data android:name="TD_CHANNEL_ID" android:value="${TD_CHANNEL_VALUE}"/>
  </application> 
</manifest>
1.2 在項目的 build.gradle 里配置 productFlavors,定義渠道號:
productFlavors {
  yyb {}  
  bdsjzs {}  
  wdj {}  
  xiaomi {}  
  sjzs360 {} 
  productFlavors.all {  
      flavor -> flavor.manifestPlaceholders = [TD_CHANNEL_VALUE: name] 
   }
}

上面定義了一些渠道(比如:豌豆莢,360,小米等),TD_CHANNEL_VALUE 就是你在 meta-data 標簽中配置的值。
同時,需要注意的是,你需要在 defaultConfig 中配置一個默認的渠道名稱:
manifestPlaceholders = [TD_CHANNEL_VALUE: "default_channel_name"]

該原理就是在打包過程中更換 meta-data 標簽中的內容。

優勢:方便理貨,可以根據自身的需求配置不同的渠道執行不同的邏輯(比如:小米渠道有一個獨立的方法,其他渠道沒有);
劣勢:打包速度慢(打包時是對每個渠道都進行一次完整的打包過程)。

2.第三方打包工具

第三方的打包工具原理跟 Gradle 一樣,也是去修改 AndroidManifest.xml 中的 meta-data 標簽的內容,然后執行N次打包簽名的操作實現多渠道打包的。

優勢:簡單方便,幾乎不用自身做什么工作;
劣勢:打包速度過慢;

3.美團的多渠道打包方案

多渠道打包原理可以參考美團Android自動化之旅—生成渠道包這篇文章。Demo 可以查看 快速多渠道打包

3.1 實現原理

直接解壓apk,解壓后的根目錄會有一個META-INF
目錄,如下圖所示:



如果在META-INF目錄內添加空文件,可以不用重新簽名應用。因此,通過為不同渠道的應用添加不同的空文件,可以唯一標識一個渠道。

這樣,每打一個渠道包只需復制一個apk,在 META-INF 中添加一個使用渠道號命名的空文件即可。這種打包方式速度非??欤?00多個渠道不到一分鐘就能打完。

2.2 多渠道實現步驟

2.2.1 android 代碼中獲取渠道號
/**
 * 渠道號工具類:解析壓縮包,從中獲取渠道號
 */
public class ChannelUtil {
 private static final String CHANNEL_KEY = "uuchannel";
 private static final String DEFAULT_CHANNEL = "internal";
 private static String mChannel;

 public static String getChannel(Context context) {
     return getChannel(context, DEFAULT_CHANNEL);
 }

 public static String getChannel(Context context, String defaultChannel) {
     if (!TextUtils.isEmpty(mChannel)) {
         return mChannel;
     }
     //從apk中獲取
     mChannel = getChannelFromApk(context, CHANNEL_KEY);
     if (!TextUtils.isEmpty(mChannel)) {
        return mChannel;
     } //全部獲取失敗
   return defaultChannel;
 }
/**
 * 從apk中獲取版本信息
 *
 * @param context
 * @param channelKey
 * @return
 */
 private static String getChannelFromApk(Context context, String channelKey) {
 long startTime = System.currentTimeMillis();
 //從apk包中獲取
 ApplicationInfo appinfo = context.getApplicationInfo();
 String sourceDir = appinfo.sourceDir;
 //默認放在meta-inf/里, 所以需要再拼接一下
 String key = "META-INF/" + channelKey;
 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(key)) {
             ret = entryName; break;
         }
      }
 } catch (IOException e) {
       e.printStackTrace();
 } finally {
       if (zipfile != null) {
           try {
                 zipfile.close();
           } catch (IOException e) {
                 e.printStackTrace();
           }
       }
}
String channel = ""; 
if (!TextUtils.isEmpty(ret)) {
     String[] split = ret.split("_");
     if (split != null && split.length >= 2) {
         channel = ret.substring(split[0].length() + 1);
      }
    System.out.println("-----------------------------");
    System.out.println("渠道號:" + channel + ",解壓獲取渠道號耗時:" + (System.currentTimeMillis() - startTime) + "ms"); 
    System.out.println("-----------------------------");
 } else { 
    System.out.println("未解析到相應的渠道號,使用默認內部渠道號");
    channel = DEFAULT_CHANNEL;
 } 
return channel;
}

然后在代碼中初始化調用TalkingData設置渠道號:

String channelName = ChannelUtil.getChannel(mContext);
TCAgent.init(mContext,Constants.APP_KEY_TD,channelName );
2.2.2 編寫渠道號文件

修改 info/channel.txt(一行代表一個渠道):

yyb
bdsjzs
wdj
xiaomi
...
2.2.3 編寫 python 腳本

實現解壓 apk 文件,遍歷渠道文件 為 META-INF 目錄添加新文件,重新壓縮 apk 文件等邏輯:

# coding=utf-8
import zipfile
import shutil
import os

def delete_file_folder(src):
 '''delete files and folders'''
 if os.path.isfile(src):
   try:
     os.remove(src)
   except:
     pass 
elif os.path.isdir(src):
   for item in os.listdir(src):
     itemsrc=os.path.join(src,item)
     delete_file_folder(itemsrc)
   try:
     os.rmdir(src)
   except: 
      pass

# 創建一個空文件,此文件作為apk包中的空文件 
 src_empty_file = 'info/empty.txt'
 f = open(src_empty_file,'w')
 f.close()

# 在渠道號配置文件中,獲取指定的渠道號
 channelFile = open('./info/channel.txt','r')
 channels = channelFile.readlines()
 channelFile.close()
 print('-'*20,'all channels','-'*20)
 print(channels)print('-'*50)

# 獲取當前目錄下所有的apk文件
 src_apks = [];
 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)

# 遍歷所以的apk文件,向其壓縮文件中添加渠道號文件
for src_apk in src_apks:
 src_apk_file_name = os.path.basename(src_apk)
 print('current apk name:',src_apk_file_name)
 temp_list = os.path.splitext(src_apk_file_name)
 src_apk_name = temp_list[0]
 src_apk_extension = temp_list[1]
 apk_names = src_apk_name.split('-');
 output_dir = 'outputDir'+'/'
 if os.path.exists(output_dir):
   delete_file_folder(output_dir)
 if not os.path.exists(output_dir):
   os.mkdir(output_dir)

 # 遍歷從文件中獲得的所以渠道號,將其寫入APK包中
 for line in channels:
   target_channel = line.strip()
   target_apk = output_dir + apk_names[0] + "-" + target_channel+"-"+apk_names[2] + src_apk_extension
   shutil.copy(src_apk, target_apk)
   zipped = zipfile.ZipFile(target_apk, 'a', zipfile.ZIP_DEFLATED)
   empty_channel_file = "META-INF/uuchannel_{channel}".format(channel = target_channel)
   zipped.write(src_empty_file, empty_channel_file)
   zipped.close()

print('-'*50)
print('repackaging is over ,total package: ',len(channels))
input('\npackage over...')
2.2.4 打包一個簽名 APK 包

將APK 包放在 python 腳本的同級目錄

2.2.5 執行python 腳步,多渠道打包
python Android.py

最后就會在 同級目錄下生成 outputDir 目錄,里面就是各個渠道的 APK 。

優勢:打包速度很快,很方便;
劣勢:不夠靈活,不能靈活的配置不同的渠道不同的業務邏輯;

總結
三種打包方式中,各有各的優勢,大家在選擇多渠道打包方式的時候可以根據自身的需求來選擇

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,634評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,653評論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,835評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,235評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,459評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,000評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,819評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,004評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,257評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,717評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,003評論 2 374

推薦閱讀更多精彩內容

  • Android多渠道打包 概述 每當發新版本時,Android客戶端會被分發到各個應用市場,比如豌豆莢,360手機...
    礪雪凝霜閱讀 2,149評論 2 11
  • 目錄一、Python打包及優化(美團多渠道打包)二、Gradle打包三、其他打包方案:修改Zip文件的commen...
    守望君閱讀 5,715評論 4 17
  • 我們做Android用戶級應用開發的時候都要考慮這樣的問題,目前的應用市場有很多,我們的安裝包是通過哪個渠道進入用...
    尹star閱讀 8,779評論 11 26
  • 這里主要說一下同時使用 微信資源混淆以及同時使用 walle 打多渠道包 遇到的坑,以及如何解決這個問題的。如果只...
    Coralline_xss閱讀 1,220評論 0 1
  • android多渠道打包 1.如何查看apk的簽名信息 1將apk解壓; 2.找到META-INF 下的.RSA文...
    ping0505閱讀 1,054評論 0 1