Skip to content

feat(android): add mobile shell and Play internal-track workflow#21

Open
ScottShao wants to merge 5 commits into
BAWES-Universe:universefrom
ScottShao:feat/mobile-android
Open

feat(android): add mobile shell and Play internal-track workflow#21
ScottShao wants to merge 5 commits into
BAWES-Universe:universefrom
ScottShao:feat/mobile-android

Conversation

@ScottShao

@ScottShao ScottShao commented May 15, 2026

Copy link
Copy Markdown

Closes #4
Related to #1
/claim #1

Summary

  • add the Capacitor Android platform under mobile/android/ with the net.bawes.universe app id, bawes://callback deep-link intent filter, hardware acceleration, and landscape-only launch behavior
  • replace the generated launcher icons across every mipmap-* density using the repo's existing 512px Universe favicon asset
  • add shared Android Fastlane lanes in mobile/fastlane/ for test, signed build, and Play internal-track deploy
  • add .github/workflows/android-build.yml to run Android unit tests on PRs and perform signed bundle/deploy steps on non-PR runs when the required secrets are configured
  • fix the current mobile/package.json dependency pins so npm ci and npx cap sync android succeed for this slice, and add typescript because the repo uses capacitor.config.ts
  • regenerate mobile/package-lock.json against the public npm registry so CI and outside contributors do not inherit my local private registry settings
  • keep app/src/main/assets/ in git with a placeholder so CI can regenerate the ignored Capacitor config files during cap sync

Acceptance criteria

  • Add Android Capacitor platform under mobile/android/
  • Set applicationId to net.bawes.universe
  • Set minSdkVersion to 26 and targetSdkVersion to 34
  • Add Universe launcher icons to all mipmap-* folders
  • Add bawes://callback deep-link handling
  • Add Fastlane Android build, deploy, and test lanes
  • Add .github/workflows/android-build.yml
  • Upload to Play Store internal track
  • Verify auth deep-link login on a physical Android device
  • Verify gameplay/touch controls on a physical Android device

Verification

  • cd mobile && npm install --package-lock-only --registry=https://registry.npmjs.org
  • cd mobile && npm ci --registry=https://registry.npmjs.org
  • cd mobile && npx cap sync android
  • cd mobile && ruby -c fastlane/Fastfile && ruby -c fastlane/Appfile
  • cd mobile/android && sips -g pixelWidth -g pixelHeight app/src/main/res/mipmap-{mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi}/ic_launcher.png
  • git diff --check

