feat: add autostart APK build workflow and update Android services

- Add GitHub Actions workflow for building APK with autostart functionality
- Update BootReceiver.kt: default boot autostart to true
- Update MainService.kt: use START_STICKY and implement onTaskRemoved
- Add documentation and quick start guides
This commit is contained in:
imovely66-afk 2026-06-05 14:58:55 +00:00
commit 02dfd77907
5 changed files with 451 additions and 8 deletions

144
.github/AUTOSTART_APK_BUILD.md vendored Normal file
View file

@ -0,0 +1,144 @@
# RustDesk Autostart APK Build Workflow
此工作流用于编译启用开机自启动功能的 RustDesk Android APK。
## 功能改动
该工作流编译的 APK 包含以下自启动功能:
1. **开机自启动**:手机开机后自动启动 RustDesk 服务
2. **后台重启**:服务被系统或用户关闭后自动重新启动
3. **前台服务**:使用 Android 前台服务,即使在后台也能继续运行
### 核心修改
修改的文件位置:
- `flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt`
- 将开机启动默认值改为 `true`无需手动UI操作
- 移除不必要的权限检查
- `flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt`
- 返回 `START_STICKY` 标志
- 实现 `onTaskRemoved()` 处理,任务被移除时自动重启
## 使用方式
### 自动触发
工作流会在以下情况自动触发:
1. **代码更新时**:当推送到 `master` 分支时,如果修改了以下文件:
- `flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt`
- `flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt`
- `.github/workflows/flutter-build-autostart-apk.yml`
### 手动触发
在 GitHub Actions 中选择 **"Build RustDesk Android APK with Autostart"** 工作流,点击 **"Run workflow"**,选择要编译的架构:
- `aarch64` (ARM64推荐用于现代手机)
- `armv7` (ARM用于较旧手机)
- `x86_64` (x86 仿真器)
## 编译输出
编译成功后,会生成以下 APK 文件:
- `rustdesk-autostart-1.4.7-aarch64.apk` (ARM64 版本)
- `rustdesk-autostart-1.4.7-armv7.apk` (ARM 版本)
- `rustdesk-autostart-1.4.7-x86_64.apk` (x86_64 版本)
### 下载位置
1. **GitHub Actions Artifacts**:在工作流运行详情页面,点击 "Artifacts" 部分
2. **GitHub Release**:自动创建 `autostart-1.4.7` Release包含所有编译好的 APK
## 安装到 Root 手机
### 方法一:通过 ADB 安装
```bash
# 连接设备
adb devices
# 安装 APK
adb install -r rustdesk-autostart-1.4.7-aarch64.apk
# 授予自启动权限(需要 root
adb shell pm grant com.carriez.flutter_hbb android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
adb shell pm grant com.carriez.flutter_hbb android.permission.SYSTEM_ALERT_WINDOW
```
### 方法二:手动安装 + Root 授权
1. 下载 APK 文件
2. 将文件传输到手机
3. 打开文件管理器,点击 APK 安装
4. 安装后,使用 Root 应用(如 Magisk 或 SuperSU授予必要权限
## 所需权限
该 APK 需要以下权限才能正常自启动:
- `RECEIVE_BOOT_COMPLETED` - 接收开机广播
- `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` - 忽略电池优化
- `SYSTEM_ALERT_WINDOW` - 系统提示窗口
- `FOREGROUND_SERVICE` - 前台服务
## 测试自启动功能
### 测试方法
1. 安装并授权 APK
2. 重启手机
3. 检查 RustDesk 是否自动启动
4. 查看通知栏是否有 RustDesk 前台服务通知
### 日志查看
```bash
# 查看 BootReceiver 日志
adb logcat | grep tagBootReceiver
# 查看 MainService 日志
adb logcat | grep LOG_SERVICE
```
## 故障排除
### 自启动不工作
1. **检查权限**:确保已授予所有必要权限
2. **电池优化**:将 RustDesk 从电池优化白名单中移除
3. **ROM 限制**:某些定制 ROM如 MIUI、ColorOS可能限制后台启动
4. **Adb logcat**:运行 `adb logcat` 查看是否有错误消息
### APK 编译失败
1. 检查工作流日志
2. 确保所有依赖项已正确安装
3. 检查 Rust 版本是否为 1.75
## 工作流参数
工作流使用以下环境变量:
| 变量 | 值 | 说明 |
|------|-----|------|
| RUST_VERSION | 1.75 | Rust 编译器版本 |
| FLUTTER_VERSION | 3.24.5 | Flutter SDK 版本 |
| NDK_VERSION | r28c | Android NDK 版本 |
| VERSION | 1.4.7 | RustDesk 版本 |
## 相关文件
- 工作流定义:`.github/workflows/flutter-build-autostart-apk.yml`
- Boot receiver`flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt`
- Main service`flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt`
- AndroidManifest`flutter/android/app/src/main/AndroidManifest.xml`
## 注意事项
⚠️ **重要**
- 此 APK 需要在 Root 手机上安装以获得最佳效果
- 某些权限可能需要 Magisk 或其他 Root 解决方案才能授予
- 不同 ROM 的自启动策略可能有所不同

View file

@ -0,0 +1,214 @@
name: Build RustDesk Android APK with Autostart
on:
workflow_dispatch:
inputs:
arch:
description: 'Architecture to build'
required: true
default: 'aarch64'
type: choice
options:
- aarch64
- armv7
- x86_64
push:
branches:
- master
paths:
- 'flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt'
- 'flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt'
- '.github/workflows/flutter-build-autostart-apk.yml'
env:
RUST_VERSION: "1.75"
FLUTTER_VERSION: "3.24.5"
ANDROID_FLUTTER_VERSION: "3.24.5"
CARGO_NDK_VERSION: "3.1.2"
NDK_VERSION: "r28c"
VERSION: "1.4.7"
jobs:
generate-bridge:
uses: ./.github/workflows/bridge.yml
build-autostart-apk:
needs: [generate-bridge]
name: Build RustDesk APK ${{ matrix.job.arch }} with Autostart
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
job:
- {
arch: aarch64,
target: aarch64-linux-android,
reltype: release,
android_target: arm64-v8a,
android_platform: android-arm64,
}
- {
arch: armv7,
target: armv7-linux-androideabi,
reltype: release,
android_target: armeabi-v7a,
android_platform: android-arm,
}
- {
arch: x86_64,
target: x86_64-linux-android,
reltype: release,
android_target: x86_64,
android_platform: android-x64,
}
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
with:
tool-cache: false
android: false
dotnet: true
haskell: true
large-packages: false
docker-images: true
swap-storage: false
- name: Export GitHub Actions cache environment variables
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
clang \
cmake \
curl \
gcc-multilib \
git \
g++ \
g++-multilib \
libayatana-appindicator3-dev \
libasound2-dev \
libc6-dev \
libclang-dev \
libunwind-dev \
libgstreamer1.0-dev \
libgstreamer-plugins-base1.0-dev \
libgtk-3-dev \
libpam0g-dev \
libpulse-dev \
libva-dev \
libxcb-randr0-dev \
libxcb-shape0-dev \
libxcb-xfixes0-dev \
libxdo-dev \
libxfixes-dev \
llvm-dev \
nasm \
ninja-build \
openjdk-17-jdk-headless \
pkg-config \
wget
- name: Checkout source code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
submodules: recursive
- name: Restore bridge files
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: bridge-artifact
path: ./
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_VERSION }}
targets: ${{ matrix.job.target }}
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@23a6cea2dd7927e274fa67a56199cc32ae1ea204 # v2
with:
prefix-key: rustdesk-lib-cache-android
- uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1
id: setup-ndk
with:
ndk-version: ${{ env.NDK_VERSION }}
add-to-path: true
- name: Install Flutter
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
with:
channel: "stable"
flutter-version: ${{ env.ANDROID_FLUTTER_VERSION }}
- name: Build Rust lib for Android
shell: bash
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
cargo build --release --target ${{ matrix.job.target }}
- name: Copy compiled libraries
shell: bash
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
run: |
case ${{ matrix.job.target }} in
aarch64-linux-android)
mkdir -p ./flutter/android/app/src/main/jniLibs/arm64-v8a
cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so ./flutter/android/app/src/main/jniLibs/arm64-v8a/
cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/arm64-v8a/librustdesk.so
;;
armv7-linux-androideabi)
mkdir -p ./flutter/android/app/src/main/jniLibs/armeabi-v7a
cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/libc++_shared.so ./flutter/android/app/src/main/jniLibs/armeabi-v7a/
cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/armeabi-v7a/librustdesk.so
;;
x86_64-linux-android)
mkdir -p ./flutter/android/app/src/main/jniLibs/x86_64
cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so ./flutter/android/app/src/main/jniLibs/x86_64/
cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/x86_64/librustdesk.so
;;
esac
- name: Build Flutter APK with Autostart
shell: bash
env:
JAVA_HOME: /usr/lib/jvm/java-17-openjdk-amd64
run: |
export PATH=/usr/lib/jvm/java-17-openjdk-amd64/bin:$PATH
# Increase Gradle JVM memory for CI builds
sed -i "s/org.gradle.jvmargs=-Xmx1024M/org.gradle.jvmargs=-Xmx2g/g" ./flutter/android/gradle.properties
# Use debug sign config for APK
sed -i "s/signingConfigs.release/signingConfigs.debug/g" ./flutter/android/app/build.gradle
cd flutter
flutter build apk --release --target-platform ${{ matrix.job.android_platform }} --split-per-abi
popd
mv flutter/build/app/outputs/flutter-apk/app-${{ matrix.job.android_target }}-release.apk rustdesk-autostart-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
- name: Upload APK Artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: rustdesk-autostart-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
path: rustdesk-autostart-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
retention-days: 30
- name: Create Release
if: success()
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
files: rustdesk-autostart-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
tag_name: autostart-${{ env.VERSION }}
prerelease: true
generate_release_notes: true
continue-on-error: true

