From dfc3ee25d81398711bf5076ec5def7b38481a6f0 Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Fri, 06 Feb 2026 15:05:49 +0800
Subject: [PATCH] feat: 保活
---
uniapps/work-app/src/manifest.json | 223 ++++++++++++++++++------------------
uniapps/work-app/src/uni_modules/keep-app/utssdk/app-android/index.uts | 102 +++++++++++++++-
uniapps/work-app/src/App.vue | 16 +-
3 files changed, 217 insertions(+), 124 deletions(-)
diff --git a/uniapps/work-app/src/App.vue b/uniapps/work-app/src/App.vue
index e90687a..ccdcf8f 100644
--- a/uniapps/work-app/src/App.vue
+++ b/uniapps/work-app/src/App.vue
@@ -3,7 +3,7 @@
import { useAppStore, useUserStore, useLocationStore } from '@/store'
import { useGlobalWS } from '@/hooks/useGlobalWS.js'
// #ifdef APP-PLUS
-import { keepAliveStart } from '@/uni_modules/keep-app'
+import { keepAliveStart, requestIgnoreBatteryOptimization } from '@/uni_modules/keep-app'
// #endif
const appStore = useAppStore()
@@ -11,8 +11,8 @@
const locationStore = useLocationStore()
// #ifdef APP-PLUS
-import { getBatteryCapacity } from '@/uni_modules/lgh-getbatteryinfo'
-console.log('电池电量:', getBatteryCapacity())
+// import { getBatteryCapacity } from '@/uni_modules/lgh-getbatteryinfo'
+// console.log('电池电量:', getBatteryCapacity())
// #endif
const valuetest = ref(1)
@@ -20,11 +20,10 @@
setInterval(() => {
valuetest.value = valuetest.value + 1
console.log('valuetest.value:', valuetest.value)
-
- uni.showToast({title: valuetest.value, icon: 'none'});
+ uni.showToast({ title: valuetest.value, icon: 'none' })
}, 1000)
}
-
+tests()
useGlobalWS()
onShow(async () => {
@@ -38,7 +37,6 @@
}
}
})
-tests()
onHide(() => {
console.log('App Hide')
@@ -53,6 +51,10 @@
appStore.initSystemInfo()
// #ifdef APP-PLUS
keepAliveStart()
+ // 请求用户允许忽略电池优化(重要:用于保活)
+ setTimeout(() => {
+ requestIgnoreBatteryOptimization()
+ }, 2000)
// #endif
if (!userStore.userInfo) {
//不存在则跳转至登录页
diff --git a/uniapps/work-app/src/manifest.json b/uniapps/work-app/src/manifest.json
index 957c4be..028ccb0 100644
--- a/uniapps/work-app/src/manifest.json
+++ b/uniapps/work-app/src/manifest.json
@@ -1,112 +1,115 @@
{
- "name" : "吉安低空",
- "appid" : "__UNI__FFA6B4D",
- "description" : "",
- "versionName" : "1.0.1",
- "versionCode" : 101,
- "transformPx" : false,
- /* 5+App特有相关 */
- "app-plus" : {
- "orientation" : [
- //竖屏正方向
- "portrait-primary",
- //竖屏反方向
- "portrait-secondary",
- //横屏正方向
- "landscape-primary",
- //横屏反方向
- "landscape-secondary",
- //自然方向
- "default"
- ],
- "usingComponents" : true,
- "nvueStyleCompiler" : "uni-app",
- "compilerVersion" : 3,
- "splashscreen" : {
- "alwaysShowBeforeRender" : true,
- "waiting" : true,
- "autoclose" : true,
- "delay" : 0
- },
- /* 模块配置 */
- "modules" : {
- "Share" : {}
- },
- /* 应用发布信息 */
- "distribute" : {
- /* android打包配置 */
- "android" : {
- "permissions" : [
- "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
- "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
- "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
- "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
- "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
- "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
- "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
- "<uses-permission android:name=\"android.permission.CAMERA\"/>",
- "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
- "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
- "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
- "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
- "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
- "<uses-feature android:name=\"android.hardware.camera\"/>",
- "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
- "<uses-permission android:name=\"android.permission.RECORD_AUDIO\" />",
- "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />"
- ]
- },
- /* ios打包配置 */
- "ios" : {
- "dSYMs" : false
- },
- /* SDK配置 */
- "sdkConfigs" : {
- "share" : {
- "weixin" : {
- "appid" : "gh_f2fbbd1d5d2a",
- "UniversalLinks" : ""
- }
- }
- },
- "icons" : {
- "android" : {
- "hdpi" : "src/static/images/app-logo.png",
- "xhdpi" : "src/static/images/app-logo.png",
- "xxhdpi" : "src/static/images/app-logo.png",
- "xxxhdpi" : "src/static/images/app-logo.png"
- }
- }
- },
- "nativePlugins" : {}
- },
- /* 快应用特有相关 */
- "quickapp" : {},
- /* 小程序特有相关 */
- "mp-weixin" : {
- "appid" : "wx05742eafb412a57a",
- "setting" : {
- "urlCheck" : false
- },
- "usingComponents" : true
- },
- "mp-alipay" : {
- "usingComponents" : true
- },
- "mp-baidu" : {
- "usingComponents" : true
- },
- "mp-toutiao" : {
- "usingComponents" : true
- },
- "uniStatistics" : {
- "enable" : false
- },
- "vueVersion" : "3",
- "h5" : {
- "router" : {
- "mode" : "hash",
- "base" : "/work-app/"
- }
- }
+ "name": "吉安低空",
+ "appid": "__UNI__FFA6B4D",
+ "description": "",
+ "versionName": "1.0.1",
+ "versionCode": 101,
+ "transformPx": false,
+ /* 5+App特有相关 */
+ "app-plus": {
+ "orientation": [
+ //竖屏正方向
+ "portrait-primary",
+ //竖屏反方向
+ "portrait-secondary",
+ //横屏正方向
+ "landscape-primary",
+ //横屏反方向
+ "landscape-secondary",
+ //自然方向
+ "default"
+ ],
+ "usingComponents": true,
+ "nvueStyleCompiler": "uni-app",
+ "compilerVersion": 3,
+ "splashscreen": {
+ "alwaysShowBeforeRender": true,
+ "waiting": true,
+ "autoclose": true,
+ "delay": 0
+ },
+ /* 模块配置 */
+ "modules": {
+ "Share": {}
+ },
+ /* 应用发布信息 */
+ "distribute": {
+ /* android打包配置 */
+ "android": {
+ "permissions": [
+ "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+ "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+ "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+ "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+ "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+ "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+ "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+ "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+ "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+ "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+ "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+ "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+ "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+ "<uses-feature android:name=\"android.hardware.camera\"/>",
+ "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
+ "<uses-permission android:name=\"android.permission.RECORD_AUDIO\" />",
+ "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />",
+ "<uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />",
+ "<uses-permission android:name=\"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS\" />"
+ ]
+ },
+ /* ios打包配置 */
+ "ios": {
+ "dSYMs": false
+ },
+ /* SDK配置 */
+ "sdkConfigs": {
+ "share": {
+ "weixin": {
+ "appid": "gh_f2fbbd1d5d2a",
+ "UniversalLinks": ""
+ }
+ }
+ },
+ "icons": {
+ "android": {
+ "hdpi": "src/static/images/app-logo.png",
+ "xhdpi": "src/static/images/app-logo.png",
+ "xxhdpi": "src/static/images/app-logo.png",
+ "xxxhdpi": "src/static/images/app-logo.png"
+ }
+ }
+ },
+ "nativePlugins": {}
+ },
+ /* 快应用特有相关 */
+ "quickapp": {},
+ /* 小程序特有相关 */
+ "mp-weixin": {
+ "appid": "wx05742eafb412a57a",
+ "setting": {
+ "urlCheck": false
+ },
+ "usingComponents": true
+ },
+ "mp-alipay": {
+ "usingComponents": true
+ },
+ "mp-baidu": {
+ "usingComponents": true
+ },
+ "mp-toutiao": {
+ "usingComponents": true
+ },
+ "uniStatistics": {
+ "enable": false
+ },
+ "vueVersion": "3",
+ "h5": {
+ "router": {
+ "mode": "hash",
+ "base": "/work-app/"
+ }
+ }
}
+
diff --git a/uniapps/work-app/src/uni_modules/keep-app/utssdk/app-android/index.uts b/uniapps/work-app/src/uni_modules/keep-app/utssdk/app-android/index.uts
index 9574b10..ec249a6 100644
--- a/uniapps/work-app/src/uni_modules/keep-app/utssdk/app-android/index.uts
+++ b/uniapps/work-app/src/uni_modules/keep-app/utssdk/app-android/index.uts
@@ -8,8 +8,6 @@
import NotificationManager from "android.app.NotificationManager";
import Notification from "android.app.Notification";
import PendingIntent from "android.app.PendingIntent";
-import Service from "android.app.Service";
-import IBinder from "android.os.IBinder";
import PowerManager from "android.os.PowerManager";
import BatteryManager from "android.os.BatteryManager";
import { UTSAndroid } from "io.dcloud.uts";
@@ -21,9 +19,12 @@
// 保活服务是否已启动的标志
let isKeepAliveRunning = false;
+// WakeLock 引用,用于保持 CPU 运行
+let wakeLock: PowerManager.WakeLock | null = null;
+
/**
* 启动应用保活
- * 通过启动前台服务来保持应用在后台运行
+ * 通过 WakeLock + 通知来保持应用在后台运行
*/
export function keepAliveStart(): void {
const context = UTSAndroid.getAppContext();
@@ -38,14 +39,20 @@
}
try {
- // 创建通知渠道 (Android 8.0+)
+ // 1. 获取 WakeLock 唤醒锁,保持 CPU 运行
+ acquireWakeLock(context);
+
+ // 2. 创建通知渠道 (Android 8.0+)
createNotificationChannel(context);
- // 创建并显示前台通知
+ // 3. 创建并显示前台通知
showForegroundNotification(context);
+ // 4. 注册应用生命周期监听
+ registerLifecycleCallbacks();
+
isKeepAliveRunning = true;
- console.log("keepAliveStart: 保活服务启动成功");
+ console.log("keepAliveStart: 保活服务启动成功(WakeLock已获取)");
} catch (e) {
console.error("keepAliveStart: 启动失败", e);
}
@@ -61,12 +68,15 @@
}
try {
+ // 释放 WakeLock
+ releaseWakeLock();
+
// 取消通知
const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
notificationManager.cancel(NOTIFICATION_ID);
isKeepAliveRunning = false;
- console.log("keepAliveStop: 保活服务已停止");
+ console.log("keepAliveStop: 保活服务已停止(WakeLock已释放)");
} catch (e) {
console.error("keepAliveStop: 停止失败", e);
}
@@ -210,3 +220,81 @@
const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
notificationManager.notify(NOTIFICATION_ID, notification);
}
+
+/**
+ * 获取 WakeLock 唤醒锁
+ * PARTIAL_WAKE_LOCK: 保持 CPU 运行,屏幕和键盘背光可以关闭
+ */
+function acquireWakeLock(context: Context): void {
+ if (wakeLock != null && wakeLock!.isHeld()) {
+ console.log("acquireWakeLock: WakeLock 已持有");
+ return;
+ }
+
+ try {
+ const powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager;
+ // PARTIAL_WAKE_LOCK 保持 CPU 运行
+ wakeLock = powerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK,
+ "KeepAlive::WakeLock"
+ );
+
+ if (wakeLock != null) {
+ // 设置超时时间为无限(传 0 或负数表示无限)
+ // 使用 acquire() 无参版本
+ wakeLock!.setReferenceCounted(false);
+ wakeLock!.acquire();
+ console.log("acquireWakeLock: WakeLock 获取成功");
+ }
+ } catch (e) {
+ console.error("acquireWakeLock: WakeLock 获取失败", e);
+ }
+}
+
+/**
+ * 释放 WakeLock 唤醒锁
+ */
+function releaseWakeLock(): void {
+ if (wakeLock != null && wakeLock!.isHeld()) {
+ try {
+ wakeLock!.release();
+ wakeLock = null;
+ console.log("releaseWakeLock: WakeLock 已释放");
+ } catch (e) {
+ console.error("releaseWakeLock: WakeLock 释放失败", e);
+ }
+ }
+}
+
+/**
+ * 注册应用生命周期回调
+ * 当应用进入后台时,确保 WakeLock 保持持有
+ */
+function registerLifecycleCallbacks(): void {
+ // 应用进入后台时的回调
+ UTSAndroid.onAppActivityPause(() => {
+ console.log("onAppActivityPause: 应用进入后台");
+ // 确保 WakeLock 仍然持有
+ const context = UTSAndroid.getAppContext();
+ if (context != null && isKeepAliveRunning) {
+ if (wakeLock == null || !wakeLock!.isHeld()) {
+ acquireWakeLock(context);
+ }
+ }
+ });
+
+ // 应用返回前台时的回调
+ UTSAndroid.onAppActivityResume(() => {
+ console.log("onAppActivityResume: 应用返回前台");
+ });
+
+ // 应用被销毁时的回调
+ UTSAndroid.onAppActivityDestroy(() => {
+ console.log("onAppActivityDestroy: 应用被销毁");
+ // 释放资源
+ releaseWakeLock();
+ isKeepAliveRunning = false;
+ });
+
+ console.log("registerLifecycleCallbacks: 生命周期回调已注册");
+}
--
Gitblit v1.9.3