diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml new file mode 100644 index 0000000..3e49e0f --- /dev/null +++ b/.forgejo/workflows/release.yml @@ -0,0 +1,62 @@ +name: Release APK + +on: + push: + tags: ["v*"] + +jobs: + build: + runs-on: android + + steps: + - uses: actions/checkout@v4 + + - name: Extract version + run: | + VERSION=$(grep '^version:' app/pubspec.yaml | sed 's/version: //') + echo "VERSION_CODE=$(echo "$VERSION" | grep -oP '(?<=\+)\d+')" >> $GITHUB_ENV + echo "VERSION_NAME=$(echo "$VERSION" | grep -oP '^[^+]+')" >> $GITHUB_ENV + + - name: Decode keystore + run: | + echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > app/android/app/release.jks + echo "KEYSTORE_PATH=$GITHUB_WORKSPACE/app/android/app/release.jks" >> $GITHUB_ENV + + - name: Build release APK + env: + STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }} + KEY_ALIAS: ${{ secrets.KEY_ALIAS }} + KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} + # Host-mode runners share ~/.gradle (including the daemon) across + # unrelated projects; a warm daemon from another build can poison + # this one. Keep caches shared, just don't attach to a daemon. + GRADLE_OPTS: -Dorg.gradle.daemon=false + run: | + cd app + env -u GITHUB_TOKEN -u GH_TOKEN -u JAVA_HOME \ + devbox run -- flutter build apk --release + + - name: Create release and upload APK + env: + FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + APK="mews-${{ env.VERSION_NAME }}.apk" + cp app/build/app/outputs/flutter-apk/app-release.apk "$APK" + + BODY=$(python3 -c " + import json + print(json.dumps(open('app/fastlane/metadata/android/en-US/changelogs/${{ env.VERSION_CODE }}.txt').read().strip())) + ") + + RELEASE_ID=$(curl -sf -X POST \ + -H "Authorization: token $FORGEJO_TOKEN" \ + -H "Content-Type: application/json" \ + "$GITHUB_SERVER_URL/api/v1/repos/$GITHUB_REPOSITORY/releases" \ + -d "{\"tag_name\":\"$GITHUB_REF_NAME\",\"name\":\"$GITHUB_REF_NAME\",\"body\":$BODY}" \ + | python3 -c 'import sys,json; print(json.load(sys.stdin)["id"])') + + curl -sf -X POST \ + -H "Authorization: token $FORGEJO_TOKEN" \ + -H "Content-Type: application/vnd.android.package-archive" \ + "$GITHUB_SERVER_URL/api/v1/repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID/assets?name=$APK" \ + --data-binary @"$APK" diff --git a/app/android/app/build.gradle.kts b/app/android/app/build.gradle.kts index 8674251..9094354 100644 --- a/app/android/app/build.gradle.kts +++ b/app/android/app/build.gradle.kts @@ -23,21 +23,28 @@ android { } defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId = "page.mews.mews" - // You can update the following values to match your application needs. - // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode versionName = flutter.versionName } + signingConfigs { + create("release") { + storeFile = System.getenv("KEYSTORE_PATH")?.let { file(it) } + storePassword = System.getenv("STORE_PASSWORD") + keyAlias = System.getenv("KEY_ALIAS") + keyPassword = System.getenv("KEY_PASSWORD") + } + } + buildTypes { release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.getByName("debug") + // Falls back to the debug keys locally, so `flutter run --release` + // keeps working without a keystore on hand. + signingConfig = if (System.getenv("KEYSTORE_PATH") != null) + signingConfigs.getByName("release") else signingConfigs.getByName("debug") } } } diff --git a/app/fastlane/Fastfile b/app/fastlane/Fastfile new file mode 100644 index 0000000..87707fa --- /dev/null +++ b/app/fastlane/Fastfile @@ -0,0 +1 @@ +default_platform(:android) diff --git a/app/fastlane/metadata/android/en-US/changelogs/1.txt b/app/fastlane/metadata/android/en-US/changelogs/1.txt new file mode 100644 index 0000000..0b524c9 --- /dev/null +++ b/app/fastlane/metadata/android/en-US/changelogs/1.txt @@ -0,0 +1 @@ +First release. diff --git a/app/fastlane/metadata/android/en-US/full_description.txt b/app/fastlane/metadata/android/en-US/full_description.txt new file mode 100644 index 0000000..3c6eea6 --- /dev/null +++ b/app/fastlane/metadata/android/en-US/full_description.txt @@ -0,0 +1,7 @@ +The Mews Browser is a reader for Mews pages, Gemini capsules, and Spartan +sites. It's local-first: pages, bookmarks, subscriptions, and reading +settings live in a local database, and network access only revalidates the +cache. + +The reader controls presentation, not the page author, so every site reads +consistently in the typeface, size, and color you choose. diff --git a/app/fastlane/metadata/android/en-US/images/icon.png b/app/fastlane/metadata/android/en-US/images/icon.png new file mode 100644 index 0000000..dcddcd8 Binary files /dev/null and b/app/fastlane/metadata/android/en-US/images/icon.png differ diff --git a/app/fastlane/metadata/android/en-US/short_description.txt b/app/fastlane/metadata/android/en-US/short_description.txt new file mode 100644 index 0000000..4646e2b --- /dev/null +++ b/app/fastlane/metadata/android/en-US/short_description.txt @@ -0,0 +1 @@ +A local-first reader for Mews pages, Gemini capsules, and Spartan sites. diff --git a/app/fastlane/metadata/android/en-US/title.txt b/app/fastlane/metadata/android/en-US/title.txt new file mode 100644 index 0000000..fc0ecb6 --- /dev/null +++ b/app/fastlane/metadata/android/en-US/title.txt @@ -0,0 +1 @@ +The Mews Browser