Android:如何优雅的开发马甲包?

什么是马甲包呢?

简而言之,同样的代码,包装成不同的APP,就是马甲包。对于开发者来说代码被盗用被包装成马甲包是很气人了,所以建议大家注意自己代码的保护!

那么问题来了,真的有需要要开发不同的马甲包(咱也不知道为啥,就是有这种需求)该怎么开发呢?
看了很多方案最多的就是复制一套代码,修改包名,当然是可行的,但是也有一个弊端,马甲包越多,代码越多,版本越多,马家项目越多,一次更新要修改很多马甲包,这样维护会死人的,亲身经历!
如何优雅的开发马甲包呢?前提是一套代码!

马甲包开发,首先要了解android怎么区分不同的APP,作为开发者当然第一反应就是PackageName,这样说虽然也对,但是并不严谨,为了这个问题,我特意询问了应用商店的客服(毕竟马甲包也是为了上架),新建应用的包名是applicationID,还是PackageName,当然客服的回答并不理想,他们也不熟悉,然而我们去查看android的开发者文档,会明确的告诉你,android应用是根据applicationID区分的,只不过用早期eclipse开发项目时没有applicationID和PackageName的区分,就默认二者是一样的,到了android studio开发时,二者默认也是一样的,但是也可以不一样,那么我们就可以通过修改applicationID来打包不同的马甲包,接下来介绍马甲包需要修改的地方如何修改。

APP名称、icon怎么修改呢?

