Android 多版本 多渠道打包

在平時的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文件

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容