diff --git a/Makefile b/Makefile index d29f993e104c..aa6ed21a1006 100644 --- a/Makefile +++ b/Makefile @@ -190,25 +190,28 @@ xcode-clean: ##@prepare Clean XCode derived data and archives #---------------- release: release-android release-ios ##@build Build release for Android and iOS -release-android: export BUILD_ENV ?= prod -release-android: export BUILD_TYPE ?= nightly -release-android: export BUILD_NUMBER ?= $(TMP_BUILD_NUMBER) +build-android: SHELL := /bin/sh +build-android: export BUILD_ENV ?= prod +build-android: export BUILD_TYPE ?= nightly +build-android: export BUILD_NUMBER ?= $(TMP_BUILD_NUMBER) +build-android: export ANDROID_ABI_SPLIT ?= false +build-android: export ANDROID_ABI_INCLUDE ?= armeabi-v7a;arm64-v8a;x86 +build-android: ##@build Build unsigned Android APK + @scripts/build-android.sh + +release-android: export TARGET := keytool release-android: export KEYSTORE_PATH ?= $(HOME)/.gradle/status-im.keystore -release-android: export ANDROID_APK_SIGNED ?= true -release-android: export ANDROID_ABI_SPLIT ?= false -release-android: export ANDROID_ABI_INCLUDE ?= armeabi-v7a;arm64-v8a;x86 -release-android: keystore ##@build Build release for Android - scripts/release-android.sh +release-android: keystore build-android ##@build Build signed Android APK + @scripts/sign-android.sh result/app-release-unsigned.apk release-fdroid: export BUILD_ENV = prod release-fdroid: export BUILD_TYPE = release -release-fdroid: export ANDROID_APK_SIGNED = false release-fdroid: export ANDROID_ABI_SPLIT = false release-fdroid: export ANDROID_ABI_INCLUDE = armeabi-v7a;arm64-v8a;x86;x86_64 release-fdroid: export READER_FEATURES = google-free release-fdroid: ##@build Build release for F-Droid - scripts/google-free.sh - scripts/release-android.sh + @scripts/google-free.sh + @scripts/build-android.sh release-ios: export TARGET := ios release-ios: export BUILD_ENV ?= prod diff --git a/android/app/build.gradle b/android/app/build.gradle index 98e472c31df1..28c0e33902b9 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -234,23 +234,6 @@ android { jumboMode true javaMaxHeapSize "8g" } - signingConfigs { - debug { - storeFile file('debug.keystore') - storePassword 'android' - keyAlias 'androiddebugkey' - keyPassword 'android' - } - /* Caution! In production, you need to generate your own keystore file. - * See: https://facebook.github.io/react-native/docs/signed-apk-android */ - release { - /* environment variables take precedence over gradle.properties file */ - storeFile file(getEnvOrConfig('KEYSTORE_PATH').replaceAll("~", System.properties['user.home'])) - storePassword getEnvOrConfig('KEYSTORE_PASSWORD') - keyAlias getEnvOrConfig('KEYSTORE_ALIAS') - keyPassword getEnvOrConfig('KEYSTORE_KEY_PASSWORD') - } - } splits { abi { reset() @@ -259,20 +242,26 @@ android { universalApk true } } + signingConfigs { + debug { + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } buildTypes { debug { applicationIdSuffix ".debug" debuggable true versionNameSuffix "-SNAPSHOT" - signingConfig signingConfigs.debug resValue "string", "build_config_package", "im.status.ethereum" + signingConfig signingConfigs.debug } release { minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" - if (getEnvOrConfig('ANDROID_APK_SIGNED').toBoolean()) { - signingConfig signingConfigs.release - } + signingConfig null } pr { initWith release diff --git a/android/build.gradle b/android/build.gradle index fffbf0a58099..05502a37e151 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -22,7 +22,7 @@ buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.31" classpath "com.android.tools.build:gradle:${project.ext.gradlePluginVersion}" - classpath "com.google.gms:google-services:4.3.10" + classpath "com.google.gms:google-services:4.3.10" // WARNING: Do not place your application dependencies here! // They belong in the individual module build.gradle files. } diff --git a/android/gradle.properties b/android/gradle.properties index 643fef770990..b1a0c8a8dbe6 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -42,8 +42,6 @@ KEYSTORE_KEY_PASSWORD=password ANDROID_ABI_SPLIT=false # Some platforms are excluded though ANDROID_ABI_INCLUDE=armeabi-v7a;arm64-v8a;x86 -# F-Droid builds need to be unsigned -ANDROID_APK_SIGNED=true org.gradle.jvmargs=-Xmx8704M diff --git a/ci/Jenkinsfile.android b/ci/Jenkinsfile.android index cf6a326f9abd..dc837b8ff3b0 100644 --- a/ci/Jenkinsfile.android +++ b/ci/Jenkinsfile.android @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.4.0' +library 'status-jenkins-lib@build-unsigned-android' pipeline { agent { label 'linux && x86_64 && nix-2.6' } diff --git a/ci/Jenkinsfile.combined b/ci/Jenkinsfile.combined index 7f3f1db83ce9..bc2a086a6754 100644 --- a/ci/Jenkinsfile.combined +++ b/ci/Jenkinsfile.combined @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.4.0' +library 'status-jenkins-lib@build-unsigned-android' pipeline { agent { label 'linux' } diff --git a/ci/Jenkinsfile.ios b/ci/Jenkinsfile.ios index 4ff3566f3152..b6b8a9aebbcb 100644 --- a/ci/Jenkinsfile.ios +++ b/ci/Jenkinsfile.ios @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.4.0' +library 'status-jenkins-lib@build-unsigned-android' pipeline { agent { label 'macos && x86_64 && nix-2.6 && xcode-12.5' } diff --git a/ci/Jenkinsfile.nix-cache b/ci/Jenkinsfile.nix-cache index 48214755a674..4ad18f27739b 100644 --- a/ci/Jenkinsfile.nix-cache +++ b/ci/Jenkinsfile.nix-cache @@ -1,4 +1,4 @@ -library 'status-jenkins-lib@v1.4.0' +library 'status-jenkins-lib@build-unsigned-android' pipeline { agent { label params.AGENT_LABEL } diff --git a/nix/README.md b/nix/README.md index ef314bf5f708..7e5e86e7371c 100644 --- a/nix/README.md +++ b/nix/README.md @@ -19,7 +19,6 @@ Here is a sample structure of the `config` attribute set: build-number = 9999; # Used for versionCode and CFBundleVersion in Android and iOS respectively android = { gradle-opts = ""; # Gradle options passed for Android builds - keystore-path = ""; # Path to keystore for signing the APK abi-split = false; # If APKs should be split based on architectures abi-include = "x86"; # Android architectures to build for }; diff --git a/nix/config.nix b/nix/config.nix index 416ff6e5aeed..34ca0bd6c2fe 100644 --- a/nix/config.nix +++ b/nix/config.nix @@ -7,7 +7,6 @@ android = { gradle-opts = null; # Gradle options passed for Android builds - keystore-path = null; # Path to keystore for signing the APK apk-signed = true; # F-Droid builds aren't signed by us abi-split = false; # If APKs should be split based on architectures abi-include = "armeabi-v7a;arm64-v8a;x86"; # Android architectures to build for diff --git a/nix/mobile/android/default.nix b/nix/mobile/android/default.nix index 911772c35a1c..ca8b8d4f50bf 100644 --- a/nix/mobile/android/default.nix +++ b/nix/mobile/android/default.nix @@ -2,9 +2,6 @@ , status-go, androidPkgs, androidShell }: let - # For generating a temporary keystore for local development - keystore = callPackage ./keystore.nix { }; - # Import a jsbundle compiled out of clojure codebase jsbundle = callPackage ./jsbundle { }; @@ -13,12 +10,12 @@ let # TARGETS release = callPackage ./release.nix { - inherit keystore jsbundle status-go watchmanFactory; + inherit jsbundle status-go watchmanFactory; }; in { # TARGETS - inherit keystore release jsbundle; + inherit release jsbundle; shell = mkShell { buildInputs = with pkgs; [ diff --git a/nix/mobile/android/keystore.nix b/nix/mobile/android/keystore.nix deleted file mode 100644 index a6d4a5d171b2..000000000000 --- a/nix/mobile/android/keystore.nix +++ /dev/null @@ -1,44 +0,0 @@ -# -# Generates an ad-hoc and temporary keystore for signing debug/pr builds. -# -# WARNING: Do NOT use this to make a keystore that needs to be secret! -# Using a derivation will store the inputs in a .drv file. -# -{ stdenv, lib, pkgs }: - -let - inherit (lib) getAttr; - - gradleProps = pkgs.gradlePropParser ../../../android/gradle.properties; - - # Loading defaults from gradle.properties which should be safe. - KEYSTORE_ALIAS = getAttr "KEYSTORE_ALIAS" gradleProps; - KEYSTORE_PASSWORD = getAttr "KEYSTORE_PASSWORD" gradleProps; - KEYSTORE_KEY_PASSWORD = getAttr "KEYSTORE_KEY_PASSWORD" gradleProps; - -in stdenv.mkDerivation { - name = "status-react-android-keystore"; - - buildInputs = [ pkgs.openjdk8 ]; - - phases = [ "generatePhase" ]; - generatePhase = '' - keytool -genkey -v \ - -keyalg RSA \ - -keysize 2048 \ - -validity 10000 \ - -deststoretype pkcs12 \ - -dname "CN=, OU=, O=, L=, S=, C=" \ - -keystore "$out" \ - -alias "${KEYSTORE_ALIAS}" \ - -storepass "${KEYSTORE_PASSWORD}" \ - -keypass "${KEYSTORE_KEY_PASSWORD}" \ - >&2 - ''; - - shellHook = '' - export KEYSTORE_ALIAS="${KEYSTORE_ALIAS}" - export KEYSTORE_PASSWORD="${KEYSTORE_PASSWORD}" - export KEYSTORE_KEY_PASSWORD="${KEYSTORE_KEY_PASSWORD}" - ''; -} diff --git a/nix/mobile/android/release.nix b/nix/mobile/android/release.nix index afeae2fe24ac..b8b634cf5f5d 100644 --- a/nix/mobile/android/release.nix +++ b/nix/mobile/android/release.nix @@ -1,6 +1,6 @@ { stdenv, pkgs, deps, lib, config, callPackage, watchmanFactory, androidPkgs, patchMavenSources, - keystore, jsbundle, status-go }: + jsbundle, status-go }: { # Value for BUILD_ENV checked by Clojure code at compile time @@ -28,9 +28,6 @@ let gradleOpts = getConfig "android.gradle-opts" null; # Used to detect end-to-end builds androidAbiInclude = getConfig "android.abi-include" "armeabi-v7a;arm64-v8a;x86"; - # Keystore can be provided via config and extra-sandbox-paths. - # If it is not we use an ad-hoc one generated with default password. - keystorePath = getConfig "android.keystore-path" keystore; baseName = "${buildType}-android"; name = "status-react-build-${baseName}"; @@ -76,7 +73,6 @@ in stdenv.mkDerivation rec { # custom env variables derived from config STATUS_GO_SRC_OVERRIDE = getConfig "status-go.src-override" null; - ANDROID_APK_SIGNED = getConfig "android.apk-signed" "true"; ANDROID_ABI_SPLIT = getConfig "android.abi-split" "false"; ANDROID_ABI_INCLUDE = androidAbiInclude; @@ -88,8 +84,7 @@ in stdenv.mkDerivation rec { STATUS_GO_ANDROID_LIBDIR = status-go { inherit secretsFile; }; phases = [ - "unpackPhase" "secretsPhase" "keystorePhase" - "buildPhase" "checkPhase" "installPhase" + "unpackPhase" "secretsPhase" "buildPhase" "checkPhase" "installPhase" ]; unpackPhase = '' @@ -120,21 +115,13 @@ in stdenv.mkDerivation rec { ${patchMavenSources} ./android/build.gradle ''; - # if secretsFile is not set we use generate keystore + # Secrets file is passed to sandbox using extra-sandbox-paths. secretsPhase = if (secretsFile != "") then '' source "${secretsFile}" - ${checkEnvVarSet "KEYSTORE_ALIAS"} - ${checkEnvVarSet "KEYSTORE_PASSWORD"} - ${checkEnvVarSet "KEYSTORE_KEY_PASSWORD"} - '' else keystore.shellHook; - - # if keystorePath is set copy it into build directory - keystorePhase = - assert assertMsg (keystorePath != null) "keystorePath has to be set!"; - '' - export KEYSTORE_PATH="$PWD/status-im.keystore" - cp -a --no-preserve=ownership "${keystorePath}" "$KEYSTORE_PATH" + '' else '' + echo 'WARNING: No secrets provided!' >&2 ''; + buildPhase = let adhocEnvVars = optionalString stdenv.isLinux "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${makeLibraryPath [ pkgs.zlib ]}"; diff --git a/nix/scripts/build.sh b/nix/scripts/build.sh index 628a8a55abcb..e5088676ce89 100755 --- a/nix/scripts/build.sh +++ b/nix/scripts/build.sh @@ -58,7 +58,7 @@ nixOpts=( ${GIT_ROOT}/nix/scripts/gcroots.sh "${TARGET}" "${@}" # Run the actual build -echo "Running: nix-build "${nixOpts[@]}" "${@}" default.nix" +echo "${GRN}Running:${RST} nix-build "${nixOpts[@]}" "${@}" default.nix" nixResultPath=$(nix-build "${nixOpts[@]}" "${@}" default.nix) echo -e "\n${YLW}Extracting result${RST}: ${BLD}${nixResultPath}${RST}" diff --git a/scripts/release-android.sh b/scripts/build-android.sh similarity index 84% rename from scripts/release-android.sh rename to scripts/build-android.sh index 6077551e4a6c..2016f82cb140 100755 --- a/scripts/release-android.sh +++ b/scripts/build-android.sh @@ -26,13 +26,9 @@ config='' if [[ -n "${STATUS_GO_SRC_OVERRIDE}" ]]; then config+="status-im.status-go.src-override=\"${STATUS_GO_SRC_OVERRIDE}\";" fi -if [[ "${ANDROID_APK_SIGNED}" == "true" ]]; then - config+="status-im.android.keystore-path=\"$(must_get_env KEYSTORE_PATH)\";" -fi config+="status-im.commit-hash=\"$(git rev-parse --verify HEAD)\";" config+="status-im.build-type=\"$(must_get_env BUILD_TYPE)\";" config+="status-im.build-number=\"$(must_get_env BUILD_NUMBER)\";" -config+="status-im.android.apk-signed=\"$(must_get_env ANDROID_APK_SIGNED)\";" config+="status-im.android.abi-split=\"$(must_get_env ANDROID_ABI_SPLIT)\";" config+="status-im.android.abi-include=\"$(must_get_env ANDROID_ABI_INCLUDE)\";" nixOpts=() @@ -43,22 +39,15 @@ chmod 644 ${SECRETS_FILE_PATH} # If secrets file was created we want to remove it. trap "rm -vf ${SECRETS_FILE_PATH}" EXIT ERR INT QUIT # Secrets like this can't be passed via args or they end up in derivation. -if [[ -n "${KEYSTORE_ALIAS}${KEYSTORE_ALIAS}${KEYSTORE_ALIAS}" ]]; then - # WARNING: All three have to be set! - append_env_export 'KEYSTORE_PASSWORD' - append_env_export 'KEYSTORE_ALIAS' - append_env_export 'KEYSTORE_KEY_PASSWORD' -fi if [[ -n "${INFURA_TOKEN}" ]]; then append_env_export 'INFURA_TOKEN' fi if [[ -n "${OPENSEA_API_KEY}" ]]; then append_env_export 'OPENSEA_API_KEY' fi - # Used by Clojure at compile time for remove import of react-native-notifications for fdroid release if [[ -n "${READER_FEATURES}" ]]; then - append_env_export 'READER_FEATURES' + append_env_export 'READER_FEATURES' fi # If no secrets were passed there's no need to pass the 'secretsFile'. diff --git a/scripts/generate-keystore.sh b/scripts/generate-keystore.sh index 592a0c14c38b..0b3fc20151c7 100755 --- a/scripts/generate-keystore.sh +++ b/scripts/generate-keystore.sh @@ -32,7 +32,6 @@ KEYSTORE_PATH=${KEYSTORE_PATH/#\~/$HOME} if [[ -e "${KEYSTORE_PATH}" ]]; then echo -e "${YLW}Keystore file already exists:${RST} ${KEYSTORE_PATH}" >&2 - echo "${KEYSTORE_PATH}" exit 0 fi @@ -41,7 +40,7 @@ KEYSTORE_DIR=$(dirname "${KEYSTORE_PATH}") echo -e "${GRN}Generating keystore...${RST}" >&2 -keytool -genkey -v \ +exec keytool -genkey -v \ -keyalg RSA \ -keysize 2048 \ -validity 10000 \ @@ -52,5 +51,3 @@ keytool -genkey -v \ -storepass "${KEYSTORE_PASSWORD}" \ -keypass "${KEYSTORE_KEY_PASSWORD}" \ > /dev/stderr - -echo "${KEYSTORE_PATH}" diff --git a/scripts/sign-android.sh b/scripts/sign-android.sh new file mode 100755 index 000000000000..cc5a6c932bc3 --- /dev/null +++ b/scripts/sign-android.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -e + +GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel) +source "${GIT_ROOT}/scripts/colors.sh" + +function property() { + grep "${2}" "${1}" | cut -d'=' -f2 +} + +function gradle_property() { + property ${GIT_ROOT}/android/gradle.properties ${1} +} + +function env_var_or_gradle_prop() { + VAR_NAME="${1}" + if [[ -n "${!VAR_NAME}" ]]; then + echo "${!VAR_NAME}" + else + gradle_property "${VAR_NAME}" + fi +} + +function must_get_env() { + declare -n VAR_VALUE="$1" + if [[ -n "${VAR_VALUE}" ]]; then + echo "${VAR_VALUE}" + return + fi + echo -e "${RED}No required env variable:${RST} ${BLD}${!VAR_VALUE}${RST}" 1>&2 + exit 1 +} + +echo -e "${GRN}Signing APK:${RST} ${@}" >&2 + +exec jarsigner \ + -keystore "$(env_var_or_gradle_prop KEYSTORE_PATH)" \ + -storepass "$(env_var_or_gradle_prop KEYSTORE_PASSWORD)" \ + -keypass "$(env_var_or_gradle_prop KEYSTORE_KEY_PASSWORD)" \ + "${@}" "$(env_var_or_gradle_prop KEYSTORE_ALIAS)"