如何在 AndroidManifest.xml 文件中访问 BuildConfig 的值?

177

是否可以从AndroidManifest.xml访问BuildConfig值?

在我的build.gradle文件中,我有:

defaultConfig {
    applicationId "com.compagny.product"
    minSdkVersion 16
    targetSdkVersion 21
    versionCode 1
    versionName "1.0"

    // Facebook app id
    buildConfigField "long", "FACEBOOK_APP_ID", FACEBOOK_APP_ID
}

FACEBOOK_APP_ID是在我的gradle.properties文件中定义的:

# Facebook identifier (app ID)
FACEBOOK_APP_ID=XXXXXXXXXX

为了在我的应用程序中使用Facebook连接,我必须将以下行添加到我的AndroidManifest.xml文件:

<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/applicationId"/> 

我想要用gradle中定义的FACEBOOK_APP_ID BuildConfig字段来替换@string/applicationId,就像这样:

<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="FACEBOOK_APP_ID"/> 

使用 BuildConfig 是否可能实现这一点?如果不行,我该如何实现?


我可以知道保留在构建中的任何具体原因吗?因为将FACEBOOK_APP_ID保留在构建或直接字符串中将产生相同的影响,并且在反编译后可见。是否有其他方法来在清单中安全地保护此密钥并访问它? - Anukool srivastav
7个回答

237

替换

buildConfigField "long", "FACEBOOK_APP_ID", FACEBOOK_APP_ID
resValue "string", "FACEBOOK_APP_ID", FACEBOOK_APP_ID

然后重新构建你的项目(Android Studio -> Build -> Rebuild Project)。

这两种命令都会在项目构建期间生成值 - 在第一种情况下,它们由Java常量组成;在第二种情况下,它们由Android资源组成。但是,第二种方法将生成一个string资源值,可以使用@string/FACEBOOK_APP_ID语法访问。这意味着它既可以在清单文件中使用,也可以在代码中使用。


1
这是我正在使用的确切代码,但我遇到了一个问题:由于某种原因,Facebook SDK将该字符串读取为整数,然后抛出ClassCastException,因为整数无法强制转换为字符串。有人遇到过这个问题吗? - W.K.S
它是一个字符串:<item name="facebook_app_id" type="string">15233522...</item> - W.K.S
那会创建一个语法错误 表达式期望 :/ - W.K.S
19
请确保您编写的是 resValue "string",而不是 resValue "String"。 - keybee
1
如果您想使用布尔值,请确保键入resValue“bool”而不是“boolean”-> https://www.tanelikorri.com/tutorial/android/set-variables-in-build-gradle/ - reavcn
显示剩余6条评论

100

另一种从AndroidManifest.xml访问Gradle Build Config值的方法是通过占位符,如下所示:

android {
    defaultConfig {
        manifestPlaceholders = [ facebookAppId:"someId..."]
    }
    productFlavors {
        flavor1 {
        }
        flavor2 {
            manifestPlaceholders = [ facebookAppId:"anotherId..." ]
        }
    }
}

然后在你的清单文件中:

<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="${facebookAppId}"/> 

请点击此处查看更多详细信息:https://developer.android.com/studio/build/manifest-build-variables.html (旧链接仅供参考:http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger

2
这是一个很棒的解决方案。 - BinaryShrub
2
是的,这是一种很好的仅清单字符串注入方法! - stkent
2
你如何在Java中从manifestPlaceholders获取值?这对于在Java代码和清单中使用的常量非常有用。 - Louis CAD
1
@LouisCAD 我没有尝试过,但你可以试一下以下方法: var placeholder = 'your placeholder'(换行) buildConfigField "String", "PLACEHOLDER_NAME", placeholder(换行) manifestPlaceholders = [ placeholderName:placholder](换行)如果这个方法对你有用,我会很高兴知道。 - GregoryK
如果我们需要从构建gradle文件中设置android:name字符串,该怎么办? - WISHY
显示剩余8条评论

60

注意: 当您使用 resValue 时,该值可能会意外被字符串资源文件(例如另一种语言)覆盖。

为了获取一个真正的常量值,您可以在清单和Java代码中使用manifestPlaceholdersbuildConfigField两者结合,例如:

