react-native-sop-docs/10-release-process/android-release.md

404 lines
9.1 KiB
Markdown

# Android Release Process
## Keystore Generation
### Create Release Keystore
```bash
# Generate a new keystore
keytool -genkeypair -v -storetype PKCS12 -keystore myapp-release-key.keystore -alias myapp-key-alias -keyalg RSA -keysize 2048 -validity 10000
# Verify keystore
keytool -list -v -keystore myapp-release-key.keystore
```
### Keystore Security
```bash
# Store keystore securely
mkdir -p ~/.android/keystores
mv myapp-release-key.keystore ~/.android/keystores/
# Set proper permissions
chmod 600 ~/.android/keystores/myapp-release-key.keystore
```
## Gradle Configuration
### Configure Signing
**android/gradle.properties:**
```properties
# Keystore configuration
MYAPP_UPLOAD_STORE_FILE=myapp-release-key.keystore
MYAPP_UPLOAD_KEY_ALIAS=myapp-key-alias
MYAPP_UPLOAD_STORE_PASSWORD=your_keystore_password
MYAPP_UPLOAD_KEY_PASSWORD=your_key_password
# Build optimization
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.configureondemand=true
org.gradle.daemon=true
# Android configuration
android.useAndroidX=true
android.enableJetifier=true
android.enableR8.fullMode=true
```
**android/app/build.gradle:**
```gradle
android {
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {
applicationId "com.myapp.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0.0"
multiDexEnabled true
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
release {
if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
storeFile file(MYAPP_UPLOAD_STORE_FILE)
storePassword MYAPP_UPLOAD_STORE_PASSWORD
keyAlias MYAPP_UPLOAD_KEY_ALIAS
keyPassword MYAPP_UPLOAD_KEY_PASSWORD
}
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
applicationIdSuffix ".debug"
debuggable true
minifyEnabled false
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
release {
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
debuggable false
zipAlignEnabled true
}
}
splits {
abi {
reset()
enable true
universalApk false
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
}
```
## ProGuard Configuration
**android/app/proguard-rules.pro:**
```proguard
# React Native
-keep class com.facebook.react.** { *; }
-keep class com.facebook.hermes.** { *; }
-keep class com.facebook.jni.** { *; }
# Keep our application class
-keep class com.myapp.** { *; };
# Keep native methods
-keepclassmembers class * {
native <methods>;
}
# Keep enums
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Keep Parcelable implementations
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# Keep serializable classes
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# Firebase
-keep class com.google.firebase.** { *; }
-keep class com.google.android.gms.** { *; }
# OkHttp
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
# Gson
-keepattributes Signature
-keepattributes *Annotation*
-dontwarn sun.misc.**
-keep class com.google.gson.** { *; }
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
```
## Build Process
### Build Commands
```bash
# Clean build
cd android && ./gradlew clean
# Build debug APK
./gradlew assembleDebug
# Build release APK
./gradlew assembleRelease
# Build release AAB (recommended for Play Store)
./gradlew bundleRelease
# Install debug APK
./gradlew installDebug
# Install release APK
./gradlew installRelease
```
### Build Variants
```gradle
android {
flavorDimensions "version"
productFlavors {
development {
dimension "version"
applicationIdSuffix ".dev"
versionNameSuffix "-dev"
buildConfigField "String", "API_BASE_URL", '"https://dev-api.myapp.com"'
resValue "string", "app_name", "MyApp Dev"
}
staging {
dimension "version"
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
buildConfigField "String", "API_BASE_URL", '"https://staging-api.myapp.com"'
resValue "string", "app_name", "MyApp Staging"
}
production {
dimension "version"
buildConfigField "String", "API_BASE_URL", '"https://api.myapp.com"'
resValue "string", "app_name", "MyApp"
}
}
}
```
## Google Play Console Setup
### Create Application
1. **Go to Google Play Console**
2. **Create Application**
- App name: MyApp
- Default language: English
- App or game: App
- Free or paid: Free
3. **App Content**
- Privacy Policy URL
- App category
- Content rating questionnaire
- Target audience
- Data safety form
### Upload Release
```bash
# Build release AAB
cd android && ./gradlew bundleRelease
# AAB file location
# android/app/build/outputs/bundle/release/app-release.aab
```
### Release Tracks
1. **Internal Testing**
- Upload AAB
- Add internal testers
- Release to internal testing
2. **Closed Testing**
- Create closed testing track
- Add test users via email lists
- Release to closed testing
3. **Open Testing**
- Create open testing track
- Set country availability
- Release to open testing
4. **Production**
- Review release
- Set rollout percentage
- Release to production
## Version Management
### Automated Version Bumping
**scripts/bump-android-version.sh:**
```bash
#!/bin/bash
VERSION_TYPE=${1:-patch} # major, minor, patch
BUILD_GRADLE="android/app/build.gradle"
# Get current version
CURRENT_VERSION=$(grep "versionName" $BUILD_GRADLE | sed 's/.*versionName "\(.*\)"/\1/')
CURRENT_CODE=$(grep "versionCode" $BUILD_GRADLE | sed 's/.*versionCode \(.*\)/\1/')
echo "Current version: $CURRENT_VERSION ($CURRENT_CODE)"
# Calculate new version
IFS='.' read -ra VERSION_PARTS <<< "$CURRENT_VERSION"
MAJOR=${VERSION_PARTS[0]}
MINOR=${VERSION_PARTS[1]}
PATCH=${VERSION_PARTS[2]}
case $VERSION_TYPE in
major)
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
;;
minor)
MINOR=$((MINOR + 1))
PATCH=0
;;
patch)
PATCH=$((PATCH + 1))
;;
esac
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
NEW_CODE=$((CURRENT_CODE + 1))
echo "New version: $NEW_VERSION ($NEW_CODE)"
# Update build.gradle
sed -i "s/versionCode $CURRENT_CODE/versionCode $NEW_CODE/" $BUILD_GRADLE
sed -i "s/versionName \"$CURRENT_VERSION\"/versionName \"$NEW_VERSION\"/" $BUILD_GRADLE
echo "Version updated successfully!"
```
### Git Tagging
```bash
# Create and push tag
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
# List tags
git tag -l
# Delete tag
git tag -d v1.0.0
git push origin --delete v1.0.0
```
## Release Checklist
### Pre-Release Checklist
- [ ] Update version number
- [ ] Update changelog
- [ ] Run all tests
- [ ] Test on multiple devices
- [ ] Check ProGuard configuration
- [ ] Verify signing configuration
- [ ] Test release build locally
- [ ] Update app store metadata
- [ ] Prepare release notes
### Post-Release Checklist
- [ ] Monitor crash reports
- [ ] Check app store reviews
- [ ] Monitor performance metrics
- [ ] Update documentation
- [ ] Create git tag
- [ ] Notify team of release
- [ ] Plan next release
## Troubleshooting
### Common Build Issues
```bash
# Clean and rebuild
cd android
./gradlew clean
./gradlew assembleRelease
# Clear React Native cache
npx react-native start --reset-cache
# Clear Metro cache
npx react-native start --reset-cache
# Reset Android build
cd android
rm -rf build/
rm -rf app/build/
./gradlew clean
```
### Keystore Issues
```bash
# Verify keystore
keytool -list -v -keystore your-keystore.keystore
# Check keystore alias
keytool -list -keystore your-keystore.keystore
# Export certificate
keytool -export -alias your-alias -keystore your-keystore.keystore -file certificate.crt
```