Skip to content

Commit

Permalink
feat: add GitHub Actions workflow for automated releases
Browse files Browse the repository at this point in the history
- Add GitHub Actions workflow for building and releasing APK/AAB
- Create scripts for keystore management
- Update documentation with release process
- Configure gradle for environment-based signing
  • Loading branch information
EXTREMOPHILARUM committed Nov 25, 2024
1 parent 9b69c1e commit c0b19ae
Show file tree
Hide file tree
Showing 9 changed files with 322 additions and 4 deletions.
10 changes: 10 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Android Release Signing Configuration
ANDROID_STORE_PASSWORD=your_keystore_password
ANDROID_KEY_ALIAS=your_key_alias
ANDROID_KEY_PASSWORD=your_key_password

# Note: Replace the values above with your actual keystore credentials
# To use this file:
# 1. Copy this file to .env
# 2. Replace the placeholder values with your actual keystore credentials
# 3. Make sure your release.keystore file is in android/app/
89 changes: 89 additions & 0 deletions .github/workflows/android-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Android Release

on:
push:
tags:
- 'v*'

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Set up JDK
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
cache: 'gradle'

- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Create release keystore
env:
RELEASE_KEYSTORE: ${{ secrets.RELEASE_KEYSTORE }}
run: |
echo "$RELEASE_KEYSTORE" | base64 -d > android/app/release.keystore
- name: Create .env file
env:
ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
run: |
echo "ANDROID_STORE_PASSWORD=$ANDROID_STORE_PASSWORD" > .env
echo "ANDROID_KEY_ALIAS=$ANDROID_KEY_ALIAS" >> .env
echo "ANDROID_KEY_PASSWORD=$ANDROID_KEY_PASSWORD" >> .env
- name: Build Release APK
run: |
cd android
./gradlew assembleRelease
- name: Build Release Bundle
run: |
cd android
./gradlew bundleRelease
- name: Get version from tag
id: get_version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT

- name: Create Release
uses: softprops/action-gh-release@v1
with:
name: Release ${{ steps.get_version.outputs.VERSION }}
files: |
android/app/build/outputs/apk/release/app-release.apk
android/app/build/outputs/bundle/release/app-release.aab
body: |
Release ${{ steps.get_version.outputs.VERSION }}
### Installation
- Download and install the APK on your Android device
- Alternatively, wait for the Play Store release
### Note
The AAB file is for Play Store submission only. For direct installation, use the APK.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,10 @@ yarn-error.log
!.yarn/releases
!.yarn/sdks
!.yarn/versions

# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
104 changes: 104 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,110 @@ All styling is implemented using NativeWind (Tailwind CSS for React Native), pro
- Easy theme customization
- Utility-first CSS approach
## GitHub Actions Release
The project includes a GitHub Actions workflow that automatically builds and releases the app when you push a new version tag. Here's how to set it up:
1. Encode your keystore for GitHub secrets:
```bash
npm run android:encode-keystore
```
This will output your keystore and signing information in the correct format for GitHub secrets.

2. Add the following secrets to your GitHub repository:
- `RELEASE_KEYSTORE`: The base64-encoded keystore file
- `ANDROID_STORE_PASSWORD`: Your keystore password
- `ANDROID_KEY_ALIAS`: Your key alias
- `ANDROID_KEY_PASSWORD`: Your key password

To add these secrets:
1. Go to your repository settings
2. Navigate to Secrets and Variables > Actions
3. Click "New repository secret"
4. Add each secret with its corresponding value

3. Create and push a new version tag to trigger a release:
```bash
git tag v1.0.0 # Use appropriate version number
git push origin v1.0.0
```

The workflow will:
- Build both APK and AAB files
- Create a new GitHub release
- Attach the built files to the release

The APK can be downloaded and installed directly on Android devices, while the AAB is for Play Store submission.

## Building Release APK

### Creating a Release Keystore

Before building a release APK, you need to create a keystore file to sign your app. This is required for publishing to the Google Play Store and for installing release builds on Android devices.

1. Run the interactive keystore creation script:
```bash
npm run android:create-keystore
```

The script will prompt you for:
- Keystore password
- Key alias (typically your app name)
- Key password
- Your name (CN)
- Organizational unit (OU)
- Organization (O)
- City/Locality (L)
- State/Province (ST)
- Country code (C)

The script will:
- Create the keystore file at `android/app/release.keystore`
- Generate a `.env` file with the necessary credentials
- Display the credentials for your records

2. Keep the following information safe:
- Keystore file (`release.keystore`)
- Keystore password
- Key alias
- Key password

**Important**: You'll need these same credentials to sign all future updates of your app. If you lose them, you won't be able to publish updates to the Play Store under the same app listing.

### Building the APK

1. Make sure your `.env` file contains the correct keystore credentials and the `release.keystore` file is in the `android/app/` directory.

2. Build the release APK using npm script:
```bash
npm run android:release
```

This command will:
- Load your environment variables
- Navigate to the Android directory
- Build the release APK
- Return to the project root

3. The signed APK will be generated at:
```
android/app/build/outputs/apk/release/app-release.apk
```

**Note**: Keep your `.env` file and `release.keystore` secure and never commit them to version control. The same keystore must be used for all future updates of your app.

### Additional Commands

- Clean Android build:
```bash
npm run clean:android
```

- Create an Android App Bundle (for Play Store submission):
```bash
npm run android:bundle
```

## Testing

