Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
2dd6039
feat(android): 搭建 APK v1 移动端运行时框架及平台功能门控
HKLHaoBin Jun 7, 2026
f036434
feat(android): 添加用于构建和上传调试 APK 的 CI 工作流
HKLHaoBin Jun 8, 2026
a4e5f65
fix(reqwest): 从 reqwest 依赖中移除 native-tls 特性,并改为在非移动平台的客户端构建器中条件式使用。
HKLHaoBin Jun 8, 2026
f50a8e1
feat(android): 更新移动端和桌面平台的 capability 配置
HKLHaoBin Jun 8, 2026
266fff0
fix(docs): 规范化能力文档和 JSON 文件中的 macOS 大写
HKLHaoBin Jun 8, 2026
c768da2
Fix Android APK build: TLS, capabilities, arboard
HKLHaoBin Jun 8, 2026
95d6a85
Refactor:简化类型导入并更新特定平台的配置
HKLHaoBin Jun 8, 2026
4892b00
重构:更新 app_invoke_handler_mobile 宏中的命令引用以使用 crate 路径
HKLHaoBin Jun 8, 2026
b68f436
重构:将设置用户偏好设置的通用逻辑提取到共享函数中
HKLHaoBin Jun 8, 2026
c4eb1ac
feat(ci): 通过 Gradle 设置和 Wrapper 预热增强 Android APK 构建工作流
HKLHaoBin Jun 8, 2026
d5c2e49
Link Android NDK c++_static for cpal/oboe C++ runtime.
HKLHaoBin Jun 8, 2026
f759dc8
Use whole-archive static=c++_static for Android libc++ link.
HKLHaoBin Jun 8, 2026
d8de25d
Fix Android libc++ link via CARGO_CFG_TARGET_OS in build.rs.
HKLHaoBin Jun 8, 2026
79ef162
Use -lc++_static for Android NDK link in build.rs.
HKLHaoBin Jun 8, 2026
6362ddf
Link Android libc++ via NDK -lc++_static with whole-archive.
HKLHaoBin Jun 8, 2026
bd85353
Link Android c++_static and c++abi for missing C++ ABI symbols.
HKLHaoBin Jun 8, 2026
6e1365d
Avoid Android startup microphone probe panic
HKLHaoBin Jun 8, 2026
9d5c455
Avoid Android permission JNI startup panic
HKLHaoBin Jun 8, 2026
19e3933
Add responsive mobile app shell
HKLHaoBin Jun 8, 2026
b6a6f2b
Skip provider prompt on Android startup
HKLHaoBin Jun 8, 2026
e1e7c74
Fix mobile settings layout
HKLHaoBin Jun 8, 2026
387cc22
Request Android microphone permission from UI
HKLHaoBin Jun 8, 2026
74ebe1e
Persist Android microphone grant state
HKLHaoBin Jun 8, 2026
c67c2dc
Treat Android microphone stream errors as granted
HKLHaoBin Jun 8, 2026
4cd4dcb
Prefer stored Android microphone grant
HKLHaoBin Jun 8, 2026
0523710
Ignore Android WebView microphone preflight denial
HKLHaoBin Jun 8, 2026
51b6cda
Fix Android external links
HKLHaoBin Jun 8, 2026
b624af2
Add Android audio settings permission
HKLHaoBin Jun 9, 2026
f35b4db
Bypass Android desktop microphone gate
HKLHaoBin Jun 9, 2026
a215bcd
Initialize Android context for audio backend
HKLHaoBin Jun 9, 2026
f199a81
Fix Android context bridge path
HKLHaoBin Jun 9, 2026
e3e42c6
Use webpki roots for Android ASR websocket
HKLHaoBin Jun 9, 2026
af01e51
Force mono Android recorder input
HKLHaoBin Jun 9, 2026
7102a9f
Disable Android recording cue audio
HKLHaoBin Jun 9, 2026
1e566c0
Avoid repeated Android mic permission probe
HKLHaoBin Jun 9, 2026
f4a6f56
Ignore Android debug artifacts and local CI APK downloads.
HKLHaoBin Jun 9, 2026
c0997af
Add Android overlay recording with JNI bridge and CI scaffolding.
HKLHaoBin Jun 9, 2026
0019368
Fix Android JNI lifetime and string conversion compile errors.
HKLHaoBin Jun 9, 2026
e4f8bf3
Simplify Android JNI env callback signature.
HKLHaoBin Jun 9, 2026
8e9ec45
Fix Android JNI JString to JObject conversion for call args
HKLHaoBin Jun 9, 2026
00193fc
Fix JValue two-lifetime signature in Android jval_str helper
HKLHaoBin Jun 9, 2026
dc737a9
Fix Android JNI by binding JObject locals before JValue calls
HKLHaoBin Jun 9, 2026
b1e7366
Ignore adb UI hierarchy dumps from Android debug runs.
HKLHaoBin Jun 9, 2026
4535a1c
Fix early Android JNI crash by using callback env and Context
HKLHaoBin Jun 9, 2026
3ce6f24
Fix overlay FGS crash by deferring microphone type until recording
HKLHaoBin Jun 9, 2026
e1743ae
Use startService for overlay HIDE to avoid FGS timeout crash
HKLHaoBin Jun 9, 2026
0099824
Fix Android overlay JNI and foreground service startup
HKLHaoBin Jun 9, 2026
a22a30b
Fix Android JNI helper lifetime
HKLHaoBin Jun 9, 2026
113d830
Bind Android overlay callback lifetimes
HKLHaoBin Jun 9, 2026
b2715a2
Start Android overlay display as regular service
HKLHaoBin Jun 9, 2026
810a3a2
Fix Android overlay recording runtime crashes
HKLHaoBin Jun 9, 2026
8328be3
Expose Android JNI companion methods
HKLHaoBin Jun 9, 2026
c631a72
Fix accessibility JNI static method clash
HKLHaoBin Jun 9, 2026
6951350
Fix Android clipboard JNI signature
HKLHaoBin Jun 9, 2026
7da53ef
Remove Android IME path for overlay input
HKLHaoBin Jun 9, 2026
b84991f
Simplify Android overlay button
HKLHaoBin Jun 9, 2026
102c4dd
Persist Android overlay icon position
HKLHaoBin Jun 9, 2026
691c816
Fix Android overlay keyboard trigger in other apps
HKLHaoBin Jun 9, 2026
3cdb0ab
Harden Android overlay fallback and icon handling
HKLHaoBin Jun 9, 2026
c74548a
Avoid obsolete Android SDK tools package
HKLHaoBin Jun 9, 2026
c3a7eb1
Isolate Android accessibility overlay trigger
HKLHaoBin Jun 10, 2026
f812f94
Show Android overlay from keyboard events
HKLHaoBin Jun 10, 2026
febed12
Log Android overlay keyboard path
HKLHaoBin Jun 10, 2026
9e3b836
Keep Android accessibility heartbeat fresh
HKLHaoBin Jun 10, 2026
f9867de
Deduplicate Android overlay windows
HKLHaoBin Jun 10, 2026
fb9b109
Limit keyboard overlay fallback to background
HKLHaoBin Jun 10, 2026
fd7be3c
Use native Android microphone permission status
HKLHaoBin Jun 10, 2026
a0f282f
Shelve Android keyboard overlay trigger
HKLHaoBin Jun 10, 2026
ad8b3d7
Add Android overlay gesture preferences
HKLHaoBin Jun 10, 2026
b9eecff
Add Android overlay gesture QA flow
HKLHaoBin Jun 10, 2026
dedba6d
Fix Android overlay QA events and size setting
HKLHaoBin Jun 10, 2026
68be0eb
Fix Android overlay QA foreground panel
HKLHaoBin Jun 10, 2026
30c9c58
更新 .gitignore 以忽略 Android 日志和诊断文件;重构 android_insert 和 persistence 模块中…
HKLHaoBin Jun 10, 2026
8ece234
ci: add workflow_dispatch for manual branch builds
HKLHaoBin Jun 10, 2026
bea0ba1
fix(ci): restore macos-private-api in base tauri features
HKLHaoBin Jun 10, 2026
3e02c00
fix(ci): expose windows_ime_profile stub and dedupe clipboard delay
HKLHaoBin Jun 10, 2026
905b851
refactor(android): modularize platform code into android/ tree
HKLHaoBin Jun 10, 2026
237a60a
fix(ci): include android types via path for backend-tests harness
HKLHaoBin Jun 10, 2026
58c7c91
chore(android): remove migrated android-scaffolding from git index
HKLHaoBin Jun 11, 2026
841215e
Fix Android overlay gestures and permissions
HKLHaoBin Jun 11, 2026
582af09
Complete Android setup and QA permission flow
HKLHaoBin Jun 11, 2026
cef63e1
Add Android icon safe zone
HKLHaoBin Jun 11, 2026
8eebffb
feat(android): 完善悬浮窗手势、权限面板与无障碍粘贴链路
HKLHaoBin Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
241 changes: 241 additions & 0 deletions .github/workflows/android-apk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
name: Android APK (debug)

