Set a global variable in gradle that can use in manifest file - android

I want to create a global variable similar with applicationId.
It is set value in build.gradle and will be used in manifest. Is it possible?

You can set them, for instance I'm setting it for different product flavors
productFlavors {
production {
applicationId = "com.myapp.app"
resValue "string", "authority", "com.facebook.app.FacebookContentProvider5435651423234"
}
development {
applicationId = "com.myapp.development"
resValue "string", "authority", "com.facebook.app.FacebookContentProvider2134564533421"
}
qa {
applicationId = "com.myapp.qa"
resValue "string", "authority", "com.facebook.app.FacebookContentProvider29831237981287319"
}
}
And use it like this
<provider
android:name="com.facebook.FacebookContentProvider"
android:authorities="#string/authority"
android:exported="true" />

If you just want to use the application id set in gradle in your manifest, you can simply use:
${applicationId}
For instance:
<provider
android:authorities="${applicationId}.ShareFileProvider" ... >
...
</provider>
If you want the same behavior with custom variables, you can use manifestPlaceholders, like this:
android {
defaultConfig {
manifestPlaceholders = [hostName:"www.example.com"]
}
}
And in your manifest:
<intent-filter ... >
<data android:scheme="http" android:host="${hostName}" ... />
...
</intent-filter>
See https://developer.android.com/studio/build/manifest-build-variables.html for more information.

