Where to store Android KeyStore file for CirlceCi build? - android

I am trying to configure continuous integration build for my Android app.
I use CircleCi platform for it.
Now I store my apps Keystore.jks file locally, but CircleCi needs it to sign my app.
How can I achieve that without storing the file on my git repository? Or maybe I shouldn't be concerned about that while the repository is private?
My gradle signing configs:
signingConfigs {
if (System.getenv("CIRCLECI")) {
release {
keyAlias '****'
keyPassword '****'
storeFile file(System.getenv("******"))
storePassword '****'
}
}else{
release {
...
}
}
}
My circle.yml :
general:
artifacts:
- /home/ubuntu/my-app/app/build/outputs/apk/
machine:
environment:
ANDROID_HOME: /usr/local/android-sdk-linux
dependencies:
override:
- chmod +x gradlew
test:
override:
- ./gradlew assemble
I tried to save the keystore file on CircleCi as environmental variable but it isn't working, my build fails with exception:
> Execution failed for task ':app:validateSigningDemoRelease'.
> > Keystore file /home/ubuntu/my-app/app/ HERE_IS_THE_KEYSTORE not found for signing config 'release'.
Unsigned and debug builds finish with success.
I'm also open to use any different ci platform if you suggest something else.
Thanks in advance for every advice!

I struggled with this problem recently and decided that the easiest solution was to encode the keystore file to base64 and put it into an environment variable at CircleCI.
This will encode the file and you can copy and paste the value across:
openssl base64 -A -in .signing/release.jks
Then, in your config.yml file at CircleCI, decode it back:
echo $RELEASE_KEYSTORE_BASE64 | base64 -d > .signing/release.jks

if statement does not work in signingConfigs. If you want to sign apk with different keystore for different flavors, you need to create signingConfigs and put signingconfigs into buildTypes section. I did some research about where to store android keystore file in CI/CD Cycle and I come up with three approaches:
Encode keystore file as an environment variable
As #grepx's answer, convert keystore file to base-64 encoded string and save it as an environment variable in CI tools.
Store encrypted keystore file in version control system
Encrypt keystore file and store it in version control system. You can encrypt file with:
openssl aes-256-cbc -e -in keystore.jks -out keystore.jks.encrypted -k SECRET_KEY
You need to decrypt that encrypted keystore file in build step in CI tools:
openssl aes-256-cbc -d -in keystore.jks.encrypted -k $ENCRYPT_SECRET_KEY >> keystore.jks
SECRET_KEY is stored as an environment variable in CI with this key: $ENCRYPT_SECRET_KEY
Download keystore from external source like AWS S3, Google Drive
I've published an article about this topic in medium and you can reach complete example in github to understand better.

For me you have two solutions:
It's a private depot and you're the only one using it, so you can push your key.
My preferred solution would be to create another key that you call circleCI (for example) and that you push. Personally I use this solution
My build.gradle
signingConfigs {
Keys {
keyAlias 'mykey'
storeFile file('../private_key/upload_key.jks')
keyPassword ''
storePassword ''
}
Circleci {
keyAlias 'key'
storeFile file('../private_key/debug_key.jks')
keyPassword ''
storePassword ''
}
}
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
signingConfig signingConfigs.Keys
}
debug {
signingConfig signingConfigs.Keys
}
circleci{
signingConfig signingConfigs.Circleci
}
}

According to this link you have to encrypt the file like this:
openssl aes-256-cbc -a -salt -in secrets.txt -out secrets.txt.enc
and for the decryption:
openssl aes-256-cbc -a -salt -in secrets.txt.enc -out secrets.txt.new

Related

Generate signed apk for React Native Android application using existing certificate