Run the test suite:
Expand Down
15 changes: 12 additions & 3 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,24 @@ android {
keyAlias 'androiddebugkey'
keyPassword 'android'
}
release {
def keystoreFile = file(MYAPP_RELEASE_STORE_FILE)
if (keystoreFile.exists()) {
storeFile keystoreFile
storePassword System.getenv("ANDROID_STORE_PASSWORD") ?: MYAPP_RELEASE_STORE_PASSWORD
keyAlias System.getenv("ANDROID_KEY_ALIAS") ?: MYAPP_RELEASE_KEY_ALIAS
keyPassword System.getenv("ANDROID_KEY_PASSWORD") ?: MYAPP_RELEASE_KEY_PASSWORD
} else {
logger.warn("Release keystore file not found: " + keystoreFile.absolutePath)
}
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
signingConfig signingConfigs.release
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
Expand Down
6 changes: 6 additions & 0 deletions android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,9 @@ newArchEnabled=true
# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
hermesEnabled=true

# Signing configuration - using environment variables
MYAPP_RELEASE_STORE_FILE=release.keystore
MYAPP_RELEASE_KEY_ALIAS=$ANDROID_KEY_ALIAS
MYAPP_RELEASE_STORE_PASSWORD=$ANDROID_STORE_PASSWORD
MYAPP_RELEASE_KEY_PASSWORD=$ANDROID_KEY_PASSWORD
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
"ios:device": "react-native run-ios --device",
"ios:iphone14": "react-native run-ios --simulator='iPhone 14'",
"android:clean-run": "cd android && ./gradlew clean && cd .. && react-native run-android",
"android:release": "cd android && ./gradlew assembleRelease && cd ..",
"android:release": "source .env && cd android && ./gradlew assembleRelease && cd ..",
"android:bundle": "cd android && ./gradlew bundleRelease && cd ..",
"android:create-keystore": "./scripts/create-keystore.sh",
"android:encode-keystore": "./scripts/encode-keystore.sh",
"postinstall": "patch-package"
},
"dependencies": {
Expand Down
55 changes: 55 additions & 0 deletions scripts/create-keystore.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/bin/bash

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

echo -e "${BLUE}Android Release Keystore Creation Script${NC}\n"

# Get keystore details
read -p "Enter keystore password: " STORE_PASSWORD
read -p "Enter key alias (e.g., app name): " KEY_ALIAS
read -p "Enter key password (can be same as keystore password): " KEY_PASSWORD
read -p "Enter your name (CN): " CN
read -p "Enter your organizational unit (OU): " OU
read -p "Enter your organization (O): " O
read -p "Enter your city/locality (L): " L
read -p "Enter your state/province (ST): " ST
read -p "Enter your country code (C, e.g., US): " C

# Create android/app directory if it doesn't exist
mkdir -p android/app

# Generate the keystore
keytool -genkeypair -v \
-storetype PKCS12 \
-keystore android/app/release.keystore \
-alias "$KEY_ALIAS" \
-keyalg RSA \
-keysize 2048 \
-validity 10000 \
-storepass "$STORE_PASSWORD" \
-keypass "$KEY_PASSWORD" \
-dname "CN=$CN, OU=$OU, O=$O, L=$L, ST=$ST, C=$C"

# Check if keystore was created successfully
if [ $? -eq 0 ]; then
echo -e "\n${GREEN}Keystore created successfully at android/app/release.keystore${NC}"

# Create/update .env file
echo "# Android Release Signing Configuration" > .env
echo "ANDROID_STORE_PASSWORD=$STORE_PASSWORD" >> .env
echo "ANDROID_KEY_ALIAS=$KEY_ALIAS" >> .env
echo "ANDROID_KEY_PASSWORD=$KEY_PASSWORD" >> .env

echo -e "${GREEN}Environment variables written to .env file${NC}"
echo -e "\n${BLUE}Keep these values safe - you'll need them for future app updates:${NC}"
echo -e "Keystore password: ${GREEN}$STORE_PASSWORD${NC}"
echo -e "Key alias: ${GREEN}$KEY_ALIAS${NC}"
echo -e "Key password: ${GREEN}$KEY_PASSWORD${NC}"
else
echo -e "\n${RED}Failed to create keystore${NC}"
exit 1
fi
36 changes: 36 additions & 0 deletions scripts/encode-keystore.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/bash

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

KEYSTORE_PATH="android/app/release.keystore"

if [ ! -f "$KEYSTORE_PATH" ]; then
echo -e "${RED}Error: Keystore file not found at $KEYSTORE_PATH${NC}"
echo -e "Please run 'npm run android:create-keystore' first to create the keystore."
exit 1
fi

echo -e "${BLUE}Encoding keystore for GitHub Secrets...${NC}"
ENCODED_KEYSTORE=$(base64 -i "$KEYSTORE_PATH")

echo -e "\n${GREEN}Add the following secrets to your GitHub repository:${NC}"
echo -e "\n${BLUE}RELEASE_KEYSTORE:${NC}"
echo "$ENCODED_KEYSTORE"

if [ -f ".env" ]; then
echo -e "\n${BLUE}Other required secrets from .env:${NC}"
echo -e "ANDROID_STORE_PASSWORD: $(grep ANDROID_STORE_PASSWORD .env | cut -d '=' -f2)"
echo -e "ANDROID_KEY_ALIAS: $(grep ANDROID_KEY_ALIAS .env | cut -d '=' -f2)"
echo -e "ANDROID_KEY_PASSWORD: $(grep ANDROID_KEY_PASSWORD .env | cut -d '=' -f2)"
else
echo -e "\n${RED}Warning: .env file not found. Make sure to set up your signing configuration.${NC}"
fi

echo -e "\n${BLUE}Add these secrets in your GitHub repository:${NC}"
echo "1. Go to your repository settings"
echo "2. Navigate to Secrets and Variables > Actions"
echo "3. Add the above values as repository secrets"

0 comments on commit c0b19ae

Please sign in to comment.