App 多渠道打包及重簽名方案

個人博客原文地址java

衆所周知,渠道包是國內 Android 應用市場中經常使用的分發方式。渠道包中會包含不一樣的渠道信息,方便咱們後續統計 App 在各分發渠道的下載量、用戶量、留存率等,有針對地調整應用內容或是推廣方案等。隨着國內 iOS 應用上架愈來愈難,衍生出了不少企業包,爲了方便採集數據,也會用多渠道的方案。android

另外,項目進展過程當中,可能會出現一些臨時新增渠道的需求,這時回到工程中從新打包是比較費時的,有沒有辦法加快打包速度呢?下文中分享了一些方案。git

iOS 多渠道打包方案

iOS 打渠道包目前想到的就只有兩種方式,一種是經過多 target 方式,另外一種是修改 plist 文件方式github

多 target 方式

點擊項目中的 target,右鍵選擇 Duplicate。能夠修改下圖標紅框的三處:target 名稱、plist 名稱和 scheme 名稱。objective-c

判斷當前是哪一個 target,能夠經過添加宏定義實現,方式就是在 Build Settings 找到 Preprocessor Macros,填入宏定義名。數組

代碼中這樣判斷:安全

#ifdef  TARGET1MACROS
    // target1
#elif defined TARGET2MACROS
    // target2
#endif
複製代碼

具體打包腳本就不介紹了,讀者能夠自行網上搜索,這種方式的缺點是一個渠道打一次,效率較低。下面着重分享修改 plist 的批量打包方式。bash

修改 plist 方式

下面用一個簡單的 Demo 演示一下:app

第一步:建立工程名爲 MultiChannelDemo 的項目,並在項目中新建一個 Channel.plist 文件,plist 中設置 Channel 字段,值爲 channel01。而後在頁面上設置一個 label 標籤用於顯示當前的渠道名稱,渠道名能夠經過下面的代碼獲取到:gradle

NSDictionary *channelDic = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Channel" ofType:@"plist"]];
NSString *channel = channelDic[@"Channel"];
複製代碼

第二步:把這個項目用可用的證書正常打一個母包,解壓這個 ipa 包能夠得到一個名爲 Payload 的文件夾,裏面是一個 .app 文件,右鍵顯示其包內容,內容以下:

├── Base.lproj
├── Channel.plist
├── Info.plist
├── MultiChannelDemo
├── PkgInfo
├── _CodeSignature
└── embedded.mobileprovision
複製代碼

能夠看到,裏面的 Channel.plist 也就是在前面工程中新建的存儲渠道信息的 plist,咱們會修改裏面的 Channel 再生成新的渠道包。

第三步:提取描述文件用於重簽名,上一步中 Payload 的文件夾裏有一個 embedded.mobileprovision 文件,這就是咱們須要的文件。

第四步:新建一個純文本,裏面輸入你要新增的渠道號,如:

第五步:寫一個腳本文件 ChannelPackage.sh,內容以下:

#!/bin/bash 
# 輸入的包名

name="MultiChannelDemo"

echo "------SDK渠道包----------"

appName="${name}.app"

plistBuddy="/usr/libexec/PlistBuddy"

configName="Payload/${appName}/Channel.plist"

ipa="${name}.ipa"

# 輸出的新包所在的文件夾名

outUpdateAppDir="ChannelPackages"

# entitlements.plist路徑

entitlementsDir="entitlements.plist"

# 切換到當前目錄

currDir=${PWD}

cd ${currDir}

echo "-----${currDir}"

rm -rf Payload

# 解壓縮-o:覆蓋文件 -q:不顯示解壓過程

unzip -o -q ${ipa}

# 刪除舊的文件夾,從新生成

rm -rf ${outUpdateAppDir}

mkdir ${outUpdateAppDir}

# 刪除舊的 entitlements.plist,從新生成

rm -rf ${entitlementsDir}

/usr/libexec/PlistBuddy -x -c "print :Entitlements " /dev/stdin <<< $(security cms -D -i Payload/${appName}/embedded.mobileprovision) > entitlements.plist

echo "------------------------開始打包程序------------------------"

# 渠道列表文件開始打包

for line in $(cat ChannelList.txt)

# 循環數組,修改渠道信息

do

# 修改 plist 中的 Channel 值

