Android 多版本 多渠道打包

作者: 听话哥 | 来源:发表于2019-05-06 15:19 被阅读19次

    在平时的Android开发中,基于某些需求我们可能要针对一份APK代码打出多个不同的APK包来实现一些通过换肤换名称达到不同APK发布的效果,然后针对这些不同APK再进行一次打多个渠道包等需求,该怎么样通过一份代码一次性打出多个APK包?如何快速的打出多个渠道包?这是我们需要去研究并解决的问题。

    一、简述

    1.多版本

    基于productFlavors
      本身productFlavors是一个多渠道打包方式,为了能够替换资源我们把不同版本APK包通过这个方式来区分,这里我们简单用GanHuo和GanHuo2来作为两个不同APP

    2.多渠道

      多渠道打包方式可以参考我的之前一篇关于Python多渠道打包方式

    二、示例

    1.配置build.gradle

    (1)配置app目录下面的build.gradle文件

    GanHuo {
                applicationId "com.ganhuo"
                resValue "string", "appName", '"干货"'
                buildConfigField "boolean", "AUTO_UPDATES", "false"
                manifestPlaceholders = [
                        app_name    : "Ganhuo",
                        app_icon    : "@mipmap/icon",
                        appid       : "com.ganhuo",
                        umeng_secret: "***",
                        app_scheme  : "ganhuo"
                   ]
            }
    
            GanHuo2{
                applicationId "com.ganhuo2"
                resValue "string", "appName", '"干货2"'
                manifestPlaceholders = [
                        app_name: "GanHuo2",
                        app_icon: "@mipmap/icon",
                        appid: "com.ganhuo2",
                        umeng_secret: "***",
                        app_scheme  : "ganhuo2"
                ]
            }
    

    manifestPlaceholders里面相关的参数可以让我们在manifest通过占位符的方式去替换

    <application
            android:name=".Application"
            android:allowBackup="false"
            android:hardwareAccelerated="true"
            android:icon="${app_icon}"
            android:label="${app_name}"
            android:largeHeap="true"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:theme="@style/ApplicationTheme">
    <activity
                android:name=".MainActivity"
                android:hardwareAccelerated="true"
                android:launchMode="singleTask">
                <intent-filter>
                    <action android:name="android.intent.action.VIEW" />
    
                    <category android:name="android.intent.category.DEFAULT" />
                    <category android:name="android.intent.category.BROWSABLE" />
                    <data android:scheme="${app_scheme}" />
                </intent-filter>
            </activity>
    <!-- 友盟Appkey -->
            <meta-data
                android:name="UMENG_APPKEY"
                android:value="${umeng_secret}" />
        </application>
    

    (2)定义res对象

    在build.gradle 的productFlavors 里面定义String

    GanHuo {
            resValue "string", "appName", '"干货"'
    }
    

    然后在strings.xml文件里面引用

    <resources>
        <string name="app_name">@string/appName</string>`
    </resource>
    

    (3)定义变量
    我们有时候可能需要定义一些公共变量来判断是不是测试环境或者是生产环境,或者是需要一些公用变量,我们可以定义一个叫跟GanHuo同级的defaultConfig的标签,标签里面可以放所有现场共用的属性和变量,代码如下:

    android{
        defaultConfig{
            //存放公共变量
            buildConfigField 'Boolean', 'AUTO_UPDATES', 'true'
        }
        GanHuo{
           buildConfigField 'String', 'ENVIRONMENT', '"PRODUCT"'
        }
        GanHuo2{
          buildConfigField 'String', 'ENVIRONMENT', '"TEST"'
        }
    }
    

    (4)配置资源文件

    如果不同的渠道包需要不同的相关icon,可以通过下图的方式进行配置:


    image.png

    2.解除微信回调的Activity必须在包名.wxapi下的限制

    在分不同包名的时候,由于用到了微信授权、分享相关微信功能,微信回调的Activity必须在包名.wxapi,为了解决这个问题,我们需要创建多个包名,里面创建WxEntryActivity,然后在AndroidManifest注册多个activity。这样有新的包名就需要新增一个微信回调,非常繁琐。为了偷懒,我们需要有一劳永逸的方法。这时候想到了我们在处理provider的时候由于手机里面只允许同样的provider存在一个,所以我们做了相应的处理


    image.png

    有没有类似这种操作呢,这时候发现我们可以通过activity-alias的targetActivity来实现,代码如下:

    <!-- 微信分享回调 通过别名的方式来规避多个不同版本包需要新建多个微信回调文件问题-->
            <activity android:name=".base.AbsWXEntryActivity"
                android:configChanges="keyboardHidden|orientation|screenSize"
                android:exported="true"
                android:screenOrientation="portrait"
                android:theme="@android:style/Theme.Translucent.NoTitleBar" ></activity>
            <activity-alias
                android:name="${applicationId}.wxapi.WXEntryActivity"
                android:targetActivity=".base.AbsWXEntryActivity"
                android:configChanges="keyboardHidden|orientation|screenSize"
                android:exported="true"
                android:screenOrientation="portrait"
                android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity-alias>
    

    activity-alias里面的name只是一个虚拟的占位符而已,会被重定向到实际处理的targetactivity

    这里记录一下通过android studio 3.0编译过程中遇到的几个问题
    (1)Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com/r/tools/flavorDimensions-missing-error-message.html
    在使用android studio 3.0的时候,gradle版本需要升级到3.5版本才能编译。这个错误的大致意思是:所有的flavors都必须属于同一个风格。通过查阅了资料之后发现Plugin 3.0.0之后有一种自动匹配消耗库的机制,便于debug variant 自动消耗一个库,然后就是必须要所有的flavor 都属于同一个维度。为了避免flavor 不同产生误差的问题,应该在所有的库模块都使用同一个foo尺寸。对此,我也不是很理解,庆幸的是有给出解决方案

    在主app的build.gradle里面的
     defaultConfig {
     targetSdkVersion:***
    minSdkVersion :***
    versionCode:***
     versionName :***
    //版本名后面添加一句话,意思就是flavor dimension 它的维度就是该版本号,这样维度就是都是统一的了
    flavorDimensions "versionCode"
    
    }
    

    (2)gradle 打包
      gradle打包,自定义apk名称代码报错(Cannot set the value of read-only property ‘outputFile’ )
    Error:(56, 0) Cannot set the value of read-only property ‘outputFile’ for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=debug, filters=[]}} of type com.android.build.gradle.internal.api.ApkVariantOutputImpl.
    解决:在app的buide.gradle修改3.0之前输出自定义apk名字的代码,代码如下:

    //3.0之前打包输出自定义apk名称代码
        applicationVariants.all { variant ->
            variant.outputs.each { output ->
                def outputFile = output.outputFile
                if (outputFile != null && outputFile.name.endsWith(".apk")) {
                    def fileName = "Android_${variant.productFlavors[0].name}_v${defaultConfig.versionName}.apk"
                    output.outputFile = new File(outputFile.parent, fileName)
                }
            }
        }
    //3.0之后打包输出自定义apk名称代码
        android.applicationVariants.all { variant ->
            variant.outputs.all {
                outputFileName = "Android_${variant.productFlavors[0].name}_v${defaultConfig.versionName}.apk"
            }
        }
    

    如果需要修改manifest内容,可以看我这篇文章通过gradle 动态修改AndroidManifest.xml文件

    相关文章

      网友评论

        本文标题:Android 多版本 多渠道打包

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