一、什么是马甲包
马甲包是利用各大市场规则漏洞,通过技术手段,多次上架同一款产品的方法。马甲包和主产品包拥有同样的内容和功能,除了icon和应用名称不能完全一致,其他基本一致。
二、为什么做马甲包,做马甲包有什么好处?
1.最核心的作用是获取有效客户。另外一方面是增加关键词的覆盖量,众所周知,单个APP只能有100个字符的关键词,多个APP就意味着可以覆盖N×100个字符的关键词,关键词覆盖越多,就意味着能够被更多的客户搜索到,有展现量,才有下载量,有下载量才有可能发展成为有效客户。
2.抗风险
正常情况下,任何一款产品都是要不断的更新功能的。如果我们直接在主包上更新,一旦新功能不被用户接受那就损失大了,我们前期大量投资带来的用户将会流失,这对很多产品开发者来说是不可承受之痛。
如果使用马甲包,则可以随意测试新功能,好的功能就在主包上迭代,不好的也无所谓,马甲包本身就是来背锅的。
3.导量
主包和马甲包属于同一个平台,用户信息可以共享通过弹窗,广告,Push等引导用户下载主App。有一部分App接了网盟相互导流。
4.刷榜
-
积分墙;理论上是真实用户,冲榜量级大,可靠后续补量维持;但冲榜和维榜费用高昂,非一般产品所能承受。
-
真机;利用真实机器操作任务,但不能抹机,否则就成假量了,成本相对较低。
-
技术流;机刷,服务器控制操作,成本最低。
上面三种方式,机刷是最便宜的,但是风险高,容易被发现下架,所以一般用马甲包来做机刷,以此来抵抗风险。
了解了什么是马甲包,下面就来讲一下Android怎么做马甲包
看了很多方案最多的就是复制一套代码,修改包名,当然是可行的,但是也有一个弊端,马甲包越多,代码越多,版本越多,项目越多,一次更新要修改很多马甲包,这样维护会死人的,亲身经历!
那么如何优雅的开发马甲包呢?前提是一套代码!
马甲包开发,首先要了解android怎么区分不同的APP,作为开发者当然第一反应就是PackageName,这样说虽然也对,但是并不严谨,为了这个问题,我特意询问了应用商店的客服(毕竟马甲包也是为了上架),新建应用的包名是applicationID,还是PackageName,当然客服的回答并不理想,他们也不熟悉,然而我们去查看android的开发者文档,会明确的告诉你,android应用是根据applicationID区分的,只不过用早期eclipse开发项目时没有applicationID和PackageName的区分,就默认二者是一样的,到了android studio开发时,二者默认也是一样的,但是也可以不一样,那么我们就可以通过修改applicationID来打包不同的马甲包,接下来介绍马甲包需要修改的地方如何修改。这里有我遇到的三个坑需要处理
-
APP名称、icon怎么修改呢?
-
微信分享支付、支付宝支付会有影响吗?
-
某些sdk跟签名绑定的(例如:阿里人脸识别)
首先看怎么结局解决app名称和不同资源
build.gradle文件:
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
flavorDimensions "lee"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
signingConfigs {
app {
storeFile file('keystore')
storePassword "123456"
keyAlias 'slice'
keyPassword "123456"
}
}
buildTypes {
release {
debuggable false
minifyEnabled true
// Zipalign优化
zipAlignEnabled true
// 移除无用的resource文件
shrinkResources true
signingConfig signingConfigs.app
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
signingConfig signingConfigs.app
zipAlignEnabled false
shrinkResources false
minifyEnabled false
}
}
//多渠道配置
productFlavors {
app {//主包app
applicationId "com.example.baseslicedemo"
versionName "1.0.0"
buildConfigField "String", "channel", "\"10000\""
}
app1 {//马甲包app
applicationId "com.example.baseslicedemo1"
versionName "1.0.0"
//马甲包不同的配置 可以在这里设置 我这里设置的是渠道 可以自行配置
buildConfigField "String", "channel", "\"10001\""
}
}
//jenckins 自动化多渠道打包配置
applicationVariants.all { variant ->
variant.outputs.all { output ->
def newName
newName = "${applicationId}-" + variant.buildType.name + ".apk"
outputFileName = new File(newName)
println "outputPath:" + variant.getPackageApplication().outputDirectory
}
variant.assemble.doLast {
println "outputPath:" + variant.getPackageApplication().outputDirectory + "/output.json"
delete "${variant.getPackageApplication().outputDirectory}/output.json"
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation project(path: ':base')
}
上面就是打包的命令,可以一键打出所有马甲包,也可以单独打,通过配置不同的路径资源,还可以打出不同名字和资源的马甲包下面就是安装后的应用
主包和马甲包1。
因为我设置了不同的渠道,不同的应用名,和颜色的不同,下面是应用打开后
经过上面的配置和操作之后,就可以保证在同一套代码的情况下打出不同包名的应用,只需要改改app名字、资源、颜色就可以上架了是不是很简单。
下面就是进阶版了,和包名密切相关的功能。
我们正常的开发中会遇到微信登录和支付,支付宝支付是没有问题的,微信的登录和支付会回调给包名路径下面的Activity,这种情况下有两种方案可以实现,
1、是在项目里面创建一个和马甲包的包名一样的文件路径,例如:
2、就是现在比较流行的组件化,组件的包名要和马甲包的包名一样,我推荐是这样做,这样可以把需要验证包名、或者依赖包名回调的SDK都可以。比如,阿里的面部识别SDK 组件化怎么实现就不多做介绍了,不会的同学去看看组件化是怎么实现的。
这里还有一个问题,Android 多渠道打包-马甲、白皮包无法安装在同一手机的问题。
经过排查之后发现不是applicationId的问题造成的,网上也没其他解决办法,最后发现解决办法是
自定义provider的问题。发生错误的代码:
// 自定义provider
<provider
android:name=".utils.MyFileProvider"
android:authorities="com.xxx.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
如上,authorities中属性,一开始没注意写的com.xx.xx也就是自己取的自定义的名字
改为如下:
// 自定义provider
<provider
android:name=".utils.MyFileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
或者直接将provider放到上面提到的组件化里面去,就不会有这个问题了 。
Demo地址
https://github.com/lixuce248/VestBagDemo.git
当你下定决心,准备前行的时候,剩下的只有坚持了。。。
大家如果觉得我写的还可以的话,请关注我的微信公众号