View file

@ -0,0 +1,77 @@
# 快速开始:自启动 APK 构建
## 一句话总结
在 GitHub Actions 中自动编译带开机自启动功能的 RustDesk Android APK。
## 快速步骤
### 1⃣ 查看工作流状态
进入 **Actions** → **Build RustDesk Android APK with Autostart**
### 2⃣ 手动触发编译(可选)
点击 **Run workflow** → 选择架构(推荐 `aarch64`)→ 点击绿色 **Run workflow**
### 3⃣ 等待编译完成
工作流运行约 30-45 分钟(首次编译时间较长)
### 4⃣ 下载 APK
两种方式下载:
- **Artifacts**:工作流详情页 → 找 `rustdesk-autostart-*.apk`
- **Release**Code → Releases → 找 `autostart-*` 版本
### 5⃣ 安装到手机
```bash
adb install -r rustdesk-autostart-1.4.7-aarch64.apk
```
### 6⃣ 授予权限(需 Root
```bash
# 如果手机已 Root使用以下命令
adb shell pm grant com.carriez.flutter_hbb android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
adb shell pm grant com.carriez.flutter_hbb android.permission.SYSTEM_ALERT_WINDOW
```
### 7⃣ 测试
重启手机,检查 RustDesk 是否自动启动
## 文件说明
| 文件 | 说明 |
|------|------|
| `.github/workflows/flutter-build-autostart-apk.yml` | GitHub Actions 工作流定义 |
| `flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/BootReceiver.kt` | 开机启动接收器(已修改) |
| `flutter/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt` | 主服务(已修改) |
| `.github/AUTOSTART_APK_BUILD.md` | 详细文档 |
## 关键修改
**已完成**
1. BootReceiver - 开机启动默认打开
2. MainService - 服务被关闭后自动重启
## 架构选择
| 架构 | 适用设备 | 说明 |
|------|---------|------|
| **aarch64** | 大多数现代手机 | ARM64推荐选择 |
| **armv7** | 较旧的手机 | 32 位 ARM |
| **x86_64** | Android 模拟器 | 用于开发测试 |
## 常见问题
**Q: 自启动不工作?**
A:
1. 确保手机已 Root
2. 检查权限是否授予
3. 某些 ROM如小米需要额外配置
**Q: 如何查看编译错误?**
A: 点击工作流运行 → 查看各步骤的日志输出
**Q: 能否定制架构?**
A: 可以,在工作流中手动运行时选择特定架构
## 下一步
详见 [完整文档](.github/AUTOSTART_APK_BUILD.md)

