Every time I run a project with Android Studio (1.02) it's generate an unsigned apk which located in ..\build\outputs\apk folder and get by default the name "app-debug.apk"
I want to change that default name to something else.
Is it possible? How?
In build.gradle (Module: app):
android {
...
defaultConfig {
...
setProperty("archivesBaseName", "MyNewAppNameGoesHere")
}
}
This works by modifying the archivesBaseName-property and works for Gradle Version >= 2.0, last tested with 2.1.0.
You can use applicationVariants and change the output file in the build.gradle. You can also modify the name regarding to your needs.
buildTypes{
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = file("$project.buildDir/apk/test.apk")
}
}
}
Solution for gradle3:
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = applicationId;
outputFileName += "-v" + android.defaultConfig.versionName;
if (variant.buildType.name == "release") {
outputFileName += ".apk";
} else {
outputFileName += "-SNAPSHOT.apk";
}
}
}
defaultConfig {
applicationId "com.dcarl661.awesomelayout"
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName "1.0"
//here put it in the section where you have the version stuff
setProperty("archivesBaseName", "AwesomeLayout")
}
defaultConfig {
applicationId "com.example"
def date = new Date();
def formattedDate = date.format('yyyy-MM-dd-HHmmss')
setProperty("archivesBaseName", "Quest_" + versionName + "_"+formattedDate)
}
i did like this. More detailed
If anyone is looking to change apk name outside the Android studio(just to send this file to someone else, as in my case), just right click the app name and change it to whatever you want.
The 'app' part of the name uses the folder name of your application's module (default is 'app'). See the link below on how to change that.
Why is my APK name generic?
The '-debug' prefix is something you can change in the Module settings at Build Types
Maybe this question (and its accepted answer) are interesting for you:
How to set versionName in APK filename using gradle?
It describes how to put your versionName into the APK name.
You have to use the 'Update' part of the accepted answer. Also you need the versionName (in this example) declared in your defaultConfig in the build.gradle file. It does also work if you define versionCode in the build.gradle (as described here: http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Manifest-entries ).
Related
How to get applicationId after all suffixes added in android app/build.gradle
I tried to use it as below, but the application id is null, we are setting the applicationId to default config from app/build.gradle, I assume it has executed later than we set the resValue, also I need the applicationId when it is completely appended with all suffix from flavor and buildType.
app/build.gradle
android {
defaultConfig.applicationId "com.companyname.appname"
}
util/build.gradle
android {
defaultConfig {
resValue "string", "freshchat_file_provider_authority", applicationId + ".provider"
}
}
Share if anybody can support about this.
We can make applicationId via accessing current flavorName and buildType by placing the below code in app/build.gradle android closure as below.
applicationVariants.all { variant ->
def flavorName = variant.flavorName
def buildType = variant.buildType.name
def applicationIdMade = defaultConfig.applicationId + ".$flavorName.$buildType"
println applicationIdMade // Use as you require
}
I have gradle project, the simplified android part of the build.gradle of which looks like this:
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
minSdkVersion 15
targetSdkVersion 22
versionCode 1
versionName "1.0"
def mapPlacesApiKeys = [dev_1: [api_key: 'key_1', sender_id: 'sender_id_1'], dev_9: [api_key: 'key_2', sender_id: 'sender_id_2'],prod_1: [api_key: 'key_3', sender_id: 'sender_id_3']]
if (project.hasProperty('env')) {
if (mapPlacesApiKeys.get(env) == null) {
def keyset = mapPlacesApiKeys.keySet()
throw new StopExecutionException("Value '$env' is not a valid environment value. Valid environments: $keyset. You can set an environment by passing the -Penv=<env> parameter to your gradle build.")
}
}
buildConfigField "String", "SENDER_ID", "\"${mapPlacesApiKeys.get(env).get('sender_id')}\""
manifestPlaceholders = [maps_places_api_key: mapPlacesApiKeys.get(env).get('api_key')]
}
}
When I run this from the command line I run it with an environment parameter e.g. -Penv=dev_1. This does 2 things as you can see in the script:
a) Replaces in the androidmanifest the value "maps_places_api_key" with the actual key of the specified environment
b) Adds a String with the SENDER_ID in the BuildConfig java class.
This works fine from the command line. My problem is that in intellij (or android studio, should be the same) when I import the gradle project I get the following error:
-Penv is missing. You can set an environment by passing the -Penv=<env> parameter to your gradle build.
Which is the exception that I am declaring. So my question is how can I structure this code so that the IDE doesn't try to run it when it's loading the project.
Note that I don't want to replace the "env" parameter with any kinds of flavors or buildTypes, as there's about 15 different environments and it's gonna be a mess, but if there's another suggestion that comes in to your mind feel free to share it.
android{
defaultConfig {
applicationId 'com.xx'
minSdkVersion 14
}
productFlavors {
def path="./channel.txt"
file(path).eachLine { line->
def words = line.split(':')
def name = words[0]
def sender_id = words[1]
def api_key = words[2]
"$name" {
buildConfigField "String", "SENDER_ID", sender_id
manifestPlaceholders = [maps_places_api_key: api_key]
}
}
}
}
i have a build.gradle file in my android app with this settings:
android {
...
defaultConfig {
applicationId "some.app.id"
versionName '1.2'
versionCode 3
...
}
...
}
My AndroidManifest.xml does not contain versionCode and not contain versionName.
Now i want to build this app on Jenkins and pass BUILD_NUMBER as a versionCode for app, so that every build has a higher version.
So in job I hava a call:
./gradlew -PversionCode=$BUILD_NUMBER clean build
When i use "versionCode" to rename "app-release.apk" value of versionCode is the same as passed from command line:
applicationVariants.all { variant ->
variant.outputs.each { output ->
output.outputFile = new File(output.outputFile.parent, output.outputFile.name.replace("app-release.apk", "MyApp_" + "_v" + versionName + "." + versionCode + ".apk"))
}
}
Summary
So I have a default value of "versionCode" set to 3, but when building on Jenkins I want to override it from command line.
The problem
The problem is that in AndroidManifest inside build .apk app has versionCode set to 3 instead of value from BUILD_NUMBER.
I checked it with "aapt dump badging"
The question
Can this value "versionCode" from android defaultConfig be overriden by command line parameter?
I know, I could use a function as explained in:
http://robertomurray.co.uk/blog/2013/gradle-android-inject-version-code-from-command-line-parameter/
but I prefer the cleaner way of simple override but I cant get it working.
You can use properties by defining them in a gradle.properties file, see gradle documentation.
But you'll have to be really careful which names you use for your properties: if you use versionName that property will have the correct value in gradle (you can println it) but it won't end up in your AndroidManifest.xml! So I chose to use 'versName'. (I don't know enough about gradle to understand why this is so...)
So in your project's gradle.properties you can define the following properties:
versCode=3
versName=1.2
And then change the build.gradle file into:
android {
...
defaultConfig {
applicationId "some.app.id"
versionName versName
versionCode versCode as Integer
...
}
...
}
Now you can override them on the command line like this: ./gradlew -PversCode=4 -PversName=2.1.3 clean build
After updating Android Studio to 1.0, I see this error:
Error: Library projects cannot set applicationId. applicationId is set
to 'com.super.app' in default config.
I updated the Gradle plugin as suggested but I did not understand how to fix this.
Based on this info:
ApplicationId in Library Projects
You cannot use applicationId to customize the package of a library project. The package name has to be fixed in library projects (and specified as packageName in the manifest). The Gradle plugin did not enforce this restriction earlier.
Removing applicationId variable from the library's build.gradle file should resolve the issue.
Thanks to Joel for his correct answer: I need to remove only 1 line from te .gradle file:
defaultConfig {
applicationId "com.super.app" <---- remove this line
minSdkVersion 15
targetSdkVersion 19
versionCode 1
versionName "1.0"
}
becomes
defaultConfig {
minSdkVersion 15
targetSdkVersion 19
versionCode 1
versionName "1.0"
}
and my AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.super.app">
...
This is the right solution if you don't need to rename the package name of your app. To rename it you need to use "flavours":
android {
...
productFlavors {
flavor1 {
applicationId 'com.super.superapp'
}
}
Libraries can't set applicationId and if you are working in a multi-module project and picking up flavors from a separate file , none of the above answers will work. For a modularized app, you need the following steps -
Create a flavors.gradle file in project root directory
ext.flavorConfig = { // 1
flavorDimensions "pricing"
productFlavors {
free {
dimension "pricing"
ext.myApplicationIdSuffix = '.free' // 2
}
paid {
dimension "pricing"
ext.myApplicationIdSuffix = '.paid'
}
}
productFlavors.all { flavor -> // 3
if (flavor.hasProperty('myApplicationIdSuffix') && isApplicationProject()) {
flavor.applicationIdSuffix = flavor.myApplicationIdSuffix
}
}
}
def isApplicationProject() { // 4
return project.android.class.simpleName.startsWith('BaseAppModuleExtension')
}
In 1 we export a closure so that we can use it in our modules’ build.gradle files.
In 2 we define a custom myApplicationIdSuffix property. We cannot simply have applicationIdSuffix as it is not possible to use it in library modules (build would fail if you did).
In 3 we iterate over created flavors and set applicationIdSuffix if we detect that it’s an application module only.
4 is a way to check where this closure is being used.
All that’s left is to use this closure in our modules’ build.gradle files. E.g. in application module this would look like this:
apply plugin: 'com.android.application'
apply from: "${rootProject.projectDir}/flavors.gradle"
android {
// other config...
with flavorConfig
}
If this isn't clear, you can check out this article for better understanding.
Just incase it helps some one :
When i imported an eclipse project into android studio,i got an error ::
"Error:Application and test application id cannot be the same"
Strange though,but i looked into the build.gradle and found the two placeholders,one for the application and other for testapplication.
I removed the testApplicationId from that as is suggested in this post and this helped me resolve the issue.
Note: This explaination is not related to the errors posted in this question,but might help someone who is getting a similar error.
You cannot define applicationId for your lib.
But incase you want to use an identifier in your build file, which will give you, your library package name, you can define a variable for the module and then use the value as required.
eg : Library's build.gradle
apply plugin: 'com.android.library'
def libraryGroupId = 'com.google.example'
def libraryArtifactId = project.getName()
def libraryVersion = '1.1'
Also, you can use the value below as needed in your build file itself in lib.
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "$libraryVersion"
resValue "string", "Library", libraryGroupId"
}
}
So I'm coming down to release-time for my application. We plan on releasing two versions, a free ad-based play-to-unlock version, and a paid fully unlocked version. I have the code set up that I can simply set a flag on startup to enable/disable ads and lock/unlock all the features. So literally only one line of code will execute differently between these versions.
In order to release two separate applications, they require different package names, so my question is this: Is there an easy way to refactor my application's package name? Eclipse's refactoring tool doesn't resolve the generated R file, or any XML references in layout and manifest files. I've attempted to make a new project using the original as source, but I can't reference the assets and resources, and I'm looking to avoid duplicating any of my code and assets. It's not a huge pain to refactor it manually, but I feel there must be a better way to do it. Anybody have an elegant solution to this?
Edit/Answered:
For my situation I find it perfectly acceptable to just use Project -> Android Tools -> Rename Application Package. I wasn't aware this existed, and I feel like an idiot for posting this now. Thanks for everyone's answers and comments, feel free to vote this closed.
It's very simple by using build.gradle in Android Studio. Read about productFlavors. It is a very usefull feature. Just simply add following lines in build.gradle:
productFlavors {
lite {
packageName = 'com.project.test.app'
versionCode 1
versionName '1.0.0'
}
pro {
packageName = 'com.project.testpro.app'
versionCode 1
versionName '1.0.0'
}
}
In this example I add two product flavors: first for lite version and second for full version. Each version has his own versionCode and versionName (for Google Play publication).
In code just check BuildConfig.FLAVOR:
if (BuildConfig.FLAVOR == "lite") {
// add some ads or restrict functionallity
}
For running and testing on device use "Build Variants" tab in Android Studio to switch between versions:
Possibly a duplicate of Bulk Publishing of Android Apps.
Android Library projects will do this for you nicely. You'll end up with 1 library project and then a project for each edition (free/full) with those really just containing different resources like app icons and different manifests, which is where the package name will be varied.
Hope that helps. It has worked well for me.
The best way is to use "Android Studio" -> gradle.build -> [productFlavors + generate manifest file from template]. This combination allows to build free/paid versions and bunch of editions for different app markets from one source.
This is a part of templated manifest file:
<manifest android:versionCode="1" android:versionName="1" package="com.example.product" xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:icon="#drawable/ic_launcher"
android:label="#string/{f:FREE}app_name_free{/f}{f:PAID}app_name_paid{/f}"
android:name=".ApplicationMain" android:theme="#style/AppTheme">
<activity android:label="#string/{f:FREE}app_name_free{/f}{f:PAID}app_name_paid{/f}" android:name=".ActivityMain">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
This is template "ProductInfo.template" for java file: ProductInfo.java
package com.packagename.generated;
import com.packagename.R;
public class ProductInfo {
public static final boolean mIsPaidVersion = {f:PAID}true{/f}{f:FREE}false{/f};
public static final int mAppNameId = R.string.app_name_{f:PAID}paid{/f}{f:FREE}free{/f};
public static final boolean mIsDebug = {$DEBUG};
}
This manifest is processed by gradle.build script with productFlavors and processManifest task hook:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction
...
android {
...
productFlavors {
free {
packageName 'com.example.product.free'
}
paid {
packageName 'com.example.product.paid'
}
}
...
}
afterEvaluate { project ->
android.applicationVariants.each { variant ->
def flavor = variant.productFlavors[0].name
tasks['prepare' + variant.name + 'Dependencies'].doLast {
println "Generate java files..."
//Copy templated and processed by build system manifest file to filtered_manifests forder
def productInfoPath = "${projectDir}/some_sourcs_path/generated/"
copy {
from(productInfoPath)
into(productInfoPath)
include('ProductInfo.template')
rename('ProductInfo.template', 'ProductInfo.java')
}
tasks.create(name: variant.name + 'ProcessProductInfoJavaFile', type: processTemplateFile) {
templateFilePath = productInfoPath + "ProductInfo.java"
flavorName = flavor
buildTypeName = variant.buildType.name
}
tasks[variant.name + 'ProcessProductInfoJavaFile'].execute()
}
variant.processManifest.doLast {
println "Customization manifest file..."
// Copy templated and processed by build system manifest file to filtered_manifests forder
copy {
from("${buildDir}/manifests") {
include "${variant.dirName}/AndroidManifest.xml"
}
into("${buildDir}/filtered_manifests")
}
tasks.create(name: variant.name + 'ProcessManifestFile', type: processTemplateFile) {
templateFilePath = "${buildDir}/filtered_manifests/${variant.dirName}/AndroidManifest.xml"
flavorName = flavor
buildTypeName = variant.buildType.name
}
tasks[variant.name + 'ProcessManifestFile'].execute()
}
variant.processResources.manifestFile = file("${buildDir}/filtered_manifests/${variant.dirName}/AndroidManifest.xml")
}
}
This is separated task to process file
class processTemplateFile extends DefaultTask {
def String templateFilePath = ""
def String flavorName = ""
def String buildTypeName = ""
#TaskAction
void run() {
println templateFilePath
// Load file to memory
def fileObj = project.file(templateFilePath)
def content = fileObj.getText()
// Flavor. Find "{f:<flavor_name>}...{/f}" pattern and leave only "<flavor_name>==flavor"
def patternAttribute = Pattern.compile("\\{f:((?!${flavorName.toUpperCase()})).*?\\{/f\\}",Pattern.DOTALL);
content = patternAttribute.matcher(content).replaceAll("");
def pattern = Pattern.compile("\\{f:.*?\\}");
content = pattern.matcher(content).replaceAll("");
pattern = Pattern.compile("\\{/f\\}");
content = pattern.matcher(content).replaceAll("");
// Build. Find "{$DEBUG}" pattern and replace with "true"/"false"
pattern = Pattern.compile("\\{\\\$DEBUG\\}", Pattern.DOTALL);
if (buildTypeName == "debug"){
content = pattern.matcher(content).replaceAll("true");
}
else{
content = pattern.matcher(content).replaceAll("false");
}
// Save processed manifest file
fileObj.write(content)
}
}
Updated: processTemplateFile created for code reusing purposes.
Gradle allows to use generated BuildConfig.java to pass some data to code.
productFlavors {
paid {
packageName "com.simple.paid"
buildConfigField 'boolean', 'PAID', 'true'
buildConfigField "int", "THING_ONE", "1"
}
free {
packageName "com.simple.free"
buildConfigField 'boolean', 'PAID', 'false'
buildConfigField "int", "THING_ONE", "0"
}
For everyone who want to use the solution by Denis:
In the new gradle version packageName is now applicationId and don't forget to put productFlavors { ... } in android { ... }
productFlavors {
lite {
applicationId = 'com.project.test.app'
versionCode 1
versionName '1.0.0'
}
pro {
applicationId = 'com.project.testpro.app'
versionCode 1
versionName '1.0.0'
}
}
One approach I'm experimenting with is using fully-qualified names for activities, and just changing the package attribute. It avoids any real refactoring (1 file copy, 1 text sub).
This almost works, but the generated R class isn't picked up, as the package for this is pulled out of AndroidManifest.xml, so ends up in the new package.
I think it should be fairly straight forward to build AndroidManifest.xml via an Ant rule (in -pre-build) that inserts the distribution package name, and then (in -pre-compile) the generated resources into the default (Java) package.
Hope this helps,
Phil Lello
If you want another application name, depending of the flavor, you can also add this:
productFlavors {
lite {
applicationId = 'com.project.test.app'
resValue "string", "app_name", "test lite"
versionCode 1
versionName '1.0.0'
}
pro {
applicationId = 'com.project.testpro.app'
resValue "string", "app_name", "test pro"
versionCode 1
versionName '1.0.0'
}
}