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