由于安卓應用市場非常多,加上安卓推廣渠道眾多,我們需要統計一下我們的用戶是通過哪一個渠道安裝我們的app,這時候我們就需要多渠道來做一個區分。這里我就簡單介紹一下python多渠道打包,一些相關的python以及環境就不在贅述了,相信大家都已經非常熟悉了,以下就是多渠道打包流程。
1.創建一個文件夾在文件夾里面創建一個android_channels.txt文本,里面放置所有需要的渠道
xiaomi
huawei
yingyongbao
360mobile
wandoujia
anzhuo_market
baidu
91market
anzhi_market
googleplay
2.創建打包腳本文本channel.py 這個就是我們需要執行的腳本文件
#coding=utf-8
import zipfile
import shutil
import os
import sys
if __name__ == '__main__':
apkFile = sys.argv[1]
apk = apkFile.split('.apk')[0]
# print apkFile
emptyFile = 'xxx.txt'
f = open(emptyFile, 'w')
f.close()
with open('./android_channels.txt', 'r') as f:
contens = f.read()
lines = contens.split('\n')
os.mkdir('./release')
#print lines[0]
for line in lines:
channelss = line
channel = 'channel_' + line
#輸出apk重命名
destfile = './release/%s_%s.apk' % (apk, channelss)
shutil.copy(apkFile, destfile)
zipped = zipfile.ZipFile(destfile, 'a')
channelFile = "META-INF/{channelname}".format(channelname=channel)
zipped.write(emptyFile, channelFile)
zipped.close()
os.remove('./xxx.txt')
#mac
os.system('chmod u+x zipalign_batch.sh')
os.system('./zipalign_batch.sh')
#windows
#os.system('zipalign_batch.bat')
zip align 優化的 zipalign_batch.sh
if [ -d "release" ]
then
if [ -d "release/zipaligned" ]
then
rm -rf "release/zipaligned"
fi
mkdir "release/zipaligned"
for file in ./release/*
do
if test -f $file
then
echo "${file##*/}"
zipalign -v 4 $file release/zipaligned/${file##*/}
fi
done
else
echo "No release folder, can not go on zipalign"
fi
windows系統需要的bat
@echo off
echo begin running
if exist release\zipaligned (
rd /s /q release\zipaligned
)
md release\zipaligned
for /f "delims=" %%i in ('dir release\*.apk /b') do (
zipalign -v 4 release\%%i release\zipaligned\%%i
)
echo end running
3.將簽名打包好的apk放到當前文件夾下面,通過命令行進入到當前文件夾,然后執行命令
channel.py signed.apk
查看當前文件夾,就會多了個release文件夾,打開release文件夾里面是根據channel_list渠道列表生成的10個APK。里面發現還有一個zipaligned文件夾,zipaligned是什么東西呢。
4.zipalign官方介紹
zipalign is an archive alignment tool that provides important optimization to Android application (.apk) files.
Zipalign是1.6之后引入的,是一個對Apk文件進行存檔對齊的優化工具,它的目的是確保所有的未壓縮數據都從文件的開始位置以指定的對齊方式排列。尤其是.apk壓縮包中的圖片資源和未加工處理的相關文件,對齊的方式是以4字節對齊。其好處是能夠減少應用程序的RAM內存資源消耗。Google的Android開發文檔中特別之處在發布應用到最終客戶之前務必使用Zipalign工具對你的.apk文件進行優化。
簡單提煉一下就是有以下4個特點:
(1)它是一個優化工具
(2)它是4字節邊界對齊
(3)減少內存使用
(4)提高效率
我們先解壓一下原始簽名但未寫入渠道名的signed.apk,我們再解壓一個寫入渠道名的apk,然后對比APK/META-INF目錄,會發現后者多了一個空文件,文件名一般以channel_yingyongbao這種格式來命名,由此可以看來channel后面就是我們用來標記渠道的渠道名。那Python打包的原理就可以簡單的理解為通過在APK/META-INF目錄寫入空文件來標記渠道。
5.Android 7.0系統提示安裝找不到安裝證書
Android 7.0 引入一項新的應用簽名方案 APK Signature Scheme v2,它能提供更快的應用安裝時間和更多針對未授權 APK 文件更改的保護。在默認情況下,Android Studio 2.2 和 Android Plugin for Gradle 2.2 會使用 APK Signature Scheme v2 和傳統簽名方案來簽署您的應用。
雖然我們建議您對您的應用采用 APK Signature Scheme v2,但這項新方案并非強制性的。如果您的應用在使用 APK Signature Scheme v2 時不能正確開發,您可以停用這項新方案。禁用過程會導致 Android Studio 2.2 和 Android Plugin for Gradle 2.2 僅使用傳統簽名方案來簽署您的應用。要僅用傳統方案簽署,打開模塊級 build.gradle 文件,然后將行 v2SigningEnabled false 添加到您的版本簽名配置中:
signingConfigs {
release {
try {
storeFile file(props['KEYSTORE_FILE'])
storePassword props['KEYSTORE_PASSWORD']
keyAlias props['KEY_ALIAS']
keyPassword props['KEY_PASSWORD']
//android studio2.2之后版本會默認啟用V2簽名機制,由于我們簽名是之前版本的會導致7.0系統以上手機簽名 識別不了導致
//沒辦法安裝 所以目前這里我們需要先禁用掉
v2SigningEnabled false
} catch (ex) {
throw new InvalidUserDataException("請在app文件夾下添加'signing.properties'文件并配置相應的變量值")
}
}
}
6.android 7.0提示安裝失敗,安裝包不完整
這是因為Android7.0作用域目錄訪問 在 Android 7.0 中,應用可以使用新的 API 請求訪問特定的外部存儲目錄,包括可移動媒體上的目錄,如 SD 卡。新 API 大大簡化了應用訪問標準外部存儲目錄的方式,如 Pictures 目錄。應用(如照片應用)可以使用這些 API(而不是使用 READ_EXTERNAL_STORAGE),其授予所有存儲目錄的訪問權限或存儲訪問框架,從而讓用戶可以導航到目錄。
此外,新的 API 簡化了用戶向應用授予外部存儲訪問權限的步驟。當您使用新的 API 時,系統使用一個簡單的權限 UI,其清楚地詳細介紹應用正在請求訪問的目錄。app內升級會失敗,因為下載完apk包之后,發intent安裝時,沒有讀取包所在目錄的權限,而導致讀取失敗,安裝失敗。
官方文檔:developer.android.google.cn
解決方案:
/**
* 通過隱式意圖調用系統安裝程序安裝APK
*/
public static void install(Context context) {
File file = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
, "signed.apk");
Intent intent = new Intent(Intent.ACTION_VIEW);
// 由于沒有在Activity環境下啟動Activity,設置下面的標簽
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if(Build.VERSION.SDK_INT>=24) { //判讀版本是否在7.0以上
//參數1 上下文, 參數2 Provider主機地址 和配置文件中保持一致 參數3 共享的文件
Uri apkUri =
FileProvider.getUriForFile(context, "com.a520wcf.chapter11.fileprovider", file);
//添加這一句表示對目標應用臨時授權該Uri所代表的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
}else{
intent.setDataAndType(Uri.fromFile(file),
"application/vnd.android.package-archive");
}
context.startActivity(intent);
}
具體可以參照文章:http://blog.csdn.net/yulianlin/article/details/52775160