View file

@ -20,17 +20,12 @@ class BootReceiver : BroadcastReceiver() {
Log.d(logTag, "onReceive ${intent.action}")
if (Intent.ACTION_BOOT_COMPLETED == intent.action || DEBUG_BOOT_COMPLETED == intent.action) {
// check SharedPreferences config
// check SharedPreferences config, default to true so boot auto-start works without manual UI action
val prefs = context.getSharedPreferences(KEY_SHARED_PREFERENCES, FlutterActivity.MODE_PRIVATE)
if (!prefs.getBoolean(KEY_START_ON_BOOT_OPT, false)) {
if (!prefs.getBoolean(KEY_START_ON_BOOT_OPT, true)) {
Log.d(logTag, "KEY_START_ON_BOOT_OPT is false")
return
}
// check pre-permission
if (!XXPermissions.isGranted(context, REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, SYSTEM_ALERT_WINDOW)){
Log.d(logTag, "REQUEST_IGNORE_BATTERY_OPTIMIZATIONS or SYSTEM_ALERT_WINDOW is not granted")
return
}
val it = Intent(context, MainService::class.java).apply {
action = ACT_INIT_MEDIA_PROJECTION_AND_SERVICE

View file

@ -346,7 +346,20 @@ class MainService : Service() {
requestMediaProjection()
}
}
return START_NOT_STICKY // don't use sticky (auto restart), the new service (from auto restart) will lose control
return START_STICKY
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
Log.d(logTag, "onTaskRemoved, restarting service")
val restartIntent = Intent(applicationContext, MainService::class.java).apply {
action = ACT_INIT_MEDIA_PROJECTION_AND_SERVICE
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
applicationContext.startForegroundService(restartIntent)
} else {
applicationContext.startService(restartIntent)
}
}
override fun onConfigurationChanged(newConfig: Configuration) {