# Triggers:
# - push v*-tauri tag → build debug APK, upload artifact + attach to GitHub Release
# - workflow_dispatch → build debug APK, upload artifact only (no release)
#
# Scope: full overlay/accessibility APK for ADB testing (v1 RECORD_AUDIO + overlay manifest merge).

on:
push:
tags:
- 'v*-tauri'
workflow_dispatch:

jobs:
build-android-apk:
permissions:
contents: write
runs-on: ubuntu-latest
env:
CI: true
steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Setup Java 17 (Zulu)
uses: actions/setup-java@v4
with:
distribution: zulu
java-version: '17'

- name: Setup Android SDK
uses: android-actions/setup-android@v3
with:
packages: platform-tools

- name: Install NDK and accept SDK licenses
shell: bash
run: |
set -euo pipefail
sdkmanager "ndk;26.1.10909125"
ndk_dir="$ANDROID_HOME/ndk/26.1.10909125"
if [ ! -d "$ndk_dir" ]; then
echo "::error::NDK not found at $ndk_dir"
exit 1
fi
echo "ANDROID_NDK_HOME=$ndk_dir" >> "$GITHUB_ENV"
echo "NDK_HOME=$ndk_dir" >> "$GITHUB_ENV"
set +o pipefail
yes | sdkmanager --licenses
sdkmanager_exit=${PIPESTATUS[1]}
set -o pipefail
if [ "$sdkmanager_exit" -ne 0 ]; then
echo "::error::sdkmanager --licenses failed with exit code $sdkmanager_exit"
exit "$sdkmanager_exit"
fi

- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: openless-all/app/package-lock.json

- uses: dtolnay/rust-toolchain@stable
with:
targets: >-
aarch64-linux-android,
armv7-linux-androideabi,
i686-linux-android,
x86_64-linux-android

- name: Cache Cargo
uses: swatinem/rust-cache@v2
with:
workspaces: openless-all/app/src-tauri -> target

- uses: gradle/actions/setup-gradle@v4

- name: Install npm deps
working-directory: openless-all/app
run: npm ci

- name: Build frontend
working-directory: openless-all/app
run: npm run build

- name: Initialize Android project
working-directory: openless-all/app
run: npm run tauri -- android init --ci

- name: Copy Android scaffolding (Kotlin + XML)
working-directory: openless-all/app
run: node scripts/copy-android-scaffolding.mjs

- name: Merge APK v1 manifest permissions
working-directory: openless-all/app
run: node scripts/merge-android-v1-manifest.mjs

- name: Merge overlay / accessibility manifest
working-directory: openless-all/app
run: node scripts/merge-android-overlay-manifest.mjs

- name: Prime Gradle wrapper
working-directory: openless-all/app
shell: bash
run: |
set -euo pipefail
for attempt in 1 2 3; do
if src-tauri/gen/android/gradlew --project-dir src-tauri/gen/android --version --no-daemon; then
exit 0
fi
if [ "$attempt" -lt 3 ]; then
sleep $([ "$attempt" -eq 1 ] && echo 15 || echo 30)
fi
done
exit 1

- name: Build Android debug APK
working-directory: openless-all/app
run: npm run tauri:android:build

- name: Free disk before artifact upload
shell: bash
working-directory: openless-all/app
run: |
set -euo pipefail
rm -rf src-tauri/target
rm -rf ~/.cargo/registry ~/.cargo/git ~/.gradle/caches
df -h

- name: Collect split debug APKs
id: apk
shell: bash
working-directory: openless-all/app
run: |
set -euo pipefail
if [[ "${{ github.ref }}" == refs/tags/v* ]] && [[ "${{ github.ref_name }}" == *-tauri ]]; then
label="${{ github.ref_name }}"
else
label="run-${{ github.run_number }}"
fi
export OPENLESS_APK_LABEL="$label"
python - <<'PY'
import os
import shutil
import sys
import zipfile
from pathlib import Path

