阅读 13

Jb的测试之旅-安卓多渠道包

申明

本文没有提及到啥新技术,相反的,都是看几年前的技术,因此,本文不适合安卓开发同学,对不了解的同学会有一定的帮助;

因此,请各位大牛勿喷,谢谢~

image.png-31.1kB

前言

(一脸幽怨)这个事,终究还是落在jb身上了,事情经过是这样的:

每次发版本,安卓都需要上传N个商店,而不同的渠道需要打不同的渠道标识,
当APP和后台交互或者数据上报时,会带上各自的渠道信息。这样就能统计
到每个分发市场的下载数、用户数等关键数据;
复制代码

这块呢,本来是让产品实习生负责,结果呢,过完年后,实习生要回校了,产品老大不愿意做这事,测试只剩下一个人了,顺其而然的,这事就落在jb身上;

image.png-269.6kB

使用第三方工具

不幸中的万幸,之前这块是一测试妹子负责,当时让其写了个文档,总算有迹可循,一起看看目前我司是如何打渠道包的吧;

官网包

先需要一个官网包,可以理解base包,适用于官网下载或者APP内手动、自动更新这些场景;

360加固

有了官网包,然后就需要打渠道包的工具,我司用的是360加固工具;

链接:https://pan.baidu.com/s/1sPRt2vxdXegSBV_wEYH66A 
提取码:nu47
复制代码

下载解压,稍后下,还需要两个文件,签名文件keystore及密码、渠道文件

两个文件准备好,打开exe、注册、登录、添加信息(乱写即可),就会看到这货的界面;

image.png-27.7kB
image.png-135.6kB

点击应用加固-签名设置、多渠道设置,分别上传对应的keystore文件跟渠道文件;

image.png-45.6kB
image.png-84.6kB

然后点击添加应用,选择应用,然后就等着渠道包出来吧;

image.png-144kB
image.png-54.9kB

然后再手动去对应的渠道平台官网上传提交审核就可以了;

这个流程完,看着也很简单,没啥特别的,但是为啥要说这个事?

因为keystore不能随便给的啊!!!

既然如此,这种方式存在安全性问题,因此不建议使用,那怎么办?

没源码

在没有源码的事情下,想到的就是反编译,而日常用的最多的就是apktool工具;

流程是这样的:

  • 有base apk;
  • 复制一份新的apk;
  • 通过apktool工具,解压apk(apktool d XX.apk);
  • 添加渠道信息;
  • 通过ApkTool工具,重新打包生成新APK(apktool b newApkDir);
  • 重新签名;

这里说明几个点:

重新打包apk

apkapktool b newApkDir
复制代码

重新打包的apk会在newApkDir\dist下;

签名

这里有两种情况,没有签名跟有签名,当没有签名时,需要先生成keystore文件;

keytool -genkey -alias jb.keystore -keyalg RSA -validity 20000 -keystore jb.keystore
复制代码

输入后需要输入点内容:

image.png-119.4kB
这样,就会生成jb.keystore文件;

有前面文件后,接下来就是签名了;

jarsigner -verbose -keystore jb.keystore -signedjar jb_signed.apk jb.apk jb.keystore
复制代码

这里说明下,jb.apk就是重新打包后的apk,jb_signed.apk就是要生成的apk;

这样,打出来的包就可以安装了,但是呢,依然依赖keystore文件,如果别人的APP使用自己的keystore,普通功能是没问题的,但是一旦需要登录功能,就会报错,提示签名跟XX平台的签名不一致;

怎么解决这问题?直接xp,这里就不展开了;

自己搞呗

自己搞的前提是得有源码,如果连代码权限都没有,那就放弃吧;

而下面的例子只会使用demo来简单演示;

传统的做法

只有一个渠道标识

AndroidManifest.xmlhardcode对应的曲奥标识;

<meta-data android:value="jbtest" android:name="CHANNEL"/>
复制代码

多个渠道标识

AndroidManifest.xml添加渠道信息占位符;

<meta-data android:name="CHANNEL"  android:value="${CHANNEL}" />
复制代码

build.grade设置productFlavors标签添加渠道信息:

android{
     productFlavors{    
        "jb"{
             manifestPlaceholders = [CHANNEL : "jb"]
         }    
         "jb2"{
             manifestPlaceholders = [CHANNEL : "jb2"]
         }
     }
 }
复制代码

这样,Gradle编译生成多渠道包时,会用不同的渠道信息替换AndroidManifest.xml中的占位符;

缺点很明显,每生成一个渠道包,都要重新执行构建流程,国内渠道如此丰富,效率太低了;

美团Walle

这是落魄安卓同学提供的,github地址点这里

虽然github里面把每一步都讲的很清楚,但是因为懒,所以还是想这里贴一下gradle接入的步骤:

