From 0cead2ccb04436825bfd351841b8bb96dd5fe6ec Mon Sep 17 00:00:00 2001 From: izzy2lost Date: Wed, 13 Aug 2025 22:01:12 -0400 Subject: [PATCH] Add release stuff --- .github/workflows/android.yml | 65 ++++++++++++- .github/workflows/release.yml | 165 +++++++++++++++++++++++++++++++++ .gitignore | 5 + android/app/build.gradle | 72 +++++++++++++- android/app/proguard-rules.pro | 64 ++++++++++--- 5 files changed, 347 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index bd6a490c..06a34a70 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -2,6 +2,11 @@ name: Android Build on: push: + branches: [ main, master, develop ] + pull_request: + branches: [ main, master ] + release: + types: [ published ] concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -46,27 +51,77 @@ jobs: build-android: needs: generate-port-o2r runs-on: ubuntu-24.04 + strategy: + matrix: + build-type: [debug, release] steps: - uses: actions/checkout@v4 with: submodules: true + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + - name: Install dependencies run: sudo apt-get install -y ninja-build + - name: Download starship.o2r uses: actions/download-artifact@v4 with: name: starship.o2r path: android/app/src/main/assets + - name: Configure Gradle permissions run: chmod +x android/gradlew - - name: Build Starship + + - name: Setup Gradle cache + uses: gradle/actions/setup-gradle@v3 + with: + cache-read-only: ${{ github.ref != 'refs/heads/main' }} + + - name: Build Debug APK + if: matrix.build-type == 'debug' run: | cd android/ ./gradlew assembleDebug -P elfBuildType=RelWithDebInfo - mv app/build/outputs/apk/debug/app-debug.apk ../starship.apk - - name: Upload APK artifact + mv app/build/outputs/apk/debug/app-debug.apk ../starship-debug.apk + + - name: Setup signing keystore + if: matrix.build-type == 'release' && env.KEYSTORE_FILE != '' + run: | + echo "${{ secrets.KEYSTORE_FILE }}" | base64 -d > android/starship-release-key.keystore + echo "STARSHIP_STORE_FILE=starship-release-key.keystore" >> android/keystore.properties + echo "STARSHIP_STORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> android/keystore.properties + echo "STARSHIP_KEY_ALIAS=${{ secrets.KEY_ALIAS }}" >> android/keystore.properties + echo "STARSHIP_KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> android/keystore.properties + env: + KEYSTORE_FILE: ${{ secrets.KEYSTORE_FILE }} + + - name: Build Release APK + if: matrix.build-type == 'release' + run: | + cd android/ + ./gradlew assembleRelease -P elfBuildType=Release + mv app/build/outputs/apk/release/app-release.apk ../starship-release.apk + + - name: Upload Debug APK + if: matrix.build-type == 'debug' uses: actions/upload-artifact@v4 with: - name: starship-apk - path: starship.apk + name: starship-debug-apk + path: starship-debug.apk + retention-days: 7 + + - name: Upload Release APK + if: matrix.build-type == 'release' + uses: actions/upload-artifact@v4 + with: + name: starship-release-apk + path: starship-release.apk + retention-days: 30 + + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..7302908c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,165 @@ +name: Create Release + +on: + workflow_dispatch: + inputs: + version: + description: 'Release version (e.g., 1.0.1)' + required: true + default: '1.0.1' + prerelease: + description: 'Mark as pre-release' + required: false + default: false + type: boolean + +jobs: + generate-port-o2r: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Install dependencies + run: sudo apt-get install gcc g++ git cmake ninja-build lsb-release + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2.18 + with: + key: ${{ runner.os }}-o2r-ccache-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-o2r-ccache-${{ github.ref }} + ${{ runner.os }}-o2r-ccache- + - name: Cache build folders + uses: actions/cache@v4 + with: + key: ${{ runner.os }}-o2r-build-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-o2r-build-${{ github.ref }} + ${{ runner.os }}-o2r-build- + path: | + tools/Torch/cmake-build-release + - name: Generate starship.o2r + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + make -C tools/Torch type=release -j3 + tools/Torch/cmake-build-release/torch pack port starship.o2r o2r + - uses: actions/upload-artifact@v4 + with: + name: starship.o2r + path: starship.o2r + retention-days: 1 + + build-release: + needs: generate-port-o2r + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Install dependencies + run: sudo apt-get install -y ninja-build + + - name: Download starship.o2r + uses: actions/download-artifact@v4 + with: + name: starship.o2r + path: android/app/src/main/assets + + - name: Update version in build.gradle + run: | + sed -i "s/versionName \".*\"/versionName \"${{ github.event.inputs.version }}\"/" android/app/build.gradle + # Increment version code + CURRENT_CODE=$(grep "versionCode" android/app/build.gradle | sed 's/.*versionCode \([0-9]*\).*/\1/') + NEW_CODE=$((CURRENT_CODE + 1)) + sed -i "s/versionCode $CURRENT_CODE/versionCode $NEW_CODE/" android/app/build.gradle + echo "Updated to version ${{ github.event.inputs.version }} with code $NEW_CODE" + + - name: Configure Gradle permissions + run: chmod +x android/gradlew + + - name: Setup Gradle cache + uses: gradle/actions/setup-gradle@v3 + + - name: Setup signing keystore + if: env.KEYSTORE_FILE != '' + run: | + echo "${{ secrets.KEYSTORE_FILE }}" | base64 -d > android/starship-release-key.keystore + echo "STARSHIP_STORE_FILE=starship-release-key.keystore" >> android/keystore.properties + echo "STARSHIP_STORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> android/keystore.properties + echo "STARSHIP_KEY_ALIAS=${{ secrets.KEY_ALIAS }}" >> android/keystore.properties + echo "STARSHIP_KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> android/keystore.properties + env: + KEYSTORE_FILE: ${{ secrets.KEYSTORE_FILE }} + + - name: Build Release + run: | + cd android/ + ./gradlew clean + ./gradlew assembleRelease -P elfBuildType=Release --no-daemon + + - name: Verify APK signing + run: | + if [ -f android/starship-release-key.keystore ]; then + echo "✅ APK will be signed with release keystore" + else + echo "⚠️ APK will be signed with debug keystore (unsigned release)" + fi + + - name: Prepare release files + run: | + mkdir -p release + cp android/app/build/outputs/apk/release/app-release.apk release/starship-v${{ github.event.inputs.version }}.apk + + - name: Generate checksums + run: | + cd release + sha256sum *.apk > checksums.txt + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ github.event.inputs.version }} + name: Starship v${{ github.event.inputs.version }} + body: | + ## 🚀 Starship v${{ github.event.inputs.version }} + + ### 📱 Android Release + + **What's New:** + - Optimized release build with R8 code shrinking + - Improved performance and reduced APK size + - Enhanced file management with SAF integration + + ### 📦 Downloads + - **APK**: `starship-v${{ github.event.inputs.version }}.apk` - Direct install for Android devices + + ### 🔧 Installation Instructions + 1. Download the APK file + 2. Enable "Install from unknown sources" in Android settings + 3. Install the APK on your Android device + 4. Use [Torch](https://github.com/izzy2lost/Torch/releases) to extract your Star Fox 64 ROM + 5. Launch Starship and select your game folder + + ### ✅ Requirements + - Android 7.0 (API 24) or higher + - ARM64 or ARMv7 processor + - Star Fox 64 ROM (US 1.0 or 1.1) + + ### 🔒 Security + SHA256 checksums are provided in `checksums.txt` + + --- + Built from commit: ${{ github.sha }} + files: | + release/* + draft: false + prerelease: ${{ github.event.inputs.prerelease }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0ef6aa29..9e00e9f3 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,11 @@ ctx.c.m2c *.otr *.o2r *.log + +# Android signing +*.keystore +*.jks +keystore.properties *.eeprom assets/yaml/us/ast_test.yaml /audio_data diff --git a/android/app/build.gradle b/android/app/build.gradle index 73da3d25..2bce78d5 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,11 +7,30 @@ else { apply plugin: 'com.android.library' } +// Load keystore properties +def keystorePropertiesFile = rootProject.file("keystore.properties") +def keystoreProperties = new Properties() +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + android { namespace("com.starship.android") buildFeatures { buildConfig true } + + // Signing configuration + signingConfigs { + release { + if (keystorePropertiesFile.exists()) { + storeFile file(keystoreProperties['STARSHIP_STORE_FILE']) + storePassword keystoreProperties['STARSHIP_STORE_PASSWORD'] + keyAlias keystoreProperties['STARSHIP_KEY_ALIAS'] + keyPassword keystoreProperties['STARSHIP_KEY_PASSWORD'] + } + } + } ndkVersion "26.0.10792818" compileSdkVersion 33 defaultConfig { @@ -20,14 +39,19 @@ android { } minSdkVersion 24 targetSdkVersion 33 - versionCode 5 - versionName "1.0.0" + versionCode 6 + versionName "1.0.1" externalNativeBuild { cmake { arguments "-DSDL_SHARED=ON", "-DANDROID_STL=c++_static", "-DHAVE_LD_VERSION_SCRIPT=OFF",'-DUSE_OPENGLES=ON' abiFilters 'arm64-v8a', 'armeabi-v7a' } } + + // Optimize APK size + vectorDrawables { + useSupportLibrary true + } } // ✅ Universal APK: disables split APKs per ABI @@ -38,9 +62,31 @@ android { } buildTypes { - release { + debug { + debuggable true + jniDebuggable true minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + shrinkResources false + } + release { + debuggable false + jniDebuggable false + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + + // Enable R8 full mode for better optimization + android.enableR8.fullMode = true + + // Optimize native libraries + ndk { + debugSymbolLevel 'NONE' + } + + // Sign the release build + if (keystorePropertiesFile.exists()) { + signingConfig signingConfigs.release + } } } applicationVariants.all { variant -> @@ -60,8 +106,26 @@ android { } lintOptions { abortOnError false + checkReleaseBuilds false } + // Additional optimizations + packagingOptions { + // Exclude unnecessary files to reduce APK size + excludes += [ + 'META-INF/DEPENDENCIES', + 'META-INF/LICENSE', + 'META-INF/LICENSE.txt', + 'META-INF/NOTICE', + 'META-INF/NOTICE.txt', + 'META-INF/*.kotlin_module' + ] + // Pick first occurrence of duplicate files + pickFirsts += ['**/libc++_shared.so', '**/libjsc.so'] + } + + + if (buildAsLibrary) { libraryVariants.all { variant -> variant.outputs.each { output -> diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index eaf0e916..39a969ba 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -1,17 +1,51 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in [sdk]/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html +# Starship Android ProGuard Rules -# Add any project specific keep options here: +# Keep SDL classes +-keep class org.libsdl.app.** { *; } -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} +# Keep native methods +-keepclasseswithmembernames class * { + native ; +} + +# Keep MainActivity and its native methods +-keep class com.starship.android.MainActivity { + public static java.lang.String getSaveDir(); + public static void waitForSetupFromNative(); + public native void attachController(); + public native void detachController(); + public native void setButton(int, boolean); + public native void setCameraState(int, float); + public native void setAxis(int, short); +} + +# Keep DialogActivity +-keep class com.starship.android.DialogActivity { *; } + +# Keep ControllerButtons constants +-keep class com.starship.android.ControllerButtons { *; } + +# Keep DocumentFile for SAF +-keep class androidx.documentfile.provider.DocumentFile { *; } + +# Optimization settings +-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* +-optimizationpasses 5 +-allowaccessmodification +-dontpreverify + +# Remove logging in release builds +-assumenosideeffects class android.util.Log { + public static boolean isLoggable(java.lang.String, int); + public static int v(...); + public static int i(...); + public static int w(...); + public static int d(...); + public static int e(...); +} + +# Keep line numbers for crash reports +-keepattributes SourceFile,LineNumberTable + +# Rename source file attribute to something shorter +-renamesourcefileattribute SourceFile