-
Notifications
You must be signed in to change notification settings - Fork 190
Conversation
Add signed release APK builds on v*-tauri tags, minisign manifests per ABI, custom Android in-app updater, and CI cargo check for aarch64-linux-android. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
generate_context! requires ../dist; the android-check job was missing npm ci + vite build, causing proc macro panic on CI. Co-authored-by: Cursor <cursoragent@cursor.com>
Pair with TAURI_SIGNING_PRIVATE_KEY set via gh secret set. Old pubkey superseded for new tag releases. Co-authored-by: Cursor <cursoragent@cursor.com>
HKLHaoBin
commented
Jun 13, 2026
首先按照 OPENLESS_RELEASE_SECRETS_HANDOFF.md 在仓库中设置环境变量(或者你把这个文件提供给 AI,让 AI 通过 gh CLI 工具直接以命令方式为你的仓库配置 Secret。),之后再合并我的 PR。
PR Reviewer Guide 🔍
Here are some key observations to aid the review process:
JNI field access
device_arch() uses env.call_static_method to read Build.SUPPORTED_ABIS, but this is a static field, not a method. It should use get_static_field with the field signature "[Ljava/lang/String;". The current code will throw a JNI error at runtime when checking for updates on Android, preventing any update from being discovered.
device_arch() uses env.call_static_method to read Build.SUPPORTED_ABIS, but this is a static field, not a method. It should use get_static_field with the field signature "[Ljava/lang/String;". The current code will throw a JNI error at runtime when checking for updates on Android, preventing any update from being discovered.crate::android::jni::android::with_android_env(|env, _context| { let abis_obj = env .call_static_method( "android/os/Build", "SUPPORTED_ABIS", "()[Ljava/lang/String;", &[], ) .and_then(|value| value.l()) .map_err(|e| format!("read SUPPORTED_ABIS: {e}"))?;
Public key mismatch
PUBKEY_B64 is hardcoded to the old minisign public key, but tauri.conf.json has been updated to a new public key in this PR. When a new release is built, the desktop updater will use the new key, but the Android updater will use the old key, causing signature verification of new APKs to fail. All Android in-app updates will be rejected after the first release with the new key.
PUBKEY_B64 is hardcoded to the old minisign public key, but tauri.conf.json has been updated to a new public key in this PR. When a new release is built, the desktop updater will use the new key, but the Android updater will use the old key, causing signature verification of new APKs to fail. All Android in-app updates will be rejected after the first release with the new key.const PUBKEY_B64: &str = "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDFERUFBODAzNTY0QzMyM0YKUldRL01reFdBNmpxSGE1K0JadlpONXNWTzhJcGZCRGxjUVdIWExNNFJpeUNsSGZwazdlQThhemkK";
Misleading install result
installApk returns false immediately after starting an intent to request INSTALL_PACKAGES permission (API >= O). The Rust caller treats Ok(false) as success, so the update flow reports 'downloaded' without actually installing the APK. The user sees a success state but no installation occurs; the system permission dialog may have been shown, but the user receives no feedback to retry. The method should either block until installation completes or return an error that propagates to the UI.
installApk returns false immediately after starting an intent to request INSTALL_PACKAGES permission (API >= O). The Rust caller treats Ok(false) as success, so the update flow reports 'downloaded' without actually installing the APK. The user sees a success state but no installation occurs; the system permission dialog may have been shown, but the user receives no feedback to retry. The method should either block until installation completes or return an error that propagates to the UI.fun installApk(context: Context, apkPath: String): Boolean { val apkFile = File(apkPath) if (!apkFile.exists()) { return false } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !context.packageManager.canRequestPackageInstalls()) { val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply { data = Uri.parse("package:${context.packageName}") addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } context.startActivity(intent) return false
Uh oh!
There was an error while loading. Please reload this page.
User description
摘要
Fixes #(无关联 issue;如需可补链 Android 发版跟踪 issue)。
将 Android 移动端构建与发布规则与桌面端
release-tauri.yml对齐:v*-tauri/v*-beta-tauritag 触发 release APK、minisign 更新清单与应用内更新(Tauri plugin-updater 不支持 Android,故实现自有 updater 通道)。修复 / 新增 / 改进
android-apk.yml(Stable/Beta 渠道、OPENLESS_RELEASE_CHANNEL、tag release 签名检查、debug dispatch vs release tag 双模式、产物命名OpenLess_<version>_<abi>.apk、上传.apk.sig与latest-android-{arch}[-beta].json)。configure-android-release-signing.mjs、sign-android-apks.mjs、merge-android-updater-manifest.mjs;扩展write-updater-manifest.mjs支持 Android ABI。android/updater.rs+ KotlinOpenLessUpdateInstaller;Android 启用supportsAutoUpdate;前端AutoUpdate.tsx/ipc.ts走 Android 安装 IPC。ci.yml增加aarch64-linux-androidcargo check(含 frontend build 前置)。docs/android-mobile-apk-overlay-plan.md。tauri.conf.json更新plugins.updater.pubkey(需上游在 Actions 配置TAURI_SIGNING_PRIVATE_KEY及ANDROID_KEYSTORE_*;私钥通过 maintainer 私信交接,不进仓库)。兼容
workflow_dispatch仍产出 debug APK;新增tauri:android:build:debug/tauri:android:build:release脚本。测试计划
gh workflow run CI --ref feat/android-release-pipeline+gh workflow run "Android APK (debug)" --ref feat/android-release-pipelineHKLHaoBin/openless)27467079119(CI)、27467079900(Android debug APK)git push origin v1.3.6-4-beta-tauri(配置 Secrets 后)Release Tauri (cross-platform)run27468473394+Android APK (debug)run27468473395均 success;Release 含OpenLess_1.3.6-4_arm64-v8a.apk、latest-android-aarch64-beta.json等gh workflow run "Release Tauri (cross-platform)" --ref feat/android-release-pipeline27467468100)PR Type
Enhancement, Tests, Documentation
Description
Add custom Android in-app updater (minisign verified, system APK install)
Extend CI workflows for signed release APKs, updater manifests, and Android cargo check
Update frontend, scripts, and documentation for mobile release support
Diagram Walkthrough
flowchart LR A[Android APK CI] --> B["Build mode: debug / release"] B --> C["Tag v*-tauri: release (signed APK + updater manifest)"] B --> D["workflow_dispatch: debug APK"] C --> E["minisign signature (.sig)"] C --> F["latest-android-{arch}[-beta].json"] C --> G["Attach to GitHub Release"] H["ci.yml android-check"] --> I["cargo check --target aarch64-linux-android"] J["Frontend AutoUpdate.tsx"] --> K["appDownloadAndInstallAndroidUpdate"] K --> L["Rust updater: download + verify + install via system installer"]File Walkthrough
17 files
Expose JNI helpers for updaterDeclare updater moduleAdd Android custom in-app updaterAdd mobile update commandsRegister mobile update commandsEnable auto update for AndroidSupport Android update flowAdd Android update IPCEnable auto update for AndroidKotlin system APK installerSupport signed release APK buildsAdd release build scriptScript for Android release signing configCopy update installer Kotlin fileMerge install permissions into manifestMinisign APK signing scriptSupport Android updater manifests1 files
Add Android cargo check job3 files
Update Android release instructionsUpdate Chinese Android release instructionsUpdate overlay plan for release pipeline1 files
Add minisign-verify dependency for Android1 files