I have an Android app certificate with a file type of FILE that was created back in 2012 for my Android app written in Java. Now I have updated that app using React Native.
How can I use the existing certificate to generate keystore and sign my updated app to be released on Google Play?
I've tried this even though the React Native certificate extension is .keystore
keytool -importcert -file "your.cer" -keystore your.jks -alias "<anything>"
and I got the following error
keytool error: java.lang.Exception: Input not an X.509 certificate
I expect to have a .keystore file that allows me to release an update of my existing Android app.
You don't need to create keystore file. you can use existing jks file to sign the app. Do as follow:
Put your jks file in the app directory
add the following code in your gradle.poperties file.
MYAPP_RELEASE_STORE_FILE=filename.jks
MYAPP_RELEASE_KEY_ALIAS=your-key-alias
MYAPP_RELEASE_STORE_PASSWORD=your-store-password
MYAPP_RELEASE_KEY_PASSWORD=your-release-key-password
Now add the signingConfigs in build.gradle file as below:
signingConfigs{
release {
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
Now you can sing your using your existing jks file.
One thing missed from the accepted answer.
How to fetch the existing Keystore file from the expo?
expo fetch:android:keystore
I need to know this so hopefully, it'll help someone.

How to fix app not installing compiled apk on my mobile device, using generating signed APK of react-native

I currently new developing android react-native, I have problem regarding deploying my application on other mobile device, I read the documentation of react native How to generate signed APK, i did the instruction of there document
React Native signed-apk-android
I already done configuring those requirements based on there document. I will show you the step that I did.
First: Install this in the cmd
keytool -genkeypair -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
Second: Setting up gradle variables
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=123456
MYAPP_RELEASE_KEY_PASSWORD=123456
Third: Adding signing config to your app's gradle config
...
android {
...
defaultConfig { ... }
signingConfigs {
release {
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
}
buildTypes {
release {
...
signingConfig signingConfigs.release
}
}
}
...
Lastly: Generating the release APK
Simply run the following in a terminal:
$ cd android
$ ./gradlew assembleRelease
Before I do the installation, I gonna make sure that the package
clearly uninstalled on my mobile device.
Release APK:
Error:
you need to click on the apk (probably with developer mode active press a few times on the build number in the settings menu)

What is the best practice to use keystores to sign release version of an Android app on Travis CI?

I've been using Travis CI to build my Android app. I am signing it in the debug builds with a debug.keystore which I pushed to public repository
But I want to build the release build and upload them to Google Play Store using this gradle plugin.
This process needs a keystore and a p12 certificate file.
While I can add encrypted environment variables to Travis CI, I don't know the best way to store these files.
Question 1: What is the best practice to do this? And can someone provide an open source implementation? (I couldn't find one)
One possible implementation: Store a username and password as a environment variable securely. Store the files in a SSL enabled environment and protect them with these username and password with a simple HTTP authentication. Use them to download using curl before build process begin.
Question 2 Does this implementation make sense at all? Is it secure?
Extra: These 2 blog posts are great sources related to this but none of them answers this question unfortunately.
http://stablekernel.com/blog/deploying-google-play-continuous-delivery-android-part-4/
https://www.bignerdranch.com/blog/continuous-delivery-for-android/
Updated (5/28/15):
I have started to implement my solution here(open source): https://github.com/NonameDev/MathApp
Use System.getenv("TRAVIS") to detect your build is running on Travis.
storeFile rootProject.file('release.keystore') - keep release key in your own repository - travis will hide the password
storePassword System.getenv("KEYSTORE_PASS") - store environment variable on travis - travis will hide output
keyAlias System.getenv("ALIAS_NAME") - store environment variable on travis - travis will hide output
keyPassword System.getenv("ALIAS_PASS") - store environment variable on travis - travis will hide output
System.getenv("SERVICE_EMAIL") - store environment variable on travis - travis will hide output
rootProject.file('play.p12') - store cert locally - travis will store the email service account
Top build.gradle:
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
classpath 'com.github.triplet.gradle:play-publisher:1.1.0'
}
}
App build.gradle:
apply plugin: 'com.android.application'
apply plugin: 'com.github.triplet.play'
android {
compileSdkVersion 22
buildToolsVersion '22.0.1'
defaultConfig {
applicationId 'burrows.apps.mathapp'
minSdkVersion 9
targetSdkVersion 22
versionCode 1
versionName '1.0'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
signingConfigs {
debug {
storeFile rootProject.file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
if (System.getenv("TRAVIS")) {
release {
storeFile rootProject.file('release.keystore')
storePassword System.getenv("KEYSTORE_PASS")
keyAlias System.getenv("ALIAS_NAME")
keyPassword System.getenv("ALIAS_PASS")
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
if (System.getenv("TRAVIS")) {
play {
serviceAccountEmail = System.getenv("SERVICE_EMAIL")
pk12File = rootProject.file('play.p12')
track = 'production' // or 'alpha' or 'beta' or 'production'
}
}
Original Answer:
Have you seen this answer? He posts a link to his TravisCI builds "before" and "after" correcting his build.
Here is his answer:
Compare build
#162
and
#163.
Basically he had to run sudo pip install google-api-python-client
With that being said, I checked out the github repo here.
Here is the his .travis.yml:
language: android
android:
components:
- build-tools-21.1.2
- extra-android-m2repository
env:
global:
- secure: <removed>
- secure: <removed>
before_install:
- ci/decrypt_files
- ci/start_emulator
install:
- ./gradlew build
before_script:
- ci/wait_for_emulator
script:
- ./gradlew connectedAndroidTestMockDebug
after_success:
- ci/deploy_all
notifications:
email:
- <removed>
Source: https://github.com/mg6maciej/VielenGamesAndroidClient/blob/develop/.travis.yml
Before build:
This is the secure part of the process where the keys are used and the password is used from TravisCI(securely stored on TravisCI).
before_install:
- ci/decrypt_files
- ci/start_emulator
Source of ci/decrypt_files:
#!/bin/bash
openssl aes-256-cbc -d -k "$file_password" -in app/gradle.properties.enc -out app/gradle.properties
openssl aes-256-cbc -d -k "$file_password" -in app/crashlytics.properties.enc -out app/crashlytics.properties
openssl aes-256-cbc -d -k "$file_password" -in ci/vielengames.keystore.enc -out ci/vielengames.keystore
openssl aes-256-cbc -d -k "$file_password" -in ci/key.p12.enc -out key.p12
Source: https://github.com/mg6maciej/VielenGamesAndroidClient/blob/develop/ci/decrypt_files
After Build:
This is where python and other Google libs are being downloaded and used to deploy the app to Google Play.
after_success:
- ci/deploy_all
Source of ci/deploy_all:
#!/bin/bash
test "$TRAVIS_BRANCH" == "master" && ci/deploy_google_play
ci/deploy_testfairy
ci/deploy_crashlytics_beta
Source of ci/deploy_google_play:
#!/bin/bash
DIR=$(dirname $0)
sudo apt-get install python-openssl
sudo pip install google-api-python-client
python $DIR/basic_upload_apks.py com.vielengames $DIR/../app/build/outputs/apk/app-production-release.apk
python $DIR/basic_upload_apks.py com.vielengames.staging $DIR/../app/build/outputs/apk/app-staging-release.apk
Security:
Your Question 1:
I believe you have to have have both the keystore and p12 for the app, but you can safely store your password with TravisCI(see the "$file_password"), just like the example above.
Your Question 2:
Even if you have the keystore and p12 cert, you still need the password(see the "$file_password") for both to work and be used to publish to the store.
For extra security, you want to add another login with less permissions than you main login. Here is what the author of the repo did here:
...
TRACK = 'beta' # Can be 'alpha', beta', 'production' or 'rollout'
SERVICE_ACCOUNT_EMAIL = (
'148768954062-sp89pjb1blr7cu2f73f4fpd6dqloc047#developer.gserviceaccount.com')
# Declare command-line flags.
argparser = argparse.ArgumentParser(add_help=False)
argparser.add_argument('package_name',
help='The package name. Example: com.android.sample')
argparser.add_argument('apk_file',
nargs='?',
default='test.apk',
help='The path to the APK file to upload.')
...
Source: https://github.com/mg6maciej/VielenGamesAndroidClient/blob/develop/ci/basic_upload_apks.py
When your application complete then after export it.
At that time automatically generate key-store,SHA1 and MD5 keys which are used in play store or publicly.
Now create your final APK file for play store and perfectly use publicly.

Keystore For Signing Android App

I am trying implement In-App billing in my Androd app and when I test the purchase functionality I get the error "This version of the application is not configured for billing through Google Play."
I suspect that I did not properly generate a signed APK and that the problem is with my buil.gradle file.
I genereated a keystore by following the instructions here and generated .jks. My question is what exactly do I put for the storeFile file() in signingConfigs?
The following example is from the Android docs:
signingConfigs {
release {
storeFile file("myreleasekey.keystore")
storePassword "password"
keyAlias "MyReleaseKey"
keyPassword "password"
}
}
Simply putting the path to my .jks file didn't work. Is a .jks file different than a .keystore file? If so, how do I genereate a .keystore?
UPDATE
I learned that the .keystore and .jks are arbitrary file extensions from this answer.
My plan is to simply copy the my keystore.jks file in to the app directory then add the tag as follows:
storeFile file("keystore.jks")
Is this correct? Unfortunately it will take a few hours for the apk to be published by Google Play so I can't get a quick answer on this.
I solved the problem. The key was to choose the app directory as the key store path.
Here are detailed instructions on how I generated a signed apk in Android Studio:
Go to Build->Generate Signed apk
Select the app module, click next.
Under Key store path, click create new.
The following window will pop up.
Select your app directory for the keystore path. It will create a keystore with default name "keystore.jks". You can change it if you like.
Enter a password for the keystore. We will call it "StorePassword"
Enter a Key Alias (let's call it "KeyAlias") and a Key password (let's call it "KeyPassword")
In the build.gradle file add the following:
Example Signing config:
signingConfigs {
release {
storeFile file("keystore.jks")
storePassword "StorePassword"
keyAlias "KeyAlias"
keyPassword "KeyPassword"
}
}
Continue through the Generate Signed apk Wizard and enter in the appropriate passwords and generate the apk. The key is to make sure that the build.gradle is updated in the final signed apk.
To confirm that you successfully signed the .apk see this question.
And of course, have secure backups and be extremely protective of the keystore once it is genereated.
keytool -genkey -v -keystore name_of_your_file.keystore -alias your_alias -keyalg RSA -keysize 2048 -validity 10000
This is command will generate new keys
change name_of_your_file for your name
and your_alias for your alias
the keystore will be generated in folder where you call this
Then add this to your build.gradle
signingConfigs {
config {
storeFile file("${rootDir}/name_of_your_file.keystore")
storePassword "qwerty"
keyAlias "your_alias"
keyPassword "qwerty"
}
}
buildTypes {
release {
signingConfig android.signingConfigs.config
}
}
but change qwerty to your password
and your_alias to your alias name which you use when you generate keystore
and name_of_your_file to name of your kestore
clean your project and run ./gradlew task assembleRelease
In Android Studio go to Build->Generate Signed apk and follow steps. You don't need to add signingConfigsin build.gradle At least on current android studio version which is 1.3.2

Android Studio: how to generate signed APK using Gradle?

I've searched on Google and SO but cannot find my answer.
This is the first time I'm working with the Gradle system and I am now at the point of generating a signed APK to upload to Google Play (project is imported from eclipse).
Now, I've read the part here that you should add signingConfigs to your build.gradle.
I've added these lines and now I saw that you need to run ./gradlew assembleRelease but running this in my CMD returns
'gradle' is not recognized as an internal or external command,
operable program or batch file.
I've also tried to right click on the build.gradle and run it, saying it was sucessful but once I look in the build/apk folder only a file called app-debug-unaligned.apk.
So, how do I generate the signed APK using the Gradle system?
There are three ways to generate your build as per the buildType. (In your case, it's release but it can be named anything you want.)
Go to Gradle Task in right panel of Android Studio and search for assembleRelease or assemble(#your_defined_buildtype) under Module Tasks
Go to Build Variant in Left Panel and select the build from drop down
Go to project root directory in File Explore and open cmd/terminal and run:
Linux: ./gradlew assembleRelease or assemble(#your_defined_buildtype)
Windows: gradlew assembleRelease or assemble(#your_defined_buildtype)
If you want to do a release build (only), you can use Build > Generate Signed apk. For other build types, only the above three options are available.
You can find the generated APK in your module/build directory having the build type name in it.
It is possible to take any existing Android Studio gradle project and build/sign it from the command line without editing any files. This makes it very nice for storing your project in version control while keeping your keys and passwords separate:
./gradlew assembleRelease -Pandroid.injected.signing.store.file=$KEYFILE -Pandroid.injected.signing.store.password=$STORE_PASSWORD -Pandroid.injected.signing.key.alias=$KEY_ALIAS -Pandroid.injected.signing.key.password=$KEY_PASSWORD
You can use this code
android {
...
signingConfigs {
release {
storeFile file("../your_key_store_file.jks")
storePassword "some_password"
keyAlias "alias_name"
keyPassword "key_password"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
...
}
then from your terminal run
./gradlew assembleRelease
you will get the apk at
your-android-app/build/outputs/apk/your-android-app-release.apk
I think this can help you https://www.timroes.de/2013/09/22/handling-signing-configs-with-gradle/ then just select the Release from the Build Variants
If you live in certain countries, be sure to use a VPN.
step1: run this command in the command-line:
keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key
it will ask you for some information such as password, name,... and enter them.
step2: create a file name key.properties in your android folder.
write these lines in the created file
storePassword=<password from previous step>
keyPassword=<password from previous step>
keyAlias=key
storeFile=<location of the key store file, such as ~/key.jks>
keep the key.properties file private, always keep a backup of the key.properties file and never publish publicly.
step3: Replace the following lines in app-level Gradle
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
step4:
keytool -list -v -keystore ~/key.jks -alias key -storepass <password> -keypass <password>
step5:
I recommend building APK, using android studio.
Build > Generate Signed Bundle/APK...
This is for Kotlin DSL (build.gradle.kts).
You could either define your properties in local.properties file in the project root directory or define them as environment variables (which is especially useful for CIs like GitHub Actions).
// See https://stackoverflow.com/q/60474010
fun getLocalProperty(key: String) = gradleLocalProperties(rootDir).getProperty(key)
fun String?.toFile() = file(this!!)
// Could also use System.getenv("VARIABLE_NAME") to get each variable individually
val environment: Map<String, String> = System.getenv()
android {
signingConfigs {
create("MyAppSigningConfig") {
keyAlias = getLocalProperty("signing.keyAlias") ?: environment["SIGNING_KEY_ALIAS"] ?: error("Error!")
storeFile = (getLocalProperty("signing.storeFile") ?: environment["SIGNING_STORE_FILE"] ?: error("Error!")).toFile()
keyPassword = getLocalProperty("signing.keyPassword") ?: environment["SIGNING_KEY_PASSWORD"] ?: error("Error!")
storePassword = getLocalProperty("signing.storePassword") ?: environment["SIGNING_STORE_PASSWORD"] ?: error("Error!")
enableV1Signing = true
enableV2Signing = true
}
}
buildTypes {
getByName("release") { // OR simply release { in newer versions of Android Gradle Plugin (AGP)
signingConfig = signingConfigs["MyAppSigningConfig"]
// ...
}
}
}
myProject/local.properties file:
signing.keyAlias=foo
signing.keyPassword=bar
# also called keystore
signing.storePassword=abcdefgh
signing.storeFile=C\:\\my-files\\my-keystore.jks
NOTE: Do NOT add your local.properties file to your version control system (like Git), as it exposes your secret information like passwords etc. to the public (if it's a public repository).
Generate your APK with either of the 3 ways that this answer mentioned.
build menu > generate signed apk

Categories

Resources