android {
    defaultConfig {
        def addConstant = {constantName, constantValue ->
            manifestPlaceholders += [ (constantName):constantValue]
            buildConfigField "String", "${constantName}", "\"${constantValue}\""
        }

        addConstant("FACEBOOK_APP_ID", "xxxxx")
    }

在清单文件中授予权限:

<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="${FACEBOOK_APP_ID}"/>

来自Java:

BuildConfig.FACEBOOK_APP_ID
如果常量值需要特定于构建类型,则需要调整帮助程序addConstant(以使用groovy闭包语义),例如,
buildTypes {
    def addConstantTo = {target, constantName, constantValue ->
        target.manifestPlaceholders += [ (constantName):constantValue]
        target.buildConfigField "String", "${constantName}", "\"${constantValue}\""
    }
    debug {
        addConstantTo(owner,"FACEBOOK_APP_ID", "xxxxx-debug")
    }
    release {
        addConstantTo(owner,"FACEBOOK_APP_ID", "xxxxx-release")
    }

1
无法工作,显示应用程序 ID 无效,但当从 Java 设置时则可以工作。 - Brajendra Pandey
1
@GregEnnis 对我来说,更多的常量也可以正常工作:例如,我只需调用 addConstant() 两次(当然使用不同的 constantNames)。你遇到了什么错误? - TmTron
1
@TmTron,你不会收到错误提示,但是每次调用时都会重新分配整个“manifestPlaceholders”数组,只存储最后使用的值。 - Greg Ennis
@KristyWelsh 我不确定你做错了什么 - 可能只是一些语法错误。我建议你在 SO 上创建一个新的问题并发布你的配置。 - TmTron
@sniper:不确定你的意思。当然,您可以在gradle.build文件中访问属性文件如何读取属性文件并在项目Gradle脚本中使用值?。没有任何限制阻止您在gradle.build文件中的任何位置使用这些属性。 - TmTron
显示剩余7条评论

6

可以按照以下示例在清单文件中访问 build.gradle 属性:

例如,在 build.gradle 中有一个名为“applicationId”的属性,您想在 AndroidManifest 中访问该属性:

enter image description here

在 AndroidManifest 中访问 "applicationId":

<receiver
        android:name="com.google.android.gms.gcm.GcmReceiver"
        android:exported="true"
        android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="${applicationId}" />
        </intent-filter>
    </receiver>

同样地,我们可以为其他常量创建字符串资源,并在代码文件中简单地访问它们:
context.getString(R.string.GCM_SENDER_ID);

我可以在.properties文件中定义facebookAppId:“anotherId...”,并将存储密码和所有信息保存在其中吗?然后我可以在manifestplaceholders中访问这些,它们会间接地被访问到AndroidManifest.xml中。我可以这样做吗? - Aman Verma

3
@stkent的建议很好,但他忘了提到你需要在之后重新构建你的项目。
替换
buildConfigField "long", "FACEBOOK_APP_ID", FACEBOOK_APP_ID

使用

resValue "string", "FACEBOOK_APP_ID", FACEBOOK_APP_ID

那么

Android Studio -> Build -> Rebuild Project

这将使Android生成可通过以下方式访问的字符串资源:

R.string.FACEBOOK_APP_ID

1
无法获取 ProductFlavor_ 的未知属性 'FACEBOOK_APP_ID' - f.trajkovski

1
另一种选择:使用不同的字符串资源文件替换所有依赖于Flavor的值:
步骤1: 在“src”文件夹中创建一个名为您的Flavor名称的新文件夹,例如我的是“stage”。
步骤2: 为所有依赖于Flavor的文件创建资源文件,例如:

enter image description here

第三步: 我还使用了不同的图标,所以您也会看到mipmap文件夹。对于这个问题,只有“strings.xml”是重要的。现在您可以覆盖所有重要的字符串资源。您只需要包含要覆盖的那些,其他所有内容都将从主“strings.xml”中使用,它将在Android Studio中显示如下:

enter image description here

第四步:在您的项目中使用字符串资源,放松心情:

enter image description here


一个很好的选择,特别是如果您需要为每个变体设置许多其他字符串。 - stkent
我能否在 .properties 文件中定义 facebookAppId:“anotherId…”,并将我的商店密码和所有内容保存在其中。然后,在 manifestplaceholders 中访问这些文件,间接地访问 AndroidManifest.xml。我可以这么做吗? - Aman Verma

0
你可以如下使用 long 值:

buildConfigField 'long', 'FLAVOR_LONG', '11500L'


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接