While Marko's answer seems to work, there's currently a better solution that doesn't require adding variables to the string resource files.
The manifest merger accepts placeholders:
For custom placeholders replacements, use the following DSL to
configure the placeholders values :
android {
defaultConfig {
manifestPlaceholders = [ activityLabel:"defaultName"]
}
productFlavors {
free {
}
pro {
manifestPlaceholders = [ activityLabel:"proName" ]
}
}
will substitute the placeholder in the following declaration :
<activity android:name=".MainActivity" android:label="${activityLabel}" >
You can also manipulate those strings with groovy functions.

To use the string in Manifest, you can directly make it in strings.xml.
Like this,
<string name="variable_name">value</string>

Related

Default Activity Not Found with two different dimensions

I needed to use two different dimensions in the project. But after this usage, whatever I do, Android Studio tells me "Default Activity Not Found". Actually there's no changes in the src folder because I don't need to modify any classes in the flavors.
flavorDimensions "device", "backend"
productFlavors {
dev {
buildConfigField "String", "API_VERSION", "\"1.1\""
...extra configs
dimension "backend"
}
staging {
buildConfigField "String", "API_VERSION", "\"1.1\""
...extra configs
dimension "backend"
}
prod {
buildConfigField "String", "API_VERSION", "\"1.1\""
...extra configs
dimension "backend"
}
android {
buildConfigField "String", "DEVICE_TYPE", "\"ANDROID\""
dimension "device"
}
huawei {
buildConfigField "String", "DEVICE_TYPE", "\"ANDROID_HW\""
versionCode 10000 + defaultConfig.versionCode
dimension "device"
}
}
main/AndroidManifest.xml:
<application
android:name=".XApplication"
...
<activity
android:name=".ui.SplashActivity"
android:theme="#style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
In AndroidManifest.xml, change the android:name attribute of your activity to the fully-qualified class name of your Activity, instead of using the .ui.SplashActivity notation. When you prefix the name with ., it will append that to the package annotation of your <manifest> attribute, which may or may not match the package of your actual Activity class. Make sure your Activity class has the correct package declaration at the top of the file and is located in the right src directory.
The same goes for your Application class name. I avoid using the . notation at all costs.

Use variables in manifest

Integrating some libraries like Branch-io in Android need to define meta-data in the project manifest. some of these variables are like TestMode
<meta-data android:name="io.branch.sdk.TestMode" android:value="true" />
So, when we want to publish the application we should change it to False.
Is there any way to define a variable somewhere according to BuildType and assign it to the Meta-data to that?
You can do it by adding manifestPlaceholders to your build.gradle file:
android {
...
buildTypes {
debug {
manifestPlaceholders = [isBranchSdkInTestMode:"true"]
...
}
release {
manifestPlaceholders = [isBranchSdkInTestMode:"false"]
...
}
}
...
}
In AndroidManifest.xml, you can use it as ${isBranchSdkInTestMode}:
<meta-data android:name="io.branch.sdk.TestMode" android:value="${isBranchSdkInTestMode}" />
Yes you can inject build variables from gradle to manifest, it is done by adding variable to the build.gradle:
android {
defaultConfig {
manifestPlaceholders = [hostName:"www.example.com"]
}
deployConfg {
manifestPlaceholders = [hostName:"www.prod-server.com"]
}
...
}
And then in your manifest you can get it by:
<intent-filter ... >
<data android:scheme="http" android:host="${hostName}" ... />
...
</intent-filter>
You can read more about how this works here.

How can I access a BuildConfig value in my AndroidManifest.xml file?

Is it possible to access a BuildConfig value from AndroidManifest.xml?
In my build.gradle file, I have:
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 is defined in my gradle.properties files:
# Facebook identifier (app ID)
FACEBOOK_APP_ID=XXXXXXXXXX
To use Facebook connect in my app, I must add this line to my AndroidManifest.xml:
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="#string/applicationId"/>
I want to replace #string/applicationId by the BuildConfig field FACEBOOK_APP_ID defined in gradle, like this:
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="FACEBOOK_APP_ID"/>
Is that possible using BuildConfig? If not, how can I achieve this?
Replace
buildConfigField "long", "FACEBOOK_APP_ID", FACEBOOK_APP_ID
with
resValue "string", "FACEBOOK_APP_ID", FACEBOOK_APP_ID
then rebuild your project (Android Studio -> Build -> Rebuild Project).
The two commands both produce generated values - consisting of Java constants in the first case, and Android resources in the second - during project builds, but the second method will generate a string resource value that can be accessed using the #string/FACEBOOK_APP_ID syntax. This means it can be used in the manifest as well as in code.
Another way to access Gradle Build Config values from your AndroidManifest.xml is through placeholders like this:
android {
defaultConfig {
manifestPlaceholders = [ facebookAppId:"someId..."]
}
productFlavors {
flavor1 {
}
flavor2 {
manifestPlaceholders = [ facebookAppId:"anotherId..." ]
}
}
}
and then in your manifest:
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="${facebookAppId}"/>
See more details here: https://developer.android.com/studio/build/manifest-build-variables.html
(Old link just for reference: http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger)
note: when you use resValue the value can accidentally be overridden by the strings resource file (e.g. for another language)
To get a true constant value that you can use in the manifest and in java-code, use both manifestPlaceholders and buildConfigField: e.g.
android {
defaultConfig {
def addConstant = {constantName, constantValue ->
manifestPlaceholders += [ (constantName):constantValue]
buildConfigField "String", "${constantName}", "\"${constantValue}\""
}
addConstant("FACEBOOK_APP_ID", "xxxxx")
}
access in the manifest file:
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="${FACEBOOK_APP_ID}"/>
from java:
BuildConfig.FACEBOOK_APP_ID
If the constant value needs to be buildType-specific, the helper addConstant needs to be tweaked (to work with groovy closure semantics), e.g.,
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")
}
Access build.gradle properties in your manifest as in following example:
For example you have a property "applicationId" in your build.gradle and you want to access that in your AndroidManifest:
Access "applicationId" in AndroidManifest:
<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>
Similarly, we can create string resources for other constants and access them in code files as simple as:
context.getString(R.string.GCM_SENDER_ID);
#stkent is good but forgets to add that you need to rebuild your project afterwards
Replace
buildConfigField "long", "FACEBOOK_APP_ID", FACEBOOK_APP_ID
with
resValue "string", "FACEBOOK_APP_ID", FACEBOOK_APP_ID
then
Android Studio -> Build -> Rebuild Project
This will allow android generate the string resource accessible via
R.string.FACEBOOK_APP_ID
Another option: use a different string resource file to replace all Flavor-dependent values:
Step 1:
Create a new folder in the "src" folder with the name of your flavor, im my case "stage"
Step 2:
Create resource files for all files that are dependent on the flavor
for example:
Step 3:
I am also using different icons, so you see the mipmap folders as well. For this quetion, only the "strings.xml" is important. Now you can overwrite all important string resources. You only need to include the ones you want to override, all others will be used from the main "strings.xml", it will show up in Android Studio like this:
Step 4:
Use the string resources in your project and relax:
You can use long value as below
buildConfigField 'long', 'FLAVOR_LONG', '11500L'

Android - Manifest placeholders for different build types

I am very hyped about the new possibility of manifest placeholders in Gradle + Android Build. I've found in the gradle documentation that I can specify my own placeholders like this:
productFlavors {
free {
}
pro {
manifestPlaceholders = [ activityLabel:"proName" ]
}
}
But I would like to have one placeholder dependent on build type and not on product flavors. When I insert that placeholder specification into build type settings it takes no effect. Do you know how to achieve this? Because it seems to me stupid have three build types and three flavors associated with it. Thanks
This is my solution for different product flavours:
build.gradle:
productFlavors {
normal {
applicationId "mobi.cwiklinski.urc"
buildConfigField "String", "providerAuthority", "\"mobi.cwiklinski.urc.provider\""
resValue "string", "authorities", "mobi.cwiklinski.urc.provider"
}
adfree {
applicationId "mobi.cwiklinski.urc.adfree"
buildConfigField "String", "providerAuthority", "\"mobi.cwiklinski.urc.adfree.provider\""
resValue "string", "authorities", "mobi.cwiklinski.urc.adfree.provider"
}
}
AndroidManifest.xml
<provider
android:name="mobi.cwiklinski.urc.provider.AppProvider"
android:authorities="#string/authorities"
android:exported="true"
android:label="#string/app_name"
android:syncable="true"
android:writePermission="mobi.cwiklinski.urc.permission.USE_PROVIDER" />
And that's all - in different product flavours you will get different resource value.
Starting today with gradle plugin 0.13.0 is already working.

Use package name in XML

I'm using Android Studio to build my application. I would like to use gradle buildTypes. I add a suffix to the package name with applicationIdSuffix to modify the package name for a test build type.
buildTypes {
debug {
runProguard false
proguardFile 'proguard-rules.txt'
applicationIdSuffix '.dev'
versionNameSuffix '-dev'
}
}
Is it possible to use this information in a xml file. My plan is to modify the account type:
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType=<<PACKAGE NAME HERE ??>>
android:icon="#drawable/icon"
android:label="#string/app_name"/>
Thanks!
Here's another temporary workaround until the Android Gradle plugin gets support for placeholders in resource files.
You can dynamically create a String resource via Gradle in the defaultConfig and/or buildTypes and/or productFlavors closure:
android {
defaultConfig {
applicationId 'com.foo.bar'
resValue 'string', 'package_name', applicationId
}
}
You can then reference it in your authenticator.xml file just like you do for the label:
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="#string/package_name"
android:icon="#drawable/icon"
android:label="#string/app_name"/>
While uou can use ${packageName} to fill in the generated package name in the Manifest:
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="${packageName}"
android:icon="#drawable/icon"
android:label="#string/app_name"/>
This currently (Android Gradle 0.11) doesn't work with resource files. :-(
Instead, you must create a separate version of the resource file for each build type / variant you want with a different account type:
src
debug/res/xml/authenticator.xml (with debug package name)
main/res/xml/authenticator.xml (with default package name)
On top of jenzz's answer, i had to do this, since my case is just like as question, i add applicationIdSuffix for debug version of app.
android {
...
defaultConfig {
applicationId "..."
...
}
....
buildTypes {
release {
...
resValue 'string', 'application_id', android.defaultConfig.applicationId
}
debug {
...
applicationIdSuffix '.debug'
resValue 'string', 'application_id', android.defaultConfig.applicationId + applicationIdSuffix
} 
}
Then in any xml resource, i can get application Id as like this: #string/application_id
I'm using ${applicationId} like follow for example:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.abnerescocio.embaixadordorei.presentation">
...
<application
...
>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.android.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
...
</application>
</manifest>
I've just created a gradle plugin for this: com.inutilfutil.android-resource-placeholder
Just include it and placeholders will be replaced on all XML resources

Categories

Resources