1.修改项目根目录下build.gradle文件,在buildscript下的dependencies中增加:

classpath 'com.meituan.android.walle:plugin:1.1.6'
复制代码

完整如下:

buildscript {
    
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.4'
        classpath 'com.meituan.android.walle:plugin:1.1.6'
        
    }
}
复制代码

2.修改app工程的build.gradle文件,增加如下信息:

1)头部增加:

apply plugin: 'walle'
复制代码

2)需要在buildTypes中加signingConfig,否则报这个错: Error:Plugin requires 'APK Signature Scheme v2 Enabled' for release.

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.debug
        }
    }
复制代码

这里说明下signingConfig,是需要一个keystore,对这块有疑问的同学,请点击这里查看;

3)配置wallet信息

walle {
    // 指定渠道包的输出路径
    apkOutputFolder = new File("${project.buildDir}/outputs/channels");
    // 定制渠道包的APK的文件名称
    apkFileNameFormat = '${appName}-${packageName}-${channel}-${buildType}-v${versionName}-${versionCode}-${buildTime}.apk';
    // 渠道配置文件
    channelFile = new File("${project.getProjectDir()}/channel")
}
复制代码

4)dependencies新增 compile:

dependencies {
    implementation 'com.meituan.android.walle:library:1.1.6'
}
复制代码

完整的APP下的build.grade内容如下:

apply plugin: 'com.android.application'
apply plugin: 'walle'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.jb.myapplication"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.debug
        }
    }
}
walle {
    // 指定渠道包的输出路径
    apkOutputFolder = new File("${project.buildDir}/outputs/channels");
    // 定制渠道包的APK的文件名称
    apkFileNameFormat = '${appName}-${packageName}-${channel}-${buildType}-v${versionName}-${versionCode}-${buildTime}.apk';
    // 渠道配置文件
    channelFile = new File("${project.getProjectDir()}/channel")
}
dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation 'com.meituan.android.walle:library:1.1.6'
}


复制代码

3.添加 channel 渠道文件

直接在APP目录下添加名为channel的文件,内容是需要的渠道信息;

anzhuo
anfen
anbei
PC6
360
yingyongbao
baidu
wandoujia
pp
xiaomi
oppo
lenovo
huawei
复制代码

4.获取渠道

在需要获取渠道信息的地方使用如下代码获取渠道信息:

String channel = WalleChannelReader.getChannel(this.getApplicationContext());
复制代码

4.获取渠道

生成渠道包的方式是和assemble${variantName}Channels指令结合, 渠道包的生成目录默认存放在 build/outputs/apk/,也可以通过walle闭包中的apkOutputFolder参数来指定输出目录;

生成渠道包      
gradlew clean assembleReleaseChannels

支持 productFlavors 
gradlew clean assembleMeituanReleaseChannels

生成单个渠道包  
gradlew clean assembleReleaseChannels -PchannelList=anzhuo

生成多个渠道包  
gradlew clean assembleReleaseChannels -PchannelList=wandoujia,baidu

Mac的话,就是./gradlew;
复制代码

原理

原理的话,就是在META-INF目录内添加空文件,可以不用重新签名应用,通过为不同渠道的应用添加不同的空文件,可以唯一标识一个渠道;

每打一个渠道包只需复制一个apk,在META-INF中添加一个使用渠道号命名的空文件即可;

这块的话,网上有大神把脚本开源了,网站自个儿找下吧;

zhuanlan.zhihu.com/p/26674427

一些常用方法

需要的一些环境跟工具,请自己网上了解配置吧;

查看apk是否签名

使用的是jarsigner命令;

jarsigner -certs -verbose -verify xxx.apk 
复制代码

image.png-21.9kB

查看apk的版本号

使用aapt命令;

aapt dump badging xxx.apk
复制代码

image.png-140.7kB

查看apk的渠道号

反编译apk,jb用的是apktool工具,2.4.1版本;

链接:https://pan.baidu.com/s/1MPWTfXIGzeOUpGZplEkveA 
提取码:6h08
复制代码
apktool d XX.apk
复制代码

然后会生成一个目录,直接找到AndroidManifest.xml文件,一般常用的是友盟,因此直接搜索UMENG_CHANNEL,如果用的是别的,请自行搜索;

image.png-9.9kB

实践

凡事都需要落地,那如何落地?

上面的方案,毫无疑问是选择第三种,实践也很简单,直接在jenkins新增打渠道包的选项即可

小结

本文主要是通过3种方式来讲述安卓多渠道包的方式,旧内容,对没了解过的同学有一定的帮助,就这样吧~

1-140R3154U8.jpg-9kB

关注下面的标签,发现更多相似文章
评论