这个问题不算大问题,渠道打包就是用来做这个事情的,同时也可以配置applicationID。(具体往下看,有代码

微信分享支付、支付宝支付会有影响吗?

微信分享和支付都是会有影响的,支付宝是没有影响的,我们只需要在项目中新建和applicationID一致的项目把回调的文件放进去就可以了(见AndroidManifest最后的说明,需要自己在项目中创建,这里只贴出AndroidManifest配置

最复杂的就是某些sdk跟签名绑定的(例如:阿里人脸识别)怎么接入项目呢?

当然是采用组件化开发啦,就是把不同签名的sdk,作为一个model引入项目,就可以啦。

OK,原理已经描述完了,不知道是否能看懂,下面贴代码:

注:文件为保证隐私,有删除部分代码,需要理解自行修改

build.gradle文件:
apply plugin: 'com.android.application'

def getInteger(String name) {
    def versionFile = file('flavors.properties')
    if (versionFile.canRead()) {
        Properties versionProps = new Properties()
        versionProps.load(new FileInputStream(versionFile))
        return versionProps[name].toInteger()
    } else {
        throw new GradleException("Could not find flavors.properties!")
    }
}

def getString(String name) {
    def versionFile = file('flavors.properties')
    if (versionFile.canRead()) {
        Properties versionProps = new Properties()
        versionProps.load(new FileInputStream(versionFile))
        return versionProps[name].toString()
    } else {
        throw new GradleException("Could not find flavors.properties!")
    }
}
//根据自己需要自定义
//APPname 需要在此文件下修改,flavors.properties中配置会导致中文乱码,
//英文就无所谓,虽然试了修改编码,但是没有成功
def app_name = "马甲包名称"
def app_icon = getString('myicon')
def wechat_app_id = getString('wechat_app_id')
def wechat_app_secret = getString('wechat_app_secret')
def amap_kay = getString('amap_kay')
def umeng_appkey = getString('umeng_appkey')
def application_id = getString('application_id')
def version_name = getString('version_name')
def version_code = getInteger('version_code')

android {
    compileSdkVersion 28
    buildToolsVersion "28.0.0"
    defaultConfig {
        applicationId application_id
        minSdkVersion 18
        targetSdkVersion 28
        versionCode version_code
        versionName version_name
        flavorDimensions vest
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
        ndk { abiFilters 'armeabi'}
       
    }

    dexOptions {
        jumboMode = true
    }

    buildTypes {
        applicationVariants.all { variant ->
            variant.outputs.all { output ->
                def outputFile = output.outputFile
                if (outputFile != null && outputFile.name.endsWith('.apk')) {
                    def date = new Date().format("yyMMddHHmm")
                    def fileName = app_name + "-" + vest + "-${variant.productFlavors[0].name}-${versionName}(${versionCode})-${date}.apk"
                    outputFileName = fileName
                }
            }
        }
    }
    aaptOptions.cruncherEnabled = false
    aaptOptions.useNewCruncher = false
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    productFlavors {
         //具体渠道打包配置不在详细说明,自己google一大堆
//小米渠道
XiaoMi {
            applicationId application_id    //区别不同的APP的 “PackageName”
            resValue "string", "wechat_app_id", wechat_app_id  //微信应用app_id
            resValue "string", "wechat_app_secret", wechat_app_secret   //微信应用app_secret
            manifestPlaceholders = [
                    UMENG_CHANNEL_VALUE: "Android_xiaomi",//渠道名称
                    AMAP_APPKEY        : amap_key,                //高德APP key
                    UMENG_APPKEY       : umeng_appkey,      //umegn APP key
                    MY_LABEL           : app_name,                     //马甲包 应用名称
                    MY_ICON            : app_icon                           //马甲包 应用图标
            ]
        }
        HuaWei {.......}
        Vivo {.......}
        Oppo {....... }
        MeiZu {.......}
        Tencent {.......}
        Q360 {....... }
        AnZhi {....... }
        WanDouJia {.......}
    }
    //此处说明,下面的目录说明是lib和aar的引用,必须修改
    //此修改说明:指定lib可以指向的文件夹,
    //'libs' = 本项目的lib
    // '../'+getString('module_path')+'/libs' 通过配置修改的其他model下的lib
    sourceSets {
        main {
            jniLibs.srcDirs 'libs', '../'+getString('module_path')+'/libs'
        }
    }
    repositories {
        flatDir {
            dirs 'libs', '../'+getString('module_path')+'/libs'
        }
    }
}

dependencies {
//多余的已经删除
    api(name: 'aar_name', ext: 'aar')
    //需要同时修改setting.gradle 下面会贴出代码
    implementation project(':module1')
//    implementation project(':module2')
    //implementation project(':module3')
//    implementation project(':module4')
}

需要自己新建在proguard-android.txt同样的目录下

flavors.properties文件:
################################################################################
############################共用参数共用参数共用参数共用参数#############################################
############################共用参数共用参数共用参数共用参数#############################################
############################共用参数共用参数共用参数共用参数#############################################
############################共用参数共用参数共用参数共用参数#############################################
############################共用参数共用参数共用参数共用参数#############################################
################################################################################
version_code = 1
version_name = 1.0.0
amap_kay = **************************
################################################################################
module_path = module1
myicon = @drawable/logo1
umeng_appkey = *********************1
application_id = com.*****.*****1
wechat_app_id = *********************1
wechat_app_secret = *********************1
################################################################################
#module_path = module2
#myicon = @drawable/logo2
#umeng_appkey = *********************2
#application_id = com.*****.*****2
#wechat_app_id = *********************2
#wechat_app_secret = *********************2
#打包时其他马甲包的配置需要注释!!!
################################################################################

setting.gradle文件:

//根据不同的包名选择不同的module
include ':YouApp', ':module1'
//include ':YouApp', ':module2'
//include ':YouApp', ':module3'
//include ':YouApp', ':module4'

这些model自己可以随便新建,注意setting.gradle需要自己修改,因为新建时会自动修改
说明:model中的资源可以在项目中直接引用,不必和application一致,一致会造成build冲突

AndroidManifest.XML文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.package">
    <!-- 此处包名和项目包名一致,和applicationID不必一致 -->
    <application
        android:name=".application.Application"
        android:allowBackup="true"
        android:icon="${MY_ICON}"
        android:label="${MY_LABEL}"
        android:persistent="true"
        android:supportsRtl="true"
        android:networkSecurityConfig="@xml/network_security_config"
        android:theme="@style/AppTheme"
        tools:replace="android:label,android:supportsRtl,android:allowBackup">
        <!--除了上面的package=‘’ 以外所有用到sdk文件需要用到包名,全部用 ${applicationId}   如下:${applicationId}.fileprovider-->
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>
        <uses-library
            android:name="org.apache.http.legacy"
            android:required="false" />

        <!-- 高德定位设置key -->
        <!-- 设置key -->
        <meta-data
            android:name="com.amap.api.v2.apikey"
            android:value="${AMAP_APPKEY}" />
        <!-- 友盟统计 -->
        <meta-data
            android:name="UMENG_APPKEY"
            android:value="${UMENG_APPKEY}" />
        <meta-data
            android:name="UMENG_CHANNEL"
            android:value="${UMENG_CHANNEL_VALUE}" />
        <meta-data
            android:name="android.max_aspect"
            android:value="2.2" />
        <!-- 极光配置举例: -->
        <service
            android:name="cn.jpush.android.service.DaemonService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="cn.jpush.android.intent.DaemonService" />
                <category android:name="${applicationId}" />
            </intent-filter>
        </service>
        
        <!-- 微信配置举例 -->
        <activity
            android:name=".wxapi.WXPayEntryActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:screenOrientation="portrait" />
        <activity
            android:name=".wxapi.WXEntryActivity"
            android:configChanges="keyboardHidden|orientation|screenSize"
            android:exported="true"
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.Translucent.NoTitleBar" />

        <!-- 微信配置举例  马甲包1-->
        <activity
            android:name="com.package1.wxapi.WXPayEntryActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:screenOrientation="portrait" />
        <activity
            android:name="com.package1.wxapi.WXEntryActivity"
            android:configChanges="keyboardHidden|orientation|screenSize"
            android:exported="true"
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.Translucent.NoTitleBar" />
        
        <!-- 微信配置举例 马甲包2-->
        
        <activity
            android:name="com.package2.wxapi.WXPayEntryActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:screenOrientation="portrait" />
        <activity
            android:name="com.package2.wxapi.WXEntryActivity"
            android:configChanges="keyboardHidden|orientation|screenSize"
            android:exported="true"
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.Translucent.NoTitleBar" />
    </application>
</manifest>

至此,除了个别SDK需要跟签名绑定,新建了几个model,可以通过修改引用,达到通过配置文件控制的目的,这样开发一个马甲包如果不需要特别的sdk,只需要一个打包的时间,最多五分钟,大大节省时间,及时项目维护,只需要修改一套代码,这才是真正的马甲包!


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值