expected = {
"arm64-v8a": "arm64_v8a",
"armeabi-v7a": "armeabi_v7a",
"x86": "x86",
"x86_64": "x86_64",
}
root = Path("src-tauri/gen/android")
label = os.environ["OPENLESS_APK_LABEL"]
out_dir = Path(os.environ["RUNNER_TEMP"]) / "openless-android-debug-split"
out_dir.mkdir(parents=True, exist_ok=True)
found = {}
candidates = [
apk for apk in sorted(root.rglob("*.apk"))
if "outputs" in apk.parts
]
if not candidates:
print("::error::No APK found under src-tauri/gen/android/**/outputs/")
for apk in sorted(root.rglob("*.apk")):
print(apk)
sys.exit(1)
for apk in candidates:
with zipfile.ZipFile(apk) as archive:
abis = sorted({
name.split("/")[1]
for name in archive.namelist()
if name.startswith("lib/") and len(name.split("/")) >= 3
})
if len(abis) != 1:
print(f"::error::{apk} contains ABI directories {abis}; expected exactly one ABI per APK")
sys.exit(1)
abi = abis[0]
if abi not in expected:
print(f"::error::{apk} contains unexpected ABI {abi}")
sys.exit(1)
if abi in found:
print(f"::error::Duplicate APKs for ABI {abi}: {found[abi]} and {apk}")
sys.exit(1)
dest = out_dir / f"OpenLess-android-debug-{abi}-{label}.apk"
shutil.copy2(apk, dest)
found[abi] = dest
print(f"Collected {abi}: {apk} -> {dest}")
missing = sorted(set(expected) - set(found))
if missing:
print(f"::error::Missing split APKs for ABI(s): {', '.join(missing)}")
sys.exit(1)
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
for abi, key in expected.items():
output.write(f"{key}_path={found[abi]}\n")
output.write("release_files<<EOF\n")
for abi in expected:
output.write(f"{found[abi]}\n")
output.write("EOF\n")
PY

- name: Upload Android APK artifact (arm64-v8a)
uses: actions/upload-artifact@v4
with:
name: openless-android-debug-arm64-v8a
path: ${{ steps.apk.outputs.arm64_v8a_path }}
if-no-files-found: error

- name: Upload Android APK artifact (armeabi-v7a)
uses: actions/upload-artifact@v4
with:
name: openless-android-debug-armeabi-v7a
path: ${{ steps.apk.outputs.armeabi_v7a_path }}
if-no-files-found: error

- name: Upload Android APK artifact (x86)
uses: actions/upload-artifact@v4
with:
name: openless-android-debug-x86
path: ${{ steps.apk.outputs.x86_path }}
if-no-files-found: error

- name: Upload Android APK artifact (x86_64)
uses: actions/upload-artifact@v4
with:
name: openless-android-debug-x86_64
path: ${{ steps.apk.outputs.x86_64_path }}
if-no-files-found: error

- name: Attach APK to GitHub Release
if: startsWith(github.ref, 'refs/tags/v') && endsWith(github.ref, '-tauri')
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: OpenLess ${{ github.ref_name }}
draft: false
prerelease: ${{ endsWith(github.ref_name, '-beta-tauri') }}
files: ${{ steps.apk.outputs.release_files }}
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
branches: [main, beta]
pull_request:
branches: [main, beta]
workflow_dispatch:

jobs:
cross-platform:
Expand Down
24 changes: 23 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Package.resolved
xcuserdata/
DerivedData/
ChatGPT Image*.jpg

.cursor
# Local config / secrets
*.env
config.local.json
Expand All @@ -33,6 +33,28 @@ video-materials/
node_modules/
dist/
target/
# 本地从 CI / Actions 下载的 APK 及解压目录(非源码)
ci-artifacts/
*.apk

# Android 真机调试产物(日志 / 截图 / adb 导出 / 数据备份 / 临时还原目录)
diagnostics/
android-logs/
test-captures/
extracted/
android-crash*.log
android-run*.log
qa-*.log
qa-*.png
openless-package*.txt
openless-screenshot*.png
openless-android-run*.png
/openless_*.png
/run*.png
openless-appdata*.tar
openless-run*-ui.xml
tmp-run*/

.cargo/registry/
.cargo/git/

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ Go to [Releases](../../releases) and download:
xattr -cr /Applications/OpenLess.app
```
- **Windows**: `OpenLess_<version>_x64-setup.exe` — run the installer.
- **Android debug APK**: choose exactly one split APK for your device:
- `OpenLess-android-debug-arm64-v8a-*.apk` for most modern Android phones.
- `OpenLess-android-debug-armeabi-v7a-*.apk` for older 32-bit ARM phones.
- `OpenLess-android-debug-x86_64-*.apk` for most 64-bit Android emulator images.
- `OpenLess-android-debug-x86-*.apk` for older 32-bit x86 emulator images.
- If unsure, run `adb shell getprop ro.product.cpu.abi` and download the APK matching that ABI. Do not install the x86 builds on a normal ARM phone.
- **macOS (Homebrew)**:
```bash
brew tap appergb/openless https://github.com/appergb/openless
Expand Down
Loading