From d81b425672a8b9c95f46f5712c3e001f97f4b8cb Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Tue, 10 Feb 2026 10:03:59 +0800
Subject: [PATCH] feat: 后台弹出界面
---
uniapps/work-app/src/uni_modules/keep-app/utssdk/app-android/index.uts | 374 ++++++++++++++++++++++++++---------------------------
1 files changed, 183 insertions(+), 191 deletions(-)
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 ec249a6..2ce95f2 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
@@ -1,105 +1,105 @@
// index.uts - Android 应用保活插件
// 引用 Android API
-import Context from "android.content.Context";
-import Intent from "android.content.Intent";
-import Build from "android.os.Build";
-import NotificationChannel from "android.app.NotificationChannel";
-import NotificationManager from "android.app.NotificationManager";
-import Notification from "android.app.Notification";
-import PendingIntent from "android.app.PendingIntent";
-import PowerManager from "android.os.PowerManager";
-import BatteryManager from "android.os.BatteryManager";
-import { UTSAndroid } from "io.dcloud.uts";
+import Context from 'android.content.Context'
+import Intent from 'android.content.Intent'
+import Build from 'android.os.Build'
+import NotificationChannel from 'android.app.NotificationChannel'
+import NotificationManager from 'android.app.NotificationManager'
+import Notification from 'android.app.Notification'
+import PendingIntent from 'android.app.PendingIntent'
+import PowerManager from 'android.os.PowerManager'
+import BatteryManager from 'android.os.BatteryManager'
+import { UTSAndroid } from 'io.dcloud.uts'
// 保活服务的通知渠道ID
-const CHANNEL_ID = "keep_alive_channel";
-const NOTIFICATION_ID: Int = 1001;
+const CHANNEL_ID = 'keep_alive_channel'
+const NOTIFICATION_ID: Int = 1001
// 保活服务是否已启动的标志
-let isKeepAliveRunning = false;
+let isKeepAliveRunning = false
// WakeLock 引用,用于保持 CPU 运行
-let wakeLock: PowerManager.WakeLock | null = null;
+let wakeLock: PowerManager.WakeLock | null = null
/**
* 启动应用保活
* 通过 WakeLock + 通知来保持应用在后台运行
*/
export function keepAliveStart(): void {
- const context = UTSAndroid.getAppContext();
- if (context == null) {
- console.error("keepAliveStart: 获取应用上下文失败");
- return;
- }
+ const context = UTSAndroid.getAppContext()
+ if (context == null) {
+ console.error('keepAliveStart: 获取应用上下文失败')
+ return
+ }
- if (isKeepAliveRunning) {
- console.log("keepAliveStart: 保活服务已在运行中");
- return;
- }
+ if (isKeepAliveRunning) {
+ console.log('keepAliveStart: 保活服务已在运行中')
+ return
+ }
- try {
- // 1. 获取 WakeLock 唤醒锁,保持 CPU 运行
- acquireWakeLock(context);
+ try {
+ // 1. 获取 WakeLock 唤醒锁,保持 CPU 运行
+ acquireWakeLock(context)
- // 2. 创建通知渠道 (Android 8.0+)
- createNotificationChannel(context);
+ // 2. 创建通知渠道 (Android 8.0+)
+ createNotificationChannel(context)
- // 3. 创建并显示前台通知
- showForegroundNotification(context);
+ // 3. 创建并显示前台通知
+ showForegroundNotification(context)
- // 4. 注册应用生命周期监听
- registerLifecycleCallbacks();
+ // 4. 注册应用生命周期监听
+ registerLifecycleCallbacks()
- isKeepAliveRunning = true;
- console.log("keepAliveStart: 保活服务启动成功(WakeLock已获取)");
- } catch (e) {
- console.error("keepAliveStart: 启动失败", e);
- }
+ isKeepAliveRunning = true
+ console.log('keepAliveStart: 保活服务启动成功(WakeLock已获取)')
+ } catch (e) {
+ console.error('keepAliveStart: 启动失败', e)
+ }
}
/**
* 停止应用保活
*/
export function keepAliveStop(): void {
- const context = UTSAndroid.getAppContext();
- if (context == null) {
- return;
- }
+ const context = UTSAndroid.getAppContext()
+ if (context == null) {
+ return
+ }
- try {
- // 释放 WakeLock
- releaseWakeLock();
+ try {
+ // 释放 WakeLock
+ releaseWakeLock()
- // 取消通知
- const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
- notificationManager.cancel(NOTIFICATION_ID);
+ // 取消通知
+ const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ notificationManager.cancel(NOTIFICATION_ID)
- isKeepAliveRunning = false;
- console.log("keepAliveStop: 保活服务已停止(WakeLock已释放)");
- } catch (e) {
- console.error("keepAliveStop: 停止失败", e);
- }
+ isKeepAliveRunning = false
+ console.log('keepAliveStop: 保活服务已停止(WakeLock已释放)')
+ } catch (e) {
+ console.error('keepAliveStop: 停止失败', e)
+ }
}
/**
* 检查保活服务是否正在运行
*/
export function isKeepAliveActive(): boolean {
- return isKeepAliveRunning;
+ return isKeepAliveRunning
}
/**
* 获取电池电量百分比
*/
export function getBatteryCapacity(): string {
- const context = UTSAndroid.getAppContext();
- if (context != null) {
- const manager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager;
- const currentLevel: number = manager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
- return '' + currentLevel + '%';
- }
- return "0%";
+ const context = UTSAndroid.getAppContext()
+ if (context != null) {
+ const manager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
+ const currentLevel: number = manager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
+ return '' + currentLevel + '%'
+ }
+ return '0%'
}
/**
@@ -107,118 +107,113 @@
* 调用此方法会弹出系统设置页面
*/
export function requestIgnoreBatteryOptimization(): void {
- const context = UTSAndroid.getAppContext();
- if (context == null) {
- return;
- }
+ const context = UTSAndroid.getAppContext()
+ if (context == null) {
+ return
+ }
- if (Build.VERSION.SDK_INT >= 23) { // Android 6.0+
- const powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager;
- const packageName = context.getPackageName();
+ if (Build.VERSION.SDK_INT >= 23) {
+ // Android 6.0+
+ const powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
+ const packageName = context.getPackageName()
- if (!powerManager.isIgnoringBatteryOptimizations(packageName)) {
- try {
- const intent = new Intent();
- intent.setAction("android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS");
- intent.setData(android.net.Uri.parse("package:" + packageName));
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(intent);
- } catch (e) {
- console.error("requestIgnoreBatteryOptimization: 打开设置失败", e);
- }
- } else {
- console.log("requestIgnoreBatteryOptimization: 已在白名单中");
- }
+ if (!powerManager.isIgnoringBatteryOptimizations(packageName)) {
+ try {
+ const intent = new Intent()
+ intent.setAction('android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS')
+ intent.setData(android.net.Uri.parse('package:' + packageName))
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ context.startActivity(intent)
+ } catch (e) {
+ console.error('requestIgnoreBatteryOptimization: 打开设置失败', e)
+ }
+ } else {
+ console.log('requestIgnoreBatteryOptimization: 已在白名单中')
}
+ }
}
/**
* 检查是否已忽略电池优化
*/
export function isIgnoringBatteryOptimizations(): boolean {
- const context = UTSAndroid.getAppContext();
- if (context == null) {
- return false;
- }
+ const context = UTSAndroid.getAppContext()
+ if (context == null) {
+ return false
+ }
- if (Build.VERSION.SDK_INT >= 23) {
- const powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager;
- const packageName = context.getPackageName();
- return powerManager.isIgnoringBatteryOptimizations(packageName);
- }
+ if (Build.VERSION.SDK_INT >= 23) {
+ const powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
+ const packageName = context.getPackageName()
+ return powerManager.isIgnoringBatteryOptimizations(packageName)
+ }
- return true; // Android 6.0 以下默认返回 true
+ return true // Android 6.0 以下默认返回 true
}
/**
* 创建通知渠道 (Android 8.0+ 必需)
*/
function createNotificationChannel(context: Context): void {
- if (Build.VERSION.SDK_INT >= 26) { // Android 8.0+
- const channel = new NotificationChannel(
- CHANNEL_ID,
- "应用保活服务",
- NotificationManager.IMPORTANCE_LOW
- );
- channel.setDescription("保持应用在后台运行");
- channel.setShowBadge(false);
- channel.enableLights(false);
- channel.enableVibration(false);
+ if (Build.VERSION.SDK_INT >= 26) {
+ // Android 8.0+
+ const channel = new NotificationChannel(CHANNEL_ID, '应用保活服务', NotificationManager.IMPORTANCE_LOW)
+ channel.setDescription('保持应用在后台运行')
+ channel.setShowBadge(false)
+ channel.enableLights(false)
+ channel.enableVibration(false)
- const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
- notificationManager.createNotificationChannel(channel);
- }
+ const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ notificationManager.createNotificationChannel(channel)
+ }
}
/**
* 显示前台通知
*/
function showForegroundNotification(context: Context): void {
- // 获取应用的启动 Intent
- const packageManager = context.getPackageManager();
- const launchIntent = packageManager.getLaunchIntentForPackage(context.getPackageName());
+ // 获取应用的启动 Intent
+ const packageManager = context.getPackageManager()
+ const launchIntent = packageManager.getLaunchIntentForPackage(context.getPackageName())
- let pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT;
- if (Build.VERSION.SDK_INT >= 31) { // Android 12+
- pendingIntentFlags = pendingIntentFlags | PendingIntent.FLAG_IMMUTABLE;
- }
+ let pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT
+ if (Build.VERSION.SDK_INT >= 31) {
+ // Android 12+
+ pendingIntentFlags = pendingIntentFlags | PendingIntent.FLAG_IMMUTABLE
+ }
- const pendingIntent = PendingIntent.getActivity(
- context,
- 0,
- launchIntent,
- pendingIntentFlags
- );
+ const pendingIntent = PendingIntent.getActivity(context, 0, launchIntent, pendingIntentFlags)
- // 构建通知
- let builder: Notification.Builder;
- if (Build.VERSION.SDK_INT >= 26) {
- builder = new Notification.Builder(context, CHANNEL_ID);
- } else {
- builder = new Notification.Builder(context);
- }
+ // 构建通知
+ let builder: Notification.Builder
+ if (Build.VERSION.SDK_INT >= 26) {
+ builder = new Notification.Builder(context, CHANNEL_ID)
+ } else {
+ builder = new Notification.Builder(context)
+ }
- // 获取应用图标
- const appInfo = context.getApplicationInfo();
- const appIcon = appInfo.icon;
- const appName = packageManager.getApplicationLabel(appInfo).toString();
+ // 获取应用图标
+ const appInfo = context.getApplicationInfo()
+ const appIcon = appInfo.icon
+ const appName = packageManager.getApplicationLabel(appInfo).toString()
- builder.setSmallIcon(appIcon)
- .setContentTitle(appName)
- .setContentText("服务运行中")
- .setContentIntent(pendingIntent)
- .setOngoing(true) // 常驻通知,不可被滑动删除
- .setPriority(Notification.PRIORITY_LOW);
+ builder
+ .setSmallIcon(appIcon)
+ .setContentTitle(appName)
+ .setContentText('服务运行中')
+ .setContentIntent(pendingIntent)
+ .setOngoing(true) // 常驻通知,不可被滑动删除
+ .setPriority(Notification.PRIORITY_LOW)
- if (Build.VERSION.SDK_INT >= 21) {
- builder.setCategory(Notification.CATEGORY_SERVICE);
- }
+ if (Build.VERSION.SDK_INT >= 21) {
+ builder.setCategory(Notification.CATEGORY_SERVICE)
+ }
- const notification = builder.build();
+ const notification = builder.build()
- // 显示通知
- const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
- notificationManager.notify(NOTIFICATION_ID, notification);
+ // 显示通知
+ const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ notificationManager.notify(NOTIFICATION_ID, notification)
}
/**
@@ -226,44 +221,41 @@
* PARTIAL_WAKE_LOCK: 保持 CPU 运行,屏幕和键盘背光可以关闭
*/
function acquireWakeLock(context: Context): void {
- if (wakeLock != null && wakeLock!.isHeld()) {
- console.log("acquireWakeLock: WakeLock 已持有");
- return;
- }
+ 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"
- );
+ 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);
+ 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);
- }
+ if (wakeLock != null && wakeLock!.isHeld()) {
+ try {
+ wakeLock!.release()
+ wakeLock = null
+ console.log('releaseWakeLock: WakeLock 已释放')
+ } catch (e) {
+ console.error('releaseWakeLock: WakeLock 释放失败', e)
}
+ }
}
/**
@@ -271,30 +263,30 @@
* 当应用进入后台时,确保 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.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.onAppActivityResume(() => {
+ console.log('onAppActivityResume: 应用返回前台')
+ })
- // 应用被销毁时的回调
- UTSAndroid.onAppActivityDestroy(() => {
- console.log("onAppActivityDestroy: 应用被销毁");
- // 释放资源
- releaseWakeLock();
- isKeepAliveRunning = false;
- });
+ // 应用被销毁时的回调
+ UTSAndroid.onAppActivityDestroy(() => {
+ console.log('onAppActivityDestroy: 应用被销毁')
+ // 释放资源
+ releaseWakeLock()
+ isKeepAliveRunning = false
+ })
- console.log("registerLifecycleCallbacks: 生命周期回调已注册");
+ console.log('registerLifecycleCallbacks: 生命周期回调已注册')
}
--
Gitblit v1.9.3