android多渠道包(風味包)——安卓gradle

目錄
一、前言
二、我們需要解決的問題
1、所要達到的效果
2、需要解決的問題
三、編碼時刻
四、效果演示
五、寫在最後

一、前言

經過前幾篇 安卓gradle 文章的介紹,童鞋們應該對 安卓gradle 更加熟悉了。
1、defaultConfig——安卓gradle
2、buildTypes——安卓gradle
3、flavorDimensions和productFlavors——安卓gradle

這幾篇文章中,我們或多或少的提到 “渠道包” 和 “風味包” ,今天我們就來分享下,如何機遇一套代碼,編譯出多個 “可以並存” 且 “存在有些許差異” 的apk包。

完整代碼:github傳送,如果對你有幫助,給個star吧。

二、我們需要解決的問題

我們先理清楚做這件事情所要達到的效果 和 中間存在的問題

1、所要達到的效果

  • 一套核心代碼編譯出多個 “可以並存” 的apk包
  • 可以有差異化,eg:logo、app名字、簽名、統計渠道 等可以根據不同的apk有些許不同
  • 易維護,耦合度低

2、需要解決的問題

根據我們需要想要達到的效果,我們需要解決以下幾個問題

  • 能夠配置多個 applicationId
  • 能夠動態的設置 AndroidManifest.xml 中的數據
  • 能夠使用不同的資源,但又不污染核心代碼
  • 能夠實現差異化邏輯

接下來我們就來解決這些問題,達到我們預期的效果

三、編碼時刻

1、建立 維度 和 風味

對 維度 和 風味 陌生的童鞋,可以移步查看小盆友的另一片博文:flavorDimensions和productFlavors——安卓gradle

我們進入應用級的 build.gradle 中,增加以下代碼

android {
    // 省略其他代碼...

	// 創建風味維度
    flavorDimensions('abi')
    productFlavors {
       	x86 {
       		// 創建維度
            dimension 'abi'
        }

        armV7 {
            dimension 'abi'
        }
    }
}

至此,我們可以編譯出兩個apk包:“x86” 和 “armV7”。從編譯器的提示,我們也可以看出已經有 四種變體

因爲 “x86” 和 “armV7” 兩個風味各自都默認有 “release” 和 “debug” 兩種編譯類型,所以 2x2 則有 四種變體。

2、讓兩種風味並存

我們需要給他們各自定一個 applicationId ,這樣纔可以並存不衝突。

android {
    // 省略其他代碼...

	// 創建風味維度
    flavorDimensions('abi')
    productFlavors {
       	x86 {
       		// 創建維度
            dimension 'abi'

			// 配置 風味的applicationId
			applicationId 'com.zinc.bear'
        }

        armV7 {
            dimension 'abi'
            
			applicationId 'com.zinc.shark'
        }
    }
}

這樣第一個問題解決了!!😊很簡單吧,繼續前行。 但此時運行起來,是兩個完全相同的apk,還沒進行差異化的配置。

3、動態的設置 AndroidManifest.xml 中的數據

通過使用 manifestPlaceholders 達到這一效果

首先還是在 build.gradle 中添加以下代碼

productFlavors {
	x86 {
	   dimension 'abi'
	
	   applicationId 'com.zinc.bear'
	
	   manifestPlaceholders = [
			hostName: "www.x86.com",
			logo    : "@drawable/logo",
			appName : "bear",
	   ]
	}
	
	armV7 {
	    dimension 'abi'
	
	    applicationId 'com.zinc.shark'
	
	    manifestPlaceholders = [
			hostName: "www.armv7.com",
			logo    : "@drawable/logo",
			appName : "shark",
	    ]
	}
}

接着我們進入 AndroidManifest.xml 中,進行替換 logo 和 app名字,還有設置了一個 meta-data 的參數。

我們在 AndroidManifest.xml 中使用 manifestPlaceholders 的參數規則爲 ${參數名字},具體完整代碼如下

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zinc.flavordemo">

    <application
        android:allowBackup="true"
        android:icon="${logo}"
        android:label="${appName}"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data android:name="host" android:value="${hostName}"/>
    </application>

