python 多渠道打包以及在Android7.0系统上的问题

字数 1226阅读 966

由于安卓应用市场非常多,加上安卓推广渠道众多,我们需要统计一下我们的用户是通过哪一个渠道安装我们的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

推荐阅读更多精彩内容