美文网首页Android开发学习面试题安卓
Android:如何优雅的开发马甲包?

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

作者: ba98026b9558 | 来源:发表于2019-08-05 17:18 被阅读39次

    什么是马甲包呢?

    简而言之,同样的代码,包装成不同的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,只需要一个打包的时间,最多五分钟,大大节省时间,及时项目维护,只需要修改一套代码,这才是真正的马甲包!


    相关文章

      网友评论

        本文标题:Android:如何优雅的开发马甲包?

        本文链接:https://www.haomeiwen.com/subject/nmzmdctx.html