</manifest>

我們選擇 “Merged Manifest”(此時爲 armV7Debug 變體),可以看到 Android Studio 已經將我們設置的參數替換爲真實的參數。

至此,我們解決了第二個問題 “能夠動態的設置 AndroidManifest.xml 中的數據”。

3、使用不同的資源

不同的apk,當然會出現 同個地方,使用同樣的資源名,但又要表現不同(emmm,很繞😂),我們舉個例子,細心的童鞋會發現我們 logo 的資源名是一樣的,我們接下來看看如何配置。

這裏的 配置有兩種方法 ,小盆友就自作主張的起兩個名字: “文件夾配置”“Library 配置”。我們接下來一一展示。

3.1 文件夾配置

(1)我們在跟 main 同級 的地方建立和 風味一樣名字 的文件夾,這裏使用 “armV7” 作爲例子,則命名爲 armV7。然後按照和 main 文件夾同樣的格式建立結構,具體如下圖。

(2)最後將我們的 logo.png 圖片放入 drawable 中即可。在編譯包時,會將armV7 文件夾中的資源覆蓋在 main 中同名的資源。

(3)這種方式也同樣適用於其他資源。例如:此處我們也同樣建立了 strings.xml 文件,其中也寫入 app_name 的 string資源,最終編譯 armv7 時,形成的 app_name 則會爲 flavor_armv7。

armV7 下的 strings.xml 資源

main 下的 strings.xml 資源

3.2 Library 配置

(1)創建一個library,名稱沒有規定,這裏取名爲 “flavor_x86”。

(2)在 drawable 同樣放入 logo.png 的圖片,結構如下。

(3)最後在我們項目級的 build.gradle 中加入如下代碼,將其引入。注意此處不是使用 implementation, 而是使用 [風味名稱]+Implementation,這樣引入的 library 只會作用於該風味,例如此處只會作用於 x86 風味。

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

	// ...其他引入
	
	// 爲風味 x86 引入 library flavor_x86
    x86Implementation project(':flavor_x86')
}

(4)其他資源也同樣適用,和 “文件夾配置” 的第三小點是一樣的,就不贅述了。

3.3 兩種方法的比較

小盆友個人比較喜歡 “Library 配置” 的方法,在真實的項目中也是使用這方案。

主要考慮到如下兩點:

  • 真正的解耦,因爲 “文件夾配置” 這一方案在小盆友看來,其實和 “main”文件夾(核心代碼)還是有共用一些資源,例如 build.gradle。
  • 易去除,“Library 配置” 方案在移除或更換依賴的 Library 時,非常簡單,只需要更改 [風味名]Implementation 所引入的 Library。

4、能夠實現差異化邏輯

聰明的童鞋其實已經發現,我們在第三小點中,有存在一個 “java” 的文件夾,我們只需要保持每個風味都存在相同的類即可(類路徑要完全一樣,這樣切換不同的風味包都不需要任何更換邏輯)。

4.1 代碼時刻

我們需要在不同的風味包中調用如下代碼,但又要避免污染核心代碼。

// armv7 風味包
public class LogicUtils {
    public static String calculate(int a, int b) {
        return "armv7:" + (a + b);
    }
}

// x86 風味包
public class LogicUtils {
    public static String calculate(int a, int b) {
        return "x86:" + (a + b);
    }
}

使用方法

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tvContent = findViewById(R.id.tv_content);
        tvContent.setText("LogicUtils:" + LogicUtils.calculate(1, 2));
    }
}

項目結構

至此,我們第四個問題就解決了。

四、效果演示

完整代碼:github傳送,如果對你有幫助,給個star吧。

4.1 運行效果

4.2 並存效果

4.3 兩個應用


五、寫在最後

如果喜歡的話請給我一個贊,並關注我吧。文章中如有寫的不妥的地方,請評論區或加我微信與我討論吧,共同進步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章