Skip to content

Latest commit

 

History

History
107 lines (80 loc) · 5.03 KB

File metadata and controls

107 lines (80 loc) · 5.03 KB

Syncloud Android app

Finds Syncloud devices on the local network over mDNS and opens them.

Build

./gradlew clean testDebugUnitTest assemble bundleRelease -Pversion=26.09.1

The version is a build property, not a value in the source. CI passes the git tag. Tags are year.month or year.month.patch and the code is year * 10000 + month * 100 + patch, so 26.09.1 gives versionCode 260901. The patch component exists so a second release inside the same month still increases the code, which is what Play requires; without it the only way to ship twice in one month is to invent a fake month and wedge every real one after it. Without the property the build is 0.01, which is fine for local work and can never be published.

The release build is minified and obfuscated by R8. proguard-rules.pro keeps the core.*.model classes and the three result types intact, because jackson maps those to json by field name and renaming them breaks sign-in and the device list at runtime. Instrumented tests run against the debug build, so they cannot catch that; the smoke CI step installs the real minified release on the device and fails the build if it does not start.

The runner attaches two docker networks to every container, and android configures only one interface, so the redroid hostname can resolve to the address android never brought up and adb fails with no route to host. ci/adb_device.sh probes for an endpoint that actually answers and caches it for the later steps, instead of trusting dns.

Release signing comes from the environment, not from a file. CI supplies KEY_STORE (base64 keystore), ANDROID_STORE_FILE, ANDROID_STORE_PASSWORD, ANDROID_KEY_ALIAS and ANDROID_KEY_PASSWORD as Drone secrets. Without them the release build is unsigned, which is fine for local work.

CI

ci.syncloud.org builds every push and tag, and publishes to /home/artifact/repo/android/<build>:

syncloud-<version>.apk                     sideloading, github releases
syncloud-<version>.aab                     google play
screenshots/discovery-with-device.png      discovery screen with a real device
screenshots/01-auth .. 06-settings.png     every screen, rendered by robolectric
discovery-logcat.txt                       device log, discovery tags only
instrument.log                             instrumented test output
diagnostics/smoke-logcat.txt               device log from the minified release

Before a tag publishes, check play queries the play developer reporting api for crash and anr anomalies and fails the build if any are open, and the publish itself validates the edit before committing it, which is where missing store declarations surface. Neither check can see the app optimization warnings in the console, as those have no api.

Tagging is the only way to release. It publishes the apk and the aab to a github release and uploads the bundle to the play internal track, from where you promote it in the console. Pushes to any branch build and test but publish nothing.

Tests

Unit tests and screenshots run on the JVM. The screenshots are rendered with Robolectric and Roborazzi, so they need no emulator, and are recorded fresh on every run rather than compared against a baseline.

Discovery is tested against a real device. The pipeline runs the Syncloud platform image as a service in systemd mode, so avahi advertises exactly as it does on hardware, and runs Android in a redroid container beside it. The instrumented tests drive DiscoveryManager through the platform's own NsdManager and assert a device is found and listed.

An emulator cannot do this: its guest sits behind QEMU user mode NAT, which does not carry multicast, so mDNS never reaches it. redroid runs Android on the host kernel and gets ordinary docker networking.

The build host therefore needs binder_linux loaded with binderfs mounted, and the repository marked trusted in Drone, since both services run privileged.

Publish to Google Play

  1. Take syncloud-<version>.aab from the build artifacts or the github release
  2. Play Console -> Syncloud -> Production -> Create new release
  3. Upload the aab and roll out

Play has required app bundles for updates since November 2021. The apk remains for sideloading and github releases.

Discovery

Devices advertise _ssh._tcp named syncloud on <host> from /etc/avahi/services/syncloud.service in the rootfs image. The app browses that type with NsdManager and matches the name.

NsdManager only listens for multicast, so an access point that filters multicast to wireless clients makes discovery blind while the devices are still reachable. A unicast fallback runs alongside it, querying from an ephemeral port so responders reply directly, and reports whatever answers.

Signing key

Generated with:

keytool -genkey -v -keystore syncloud.keystore -alias syncloud \
  -keyalg RSA -keysize 2048 -validity 10000

Valid to 2041. The package name and this key's SHA-256 are registered for Android developer verification.