manifestPlaceholders
是 Android 开发中一个非常有用的配置项,主要用于在构建过程中动态替换 AndroidManifest.xml 文件里的占位符,可以在不修改AndroidManifest.xml文件的情况下,动态的配置应用的各种信息,提高开发和打包的灵活性。
1、使用场景
-
多渠道打包:
在进行多渠道打包时,不同的渠道可能需要不同的配置信息,比如应用的统计渠道ID、第三方服务的APP Key等。通过
manifestPlaceholders
可以在打包时根据不同的渠道动态的替换这些信息。 -
环境区分:
在开发、测试、生产等不同的环境下,可能需要使用不同的服务器地址、API Key等配置。使用
manifestPlaceholders
可以方便的在不同环境下替换这些配置。
2、基本用法
在项目的build.gradle
文件中,通过defaultConfig
或者buildType
或者productFlavors
中定义manifestPlaceholders
来替换AndroidManifest.xml
文件中的占位符
1、 在清单文件中定义好代码中需要使用到的元数据
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Test1"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Test1">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 动态替换的元数据,值在gradle脚本中使用manifestPlaceholders替换为真正的值 -->
<meta-data
android:name="BUGLY_APPID"
android:value="${buglyAppId}" />
<!-- 配置APP版本号 -->
<meta-data
android:name="BUGLY_APP_VERSION"
android:value="${buglyAppVersion}" />
<!-- 配置APP渠道号 -->
<meta-data
android:name="BUGLY_APP_CHANNEL"
android:value="${buglyAppChannel}" />
<!-- 配置Bugly调试模式(true或者false)-->
<meta-data
android:name="BUGLY_ENABLE_DEBUG"
android:value="${buglyEnableDebug}" />
<!-- 动态替换的元数据,值在gradle脚本中使用manifestPlaceholders替换为真正的值 -->
</application>
</manifest>
2、在gradle文件中替换清单文件中的占位符
groove写法
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
}
android {
namespace 'com.lhy.test1'
compileSdk 34
defaultConfig {
applicationId "com.lhy.test1"
minSdk 21
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// 动态替换清单文件中的元数据
manifestPlaceholders = [
buglyAppId : 'a2131231',
buglyAppVersion : 1,
buglyAppChannel : 'm_debug',
buglyEnableDebug: true
]
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = '11'
}
buildFeatures {
compose true
}
}
dependencies {
implementation libs.androidx.core.ktx
implementation libs.androidx.lifecycle.runtime.ktx
implementation libs.androidx.activity.compose
implementation platform(libs.androidx.compose.bom)
implementation libs.androidx.ui
implementation libs.androidx.ui.graphics
implementation libs.androidx.ui.tooling.preview
implementation libs.androidx.material3
testImplementation libs.junit
androidTestImplementation libs.androidx.junit
androidTestImplementation libs.androidx.espresso.core
androidTestImplementation platform(libs.androidx.compose.bom)
androidTestImplementation libs.androidx.ui.test.junit4
debugImplementation libs.androidx.ui.tooling
debugImplementation libs.androidx.ui.test.manifest
}
kts写法
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
}
android {
namespace = "com.lhy.test2"
compileSdk = 34
defaultConfig {
applicationId = "com.lhy.test2"
minSdk = 21
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
// 动态替换清单文件中的元数据
manifestPlaceholders.putAll(
mapOf(
"buglyAppId" to "a2131231",
"buglyAppVersion" to "1",
"buglyAppChannel" to "m_debug",
"buglyEnableDebug" to "true"
)
)
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
compose = true
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
}
3、在代码中获取元数据
fun getAppMetaData(context: Context, key: String): String? {
return try {
val packageManager = context.packageManager
val applicationInfo =
packageManager.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA)
applicationInfo.metaData[key].toString()
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
null
}
}