Environment limitations

  • cd mobile/android && ./gradlew test currently stops locally because this machine does not have an Android SDK configured (ANDROID_HOME / local.properties missing)
  • cd mobile && bundle install is blocked locally by the host Ruby/Xcode toolchain (system Ruby 2.6 missing the headers/build environment Fastlane's native gems expect)
  • the Play Store upload and on-device verification steps require the repo secrets plus a real Android device, so those are wired in the workflow/lane configuration but not executable from this CLI environment

Demo

Repo-hosted verification walkthrough GIF:

Android verification walkthrough

@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@ScottShao has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 48 minutes and 3 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d4c634f5-c7bf-4a4c-bc40-943fd2a13876

📥 Commits

Reviewing files that changed from the base of the PR and between 90a4504 and 84af543.

⛔ Files ignored due to path filters (2)
  • mobile/android/demo/verification-demo.gif is excluded by !**/*.gif
  • mobile/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (8)
  • .github/workflows/android-build.yml
  • mobile/android/.gitignore
  • mobile/android/app/build.gradle
  • mobile/android/app/src/main/AndroidManifest.xml
  • mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  • mobile/android/app/src/main/res/xml/file_paths.xml
  • mobile/android/gradlew.bat
  • mobile/package.json
📝 Walkthrough

Walkthrough

This PR establishes a complete Android Capacitor platform with automated build and Play Store deployment. It adds Gradle build infrastructure (SDK/library versions, plugin dependencies), configures the Android app manifest with launcher and deep-link entry points, defines UI resources and MainActivity, sets up Fastlane automation for signing and deployment, integrates a GitHub Actions workflow for testing and release, and configures VCS and dependency rules.

Changes

Android Capacitor Platform & Release Pipeline

Layer / File(s) Summary
Gradle build system and SDK configuration
mobile/android/build.gradle, mobile/android/settings.gradle, mobile/android/variables.gradle, mobile/android/gradle.properties, mobile/android/gradle/wrapper/gradle-wrapper.properties, mobile/android/gradlew, mobile/android/gradlew.bat, mobile/android/capacitor.settings.gradle, mobile/android/app/build.gradle, mobile/android/app/capacitor.build.gradle
Defines the top-level Gradle structure with version-pinned dependencies (Android Gradle Plugin 8.13.0, Google Services 4.4.4), configures Android SDK versions (min 26, target 34, compile 36), wires AndroidX library versions, sets up Capacitor plugin includes, and configures Gradle wrapper distribution (8.14.3).
App manifest, source, and UI resources
mobile/android/app/src/main/AndroidManifest.xml, mobile/android/app/src/main/java/net/bawes/universe/MainActivity.java, mobile/android/app/src/main/res/layout/activity_main.xml, mobile/android/app/src/main/res/drawable*/, mobile/android/app/src/main/res/mipmap-*/, mobile/android/app/src/main/res/values/strings.xml, mobile/android/app/src/main/res/values/styles.xml, mobile/android/app/src/main/res/xml/file_paths.xml, mobile/android/app/src/androidTest/java/…/ExampleInstrumentedTest.java, mobile/android/app/src/test/java/…/ExampleUnitTest.java, mobile/android/app/proguard-rules.pro, mobile/android/app/src/main/assets/.gitkeep
Declares the main activity with landscape orientation, MAIN/LAUNCHER intent filter, and deep-link support for bawes://callback auth; defines a full-screen WebView layout, app theme (AppCompat with no action bar), launcher icons (adaptive foreground/background), string resources (app name, package name, custom URL scheme), file provider paths, instrumentation runner, and placeholder test files.
Fastlane build and deployment lanes
mobile/fastlane/Appfile, mobile/fastlane/Fastfile, mobile/fastlane/google-play-key.json.example
Configures Fastlane for the net.bawes.universe package with three Android lanes: test runs Gradle test task, build creates a signed Release AAB using environment variable secrets (KEYSTORE_PATH, STORE_PASSWORD, KEY_ALIAS, KEY_PASSWORD), and deploy builds and uploads to Play Store internal track; includes example Google Play service account JSON template.
GitHub Actions CI/CD pipeline
.github/workflows/android-build.yml
Defines a workflow triggered on pull requests, pushes to the universe branch (with Android/mobile path filter), and manual dispatch; orchestrates Node 20, Java 17, Ruby 3.2 setup, Capacitor sync, and two jobs: test runs Fastlane tests, build_release (dependent, non-PR only) builds and conditionally uploads signed AAB and Play Store deployment—all gated by presence of required GitHub Secrets.
Node dependencies and version control configuration
mobile/package.json, mobile/android/.gitignore, mobile/android/app/.gitignore
Pins Capacitor core, push notifications, and splash screen to specific versions (8.3.4), adds TypeScript dev dependency, and defines comprehensive Android .gitignore rules for build artifacts (APK, AAR, DEX), Gradle outputs, local SDK config, IDE metadata, native builds, Fastlane reports, Capacitor plugin directories, and generated web assets.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Poem

🐰 A rabbit hops through Android's glen,
With Gradle, Fastlane, and CI/CD zen,
Icons bright and manifests true,
The Play Store calls—deployment through!
Build it, sign it, deploy with cheer, 🎉
Universe awaits, the path is clear!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(android): add mobile shell and Play internal-track workflow' clearly and concisely summarizes the main changes: adding Android Capacitor platform and GitHub Actions workflow for Play Store deployment.
Linked Issues check ✅ Passed The pull request successfully implements all primary coding objectives from issue #4: Capacitor Android platform setup with correct applicationId and SDK versions, deep-link intent filter configuration, Fastlane lanes (test, build, deploy), workflow file, and dependency pins.
Out of Scope Changes check ✅ Passed All changes are appropriately scoped to the linked issue requirements: mobile/android/ platform, mobile/fastlane/ configuration, mobile/package.json dependency fixes, .github/workflows/android-build.yml, with no unrelated modifications.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mobile/android/gradlew.bat (1)

1-95: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Normalize this batch script to CRLF line endings.

LF-only endings can break label parsing/flow control on Windows cmd.exe in some environments; this is worth fixing before release.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mobile/android/gradlew.bat` around lines 1 - 95, The batch script uses
LF-only endings which can break Windows cmd label parsing; convert the file to
use CRLF line endings (CR+LF) and re-commit so labels like
:findJavaFromJavaHome, :execute, :fail and :mainEnd are on lines terminated with
CRLF. Fix by saving the file with Windows (CRLF) EOL in your editor or run a
tool (e.g., unix2dos/w2l) or set Git to enforce CRLF (core.eol and
core.autocrlf) and re-commit the converted file, then verify the labels and flow
control work in cmd.exe.
🧹 Nitpick comments (3)
mobile/package.json (1)

23-23: 💤 Low value

Inconsistent version pinning strategy.

Runtime dependencies (lines 15-17) use exact version pins without ^, but typescript in devDependencies retains the ^ prefix. For consistency and reproducibility, consider applying the same pinning strategy across all dependencies.

♻️ Apply consistent exact pinning
-    "typescript": "^6.0.3"
+    "typescript": "5.7.2"

(After correcting the TypeScript version.)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mobile/package.json` at line 23, The devDependency "typescript" in
package.json uses a caret range ("^6.0.3") which is inconsistent with the
runtime dependencies that are exact-pinned; change the version string for
"typescript" in devDependencies from "^6.0.3" to the exact pin "6.0.3" so
pinning strategy is consistent across the manifest (locate the "typescript"
entry in package.json to update).
mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml (1)

4-4: ⚡ Quick win

Use @drawable for adaptive icon foreground per Android guidelines

Android's official guidelines recommend placing adaptive icon foreground and background assets in drawable directories, not mipmaps. Change the reference from @mipmap/ic_launcher_foreground to @drawable/ic_launcher_foreground to align with best practices and use the existing drawable-v24/ic_launcher_foreground.xml resource.

Proposed fix
-    <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
+    <foreground android:drawable="@drawable/ic_launcher_foreground"/>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml` at
line 4, The adaptive icon foreground reference currently uses the mipmap
resource; update the <foreground
android:drawable="@mipmap/ic_launcher_foreground"/> entry to reference the
drawable resource instead (use "@drawable/ic_launcher_foreground") so the
adaptive icon uses the existing drawable-v24/ic_launcher_foreground.xml per
Android guidelines; locate the <foreground> element in ic_launcher_round.xml and
replace the `@mipmap` reference with `@drawable`.
.github/workflows/android-build.yml (1)

99-112: ⚡ Quick win

Avoid double-building the AAB on workflow_dispatch.

When workflow_dispatch is triggered, the "Build signed AAB" step (lines 99-112) runs and calls fastlane android build. Then the "Deploy to Play internal track" step (lines 121-135) runs and calls fastlane android deploy, which internally calls the build lane again (Fastfile line 21). This builds the AAB twice, wasting CI time.

Skip the "Build signed AAB" step when deploying to avoid the redundant build.

♻️ Proposed fix to skip redundant build on deploy
       - name: Build signed AAB
+        if: github.event_name != 'workflow_dispatch'
         env:
           ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/android-build.yml around lines 99 - 112, The "Build signed
AAB" step is causing a redundant build because the "Deploy to Play internal
track" step calls fastlane android deploy which rebuilds; update the "Build
signed AAB" step to skip when the workflow is manually dispatched so the deploy
lane can perform the build: add an if condition (e.g. if: github.event_name !=
'workflow_dispatch') to the "Build signed AAB" job/step so it does not run on
workflow_dispatch, leaving the fastlane lanes (android build and android deploy)
and the Fastfile (deploy lane that calls build on line 21) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/android-build.yml:
- Around line 87-97: The current "Materialize signing secrets" step requires
both ANDROID_KEYSTORE_BASE64 and GOOGLE_PLAY_JSON_KEY but the signed build path
only needs the keystore; update the step so it only creates
android/release.keystore when ANDROID_KEYSTORE_BASE64 is set (do not fail or
require GOOGLE_PLAY_JSON_KEY), and move or add a separate step that materializes
fastlane/google-play-key.json only for deployment runs (e.g., gated to
workflow_dispatch or the deploy job) by checking GOOGLE_PLAY_JSON_KEY before
creating the file; refer to the step name "Materialize signing secrets" and the
env vars ANDROID_KEYSTORE_BASE64 and GOOGLE_PLAY_JSON_KEY when locating and
changing the workflow.

In `@mobile/android/.gitignore`:
- Around line 64-65: Uncomment the ignored filename entry so the Firebase config
is actually excluded: in the .gitignore remove the comment character from the
line containing google-services.json (the literal "google-services.json" entry)
so that git will ignore that file and prevent committing Firebase API keys and
project identifiers.
- Around line 56-58: Uncomment the keystore ignore patterns so signing keys are
not checked into git: remove the leading # from the lines containing "*.jks" and
"*.keystore" in the .gitignore (the commented patterns shown as "#*.jks" and
"#*.keystore") to ensure those files are ignored by default and cannot be
committed.

In `@mobile/android/app/build.gradle`:
- Around line 13-17: The aaptOptions block is currently nested inside
defaultConfig which breaks the Gradle DSL; move the entire aaptOptions {...}
(including ignoreAssetsPattern =
'!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~') out of
defaultConfig and place it directly under the android { ... } scope (sibling to
defaultConfig), preserving the same contents and formatting so aaptOptions is
defined at top-level inside the android block.

In `@mobile/android/app/src/main/res/xml/file_paths.xml`:
- Line 3: The FileProvider mapping exposes all external storage via the element
`<external-path name="my_images" path=".">`; replace it with an app-scoped
mapping (use `<external-files-path>` targeting a specific subdirectory such as
"Pictures" or your app's folder) and narrow the cache mapping (`<cache-path
path=".">`) to a specific cache subdirectory instead of "." so only app-specific
external-files and cache locations are exposed; update the entries in
file_paths.xml (referencing the existing `<external-path name="my_images"
path=".">` and the `<cache-path path=".">` elements) to use
`<external-files-path>` and a restricted `<cache-path>` with a concrete
subdirectory name.

In `@mobile/android/variables.gradle`:
- Around line 3-4: Update the targetSdkVersion to match compileSdkVersion by
changing targetSdkVersion from 34 to 36 (the variables named compileSdkVersion
and targetSdkVersion in this diff), and ensure the Android Gradle Plugin is
bumped to 8.9.0 or newer (update the AGP version in your buildscript/plugin
declaration, e.g., the com.android.tools.build:gradle entry) so
compileSdkVersion 36 is fully supported.

---

Outside diff comments:
In `@mobile/android/gradlew.bat`:
- Around line 1-95: The batch script uses LF-only endings which can break
Windows cmd label parsing; convert the file to use CRLF line endings (CR+LF) and
re-commit so labels like :findJavaFromJavaHome, :execute, :fail and :mainEnd are
on lines terminated with CRLF. Fix by saving the file with Windows (CRLF) EOL in
your editor or run a tool (e.g., unix2dos/w2l) or set Git to enforce CRLF
(core.eol and core.autocrlf) and re-commit the converted file, then verify the
labels and flow control work in cmd.exe.

---

Nitpick comments:
In @.github/workflows/android-build.yml:
- Around line 99-112: The "Build signed AAB" step is causing a redundant build
because the "Deploy to Play internal track" step calls fastlane android deploy
which rebuilds; update the "Build signed AAB" step to skip when the workflow is
manually dispatched so the deploy lane can perform the build: add an if
condition (e.g. if: github.event_name != 'workflow_dispatch') to the "Build
signed AAB" job/step so it does not run on workflow_dispatch, leaving the
fastlane lanes (android build and android deploy) and the Fastfile (deploy lane
that calls build on line 21) unchanged.

In `@mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml`:
- Line 4: The adaptive icon foreground reference currently uses the mipmap
resource; update the <foreground
android:drawable="@mipmap/ic_launcher_foreground"/> entry to reference the
drawable resource instead (use "@drawable/ic_launcher_foreground") so the
adaptive icon uses the existing drawable-v24/ic_launcher_foreground.xml per
Android guidelines; locate the <foreground> element in ic_launcher_round.xml and
replace the `@mipmap` reference with `@drawable`.

In `@mobile/package.json`:
- Line 23: The devDependency "typescript" in package.json uses a caret range
("^6.0.3") which is inconsistent with the runtime dependencies that are
exact-pinned; change the version string for "typescript" in devDependencies from
"^6.0.3" to the exact pin "6.0.3" so pinning strategy is consistent across the
manifest (locate the "typescript" entry in package.json to update).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e9d35cc5-f045-47f4-9e6d-6cf50c9f5d70

📥 Commits

Reviewing files that changed from the base of the PR and between e3106e7 and 90a4504.

⛔ Files ignored due to path filters (28)
  • mobile/android/app/src/main/res/drawable-land-hdpi/splash.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/drawable-land-mdpi/splash.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/drawable-land-xhdpi/splash.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/drawable-land-xxhdpi/splash.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/drawable-land-xxxhdpi/splash.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/drawable-port-hdpi/splash.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/drawable-port-mdpi/splash.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/drawable-port-xhdpi/splash.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/drawable-port-xxhdpi/splash.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/drawable-port-xxxhdpi/splash.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/drawable/splash.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • mobile/android/gradle/wrapper/gradle-wrapper.jar is excluded by !**/*.jar
  • mobile/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (32)
  • .github/workflows/android-build.yml
  • mobile/android/.gitignore
  • mobile/android/app/.gitignore
  • mobile/android/app/build.gradle
  • mobile/android/app/capacitor.build.gradle
  • mobile/android/app/proguard-rules.pro
  • mobile/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java
  • mobile/android/app/src/main/AndroidManifest.xml
  • mobile/android/app/src/main/assets/.gitkeep
  • mobile/android/app/src/main/java/net/bawes/universe/MainActivity.java
  • mobile/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  • mobile/android/app/src/main/res/drawable/ic_launcher_background.xml
  • mobile/android/app/src/main/res/layout/activity_main.xml
  • mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  • mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  • mobile/android/app/src/main/res/values/ic_launcher_background.xml
  • mobile/android/app/src/main/res/values/strings.xml
  • mobile/android/app/src/main/res/values/styles.xml
  • mobile/android/app/src/main/res/xml/file_paths.xml
  • mobile/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java
  • mobile/android/build.gradle
  • mobile/android/capacitor.settings.gradle
  • mobile/android/gradle.properties
  • mobile/android/gradle/wrapper/gradle-wrapper.properties
  • mobile/android/gradlew
  • mobile/android/gradlew.bat
  • mobile/android/settings.gradle
  • mobile/android/variables.gradle
  • mobile/fastlane/Appfile
  • mobile/fastlane/Fastfile
  • mobile/fastlane/google-play-key.json.example
  • mobile/package.json

Comment thread .github/workflows/android-build.yml Outdated
Comment on lines +87 to +97
- name: Materialize signing secrets
env:
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
GOOGLE_PLAY_JSON_KEY: ${{ secrets.GOOGLE_PLAY_JSON_KEY }}
run: |
if [ -z "$ANDROID_KEYSTORE_BASE64" ] || [ -z "$GOOGLE_PLAY_JSON_KEY" ]; then
echo "Missing Android release secrets; skipping signed bundle build."
exit 0
fi
printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 --decode > android/release.keystore
printf '%s' "$GOOGLE_PLAY_JSON_KEY" > fastlane/google-play-key.json

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Decouple build secrets from deployment secrets.

The "Materialize signing secrets" step requires both ANDROID_KEYSTORE_BASE64 and GOOGLE_PLAY_JSON_KEY, but the build step (lines 99-112) only needs the keystore and signing credentials, not the Play key. On push to universe (not PR, not workflow_dispatch), the workflow builds a signed AAB but doesn't deploy, so the Play key is unnecessary. This prevents build-only workflow runs when the Play key is unavailable.

Split the secret materialization: create the keystore unconditionally when ANDROID_KEYSTORE_BASE64 is present, and only materialize the Play key when deploying (on workflow_dispatch).

♻️ Proposed fix to separate build and deploy secrets
-      - name: Materialize signing secrets
+      - name: Materialize keystore
         env:
           ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
-          GOOGLE_PLAY_JSON_KEY: ${{ secrets.GOOGLE_PLAY_JSON_KEY }}
         run: |
-          if [ -z "$ANDROID_KEYSTORE_BASE64" ] || [ -z "$GOOGLE_PLAY_JSON_KEY" ]; then
-            echo "Missing Android release secrets; skipping signed bundle build."
+          if [ -z "$ANDROID_KEYSTORE_BASE64" ]; then
+            echo "Missing keystore; skipping signed bundle build."
             exit 0
           fi
           printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 --decode > android/release.keystore
+
+      - name: Materialize Play Store key
+        if: github.event_name == 'workflow_dispatch'
+        env:
+          GOOGLE_PLAY_JSON_KEY: ${{ secrets.GOOGLE_PLAY_JSON_KEY }}
+        run: |
+          if [ -z "$GOOGLE_PLAY_JSON_KEY" ]; then
+            echo "Missing Play Store key; skipping deploy."
+            exit 0
+          fi
           printf '%s' "$GOOGLE_PLAY_JSON_KEY" > fastlane/google-play-key.json
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/android-build.yml around lines 87 - 97, The current
"Materialize signing secrets" step requires both ANDROID_KEYSTORE_BASE64 and
GOOGLE_PLAY_JSON_KEY but the signed build path only needs the keystore; update
the step so it only creates android/release.keystore when
ANDROID_KEYSTORE_BASE64 is set (do not fail or require GOOGLE_PLAY_JSON_KEY),
and move or add a separate step that materializes fastlane/google-play-key.json
only for deployment runs (e.g., gated to workflow_dispatch or the deploy job) by
checking GOOGLE_PLAY_JSON_KEY before creating the file; refer to the step name
"Materialize signing secrets" and the env vars ANDROID_KEYSTORE_BASE64 and
GOOGLE_PLAY_JSON_KEY when locating and changing the workflow.

Comment thread mobile/android/.gitignore Outdated
Comment thread mobile/android/.gitignore Outdated
Comment thread mobile/android/app/build.gradle Outdated
Comment thread mobile/android/app/src/main/res/xml/file_paths.xml Outdated
Comment on lines +3 to +4
compileSdkVersion = 36
targetSdkVersion = 34

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

For current Android Gradle Plugin releases, is compileSdkVersion 36fully supported, and are there known caveats whentargetSdkVersion remains 34?

💡 Result:

As of May 15, 2026, compileSdkVersion 36 is fully supported and is the current standard for Android development [1][2]. Using compileSdkVersion 36 while maintaining targetSdkVersion 34 is a technically valid and supported configuration [3][4]. Key considerations for this configuration include: 1. Separation of Concerns: compileSdkVersion determines the APIs available to your code at compile time, while targetSdkVersion determines the runtime behavior and system-enforced restrictions [3]. You can safely use newer APIs (compileSdkVersion 36) without opting into the full suite of Android 16 runtime behavior changes (targetSdkVersion 34) [3][4]. 2. Dependency Requirements: Many modern AndroidX and third-party libraries are increasingly requiring a higher compileSdkVersion to build [5][6]. If your project dependencies have been updated to versions that require API 36, you must set your compileSdkVersion to at least 36 to resolve build-time errors, regardless of your targetSdkVersion [3][6]. 3. Caveats and Risks: - While this configuration is supported, it is a temporary measure. Google Play policies require new apps and updates to target recent API levels [7][8]. As of 2026, Google Play requires apps to target API 36 [7]. Maintaining targetSdkVersion 34 will eventually prevent you from publishing updates to the Google Play Store [7][8]. - You will not benefit from the latest Android 16 platform features, security enhancements, or UI/UX requirements (such as mandatory edge-to-edge display) until you update your targetSdkVersion [9][10]. - Ensure your Android Gradle Plugin (AGP) is updated to a version compatible with API 36 (e.g., AGP 8.9.0 or higher) to avoid build issues [2][11]. In summary, while you can use compileSdkVersion 36 with targetSdkVersion 34 to satisfy build-time dependencies, you should plan to migrate your targetSdkVersion to 36 to remain compliant with Google Play Store policies and ensure your app functions correctly on newer Android versions [7][9].

Citations:


Update targetSdkVersion to 36 to comply with Google Play Store requirements.

While compileSdkVersion 36 with targetSdkVersion 34 is technically supported, Google Play now requires apps to target API 36. Maintaining targetSdkVersion 34 will prevent publishing updates to the Google Play Store. Additionally, ensure your Android Gradle Plugin is version 8.9.0 or higher for full compatibility with compileSdkVersion 36.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mobile/android/variables.gradle` around lines 3 - 4, Update the
targetSdkVersion to match compileSdkVersion by changing targetSdkVersion from 34
to 36 (the variables named compileSdkVersion and targetSdkVersion in this diff),
and ensure the Android Gradle Plugin is bumped to 8.9.0 or newer (update the AGP
version in your buildscript/plugin declaration, e.g., the
com.android.tools.build:gradle entry) so compileSdkVersion 36 is fully
supported.

@ScottShao

Copy link
Copy Markdown
Author

Pushed follow-up commit 8d4786e to address the valid Android review items without changing issue scope:

  • moved aaptOptions to the top-level android {} block so the Gradle DSL parses correctly
  • tightened .gitignore for keystores and google-services.json
  • removed the workflow's unnecessary Play JSON materialization from the signed-build path
  • skipped the redundant manual-dispatch build so fastlane android deploy is the only build on deploy runs
  • narrowed file_paths.xml away from broad external storage exposure
  • switched the adaptive icon foreground to @drawable/...
  • exact-pinned typescript in mobile/package.json and refreshed the lockfile

Re-verified locally after the patch:

  • cd mobile && npm install --package-lock-only --registry=https://registry.npmjs.org
  • cd mobile && npx cap sync android
  • cd mobile/android && ./gradlew help
  • YAML parse of .github/workflows/android-build.yml
  • git diff --check

@ScottShao

Copy link
Copy Markdown
Author

Pushed follow-up commit eb43a17 to improve platform readiness for real-device call validation.

Change:

  • added CAMERA, RECORD_AUDIO, and MODIFY_AUDIO_SETTINGS permissions to the Android manifest

Why:

  • this keeps the Android shell aligned with the broader mobile goal of in-app video/voice support and avoids a guaranteed blocker during physical LiveKit/WebRTC validation
  • scope stays inside the existing Android-owned path for this PR

Re-verified locally:

  • cd mobile/android && ./gradlew help
  • git diff --check

@ScottShao

Copy link
Copy Markdown
Author

Pushed follow-up commit 84af543 to address the remaining valid Windows-specific nit on this Android branch.

Change:

  • normalized mobile/android/gradlew.bat to CRLF line endings so the stock Windows batch labels/flow stay compatible with cmd.exe expectations

Re-verified locally:

  • file mobile/android/gradlew.bat now reports CRLF line terminators
  • byte check confirms 94 LF / 94 CRLF pairs
  • git diff --check -- mobile/android/gradlew.bat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android app: build, signing, and Play Store via Fastlane

1 participant