$plistBuddy -c "Set :Channel $line" ${configName}

# app 重簽名

rm -rf Payload/${appName}/_CodeSignature

cp embedded.mobileprovision "Payload/${appName}/embedded.mobileprovision"

# 填入可用的證書 ID

codesign -f -s "iPhone Distribution: XXXXXX." Payload/${appName}  --entitlements ${entitlementsDir}

# 若輸出 Payload/MultiChannelDemo.app: replacing existing signature 說明重簽名完成

# 壓縮 -r:遞歸處理,將指定目錄下的全部文件和子目錄一併處理 -q:不顯示處理過程

zip -rq "${outUpdateAppDir}/$line.ipa" Payload

echo "........渠道${line}打包已完成"

done
複製代碼

腳本里的信息請根據你實際狀況修改。到這裏準備工做都完成了,須要的文件以下:

├── ChannelList.txt
├── ChannelPackage.sh
├── MultiChannelDemo.ipa
└── embedded.mobileprovision
複製代碼

第六步:在當前目錄下執行腳本文件:

sh ChannelPackage.sh
複製代碼

打包完成後生成的 ChannelPackages 文件夾下,就是咱們須要的渠道包:

├── ChannelList.txt
├── ChannelPackage.sh
├── ChannelPackages
│   ├── channel02.ipa
│   ├── channel03.ipa
│   └── channel04.ipa
├── MultiChannelDemo.ipa
├── Payload
│   └── MultiChannelDemo.app
├── embedded.mobileprovision
└── entitlements.plist
複製代碼

這種自動化打包的方式,能夠規避掉 Xcode 自己打包編譯的部分時間,快速出包。

Android 多渠道打包方案

下文介紹的是美團技術團隊開源的 Walle,它有 Gradle 插件命令行兩種使用方式,前者快速集成,後者知足自定義需求。

Gladle 插件方式

配置 build.gradle

在項目根目錄下的 build.gradle 文件中添加 Walle 插件依賴:

buildscript {
    dependencies {
        classpath 'com.meituan.android.walle:plugin:1.1.6'
    }
}
複製代碼

在 app 目錄下的 build.gradle 文件中 apply 插件:

apply plugin: 'walle'

dependencies {
    compile 'com.meituan.android.walle:library:1.1.6'
}
複製代碼

配置插件

在 app 目錄下的 build.gradle 文件中進行渠道配置:

walle {
    // 指定渠道包的輸出路徑
    apkOutputFolder = new File("${project.buildDir}/outputs/channels");
    // 定製渠道包的APK的文件名稱
    apkFileNameFormat = '${appName}_v${versionName}_${channel}.apk';
    // 渠道配置文件
    channelFile = new File("${project.getProjectDir()}/channel")
}
複製代碼

渠道配置文件裏的內容格式詳見:渠道配置文件示例

如何獲取渠道信息

在須要填寫渠道信息的地方引用這段代碼:

String channel = WalleChannelReader.getChannel(this.getApplicationContext());
複製代碼

如何生成渠道包

assemble${variantName}Channels 指令,導出 apk 包。

命令行方式

經過命令行方式,能夠不打開 IDE,直接導出新渠道的 apk。步驟以下:

首先,新建一個文件夾,取用一個上面步驟導出的 apk 包,再下載 walle-cli-all.jar,二者都放置在這個文件夾目錄下。

而後,在文件夾目錄下執行命令:

java -jar walle-cli-all.jar put -c ${channelName} ${apkName}.apk
複製代碼

若上面的命令執行成功,會在當前目錄下生成新的渠道包,名稱爲 ${apkName}_${channelName}.apk

若是要批量寫入渠道,能夠這樣,渠道之間用逗號隔開:

java -jar walle-cli-all.jar batch -c ${channelName0},${channelName1},${channelName2} ${apkName}.apk
複製代碼

或者指定渠道配置文件:

java -jar walle-cli-all.jar batch -c ${channelFile} ${apkName}.apk
複製代碼

若是要寫入額外信息,參考官方文檔

若是要檢查/顯示渠道,命令爲:

java -jar walle-cli-all.jar show ${apkName}.apk
複製代碼

Walle 如今既能知足新應用簽名方案對安全性的要求,也能知足對渠道包打包時間的要求,有須要的能夠嘗試。

相關文章
相關標籤/搜索