吉安感知网项目-前端
罗广辉
2026-02-10 d81b425672a8b9c95f46f5712c3e001f97f4b8cb
feat: 后台弹出界面
3 files modified
9 files deleted
691 ■■■■ changed files
uniapps/work-app/src/App.vue 45 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/keep-app/utssdk/app-android/index.uts 232 ●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/lgh-dialog/utssdk/app-android/index.uts 108 ●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/changelog.md patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/package.json 97 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/readme.md 7 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/app-android/config.json 3 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/app-android/index.uts 27 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/app-ios/config.json 3 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/app-ios/index.uts 85 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/interface.uts 45 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/unierror.uts 39 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/App.vue
@@ -4,7 +4,7 @@
import { useGlobalWS } from '@/hooks/useGlobalWS.js'
// #ifdef APP-PLUS
import { keepAliveStart, requestIgnoreBatteryOptimization } from '@/uni_modules/keep-app'
import { openDialog,closeDialog } from '@/uni_modules/lgh-dialog'
import { openDialog, allowFloat,getBatteryCapacity } from '@/uni_modules/lgh-dialog'
// #endif
const appStore = useAppStore()
@@ -12,34 +12,25 @@
const locationStore = useLocationStore()
// #ifdef APP-PLUS
// import { getBatteryCapacity } from '@/uni_modules/lgh-getbatteryinfo'
// console.log('电池电量:', getBatteryCapacity())
// const currentKey = ref(1)
// function testKeep() {
//     setInterval(() => {
//         currentKey.value = currentKey.value + 1
//         const val = '保活服务验证:' + currentKey.value
//         console.log(val)
//         uni.showToast({ title: val, icon: 'none' })
//     }, 1000)
// }
// testKeep()
// 开启悬浮窗
allowFloat()
// 假设五秒后来电
setTimeout(() => {
    openDialog()
}, 5000)
// #endif
const currentKey = ref(1)
function tests() {
    setInterval(() => {
        currentKey.value = currentKey.value + 1
        const val = '保活服务验证:' + currentKey.value
        console.log(val)
        uni.showToast({ title: val, icon: 'none' })
    }, 1000)
}
function popUpInterface() {
  uni.showToast({ title: '弹框', icon: 'none' })
    openDialog()
}
setTimeout(() => {
    popUpInterface()
},10000)
setTimeout(() => {
    closeDialog()
},20000)
tests()
useGlobalWS()
onShow(async () => {
uniapps/work-app/src/uni_modules/keep-app/utssdk/app-android/index.uts
@@ -1,60 +1,60 @@
// 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();
  const context = UTSAndroid.getAppContext()
    if (context == null) {
        console.error("keepAliveStart: 获取应用上下文失败");
        return;
    console.error('keepAliveStart: 获取应用上下文失败')
    return
    }
    if (isKeepAliveRunning) {
        console.log("keepAliveStart: 保活服务已在运行中");
        return;
    console.log('keepAliveStart: 保活服务已在运行中')
    return
    }
    try {
        // 1. 获取 WakeLock 唤醒锁,保持 CPU 运行
        acquireWakeLock(context);
    acquireWakeLock(context)
        // 2. 创建通知渠道 (Android 8.0+)
        createNotificationChannel(context);
    createNotificationChannel(context)
        // 3. 创建并显示前台通知
        showForegroundNotification(context);
    showForegroundNotification(context)
        // 4. 注册应用生命周期监听
        registerLifecycleCallbacks();
    registerLifecycleCallbacks()
        isKeepAliveRunning = true;
        console.log("keepAliveStart: 保活服务启动成功(WakeLock已获取)");
    isKeepAliveRunning = true
    console.log('keepAliveStart: 保活服务启动成功(WakeLock已获取)')
    } catch (e) {
        console.error("keepAliveStart: 启动失败", e);
    console.error('keepAliveStart: 启动失败', e)
    }
}
@@ -62,23 +62,23 @@
 * 停止应用保活
 */
export function keepAliveStop(): void {
    const context = UTSAndroid.getAppContext();
  const context = UTSAndroid.getAppContext()
    if (context == null) {
        return;
    return
    }
    try {
        // 释放 WakeLock
        releaseWakeLock();
    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已释放)");
    isKeepAliveRunning = false
    console.log('keepAliveStop: 保活服务已停止(WakeLock已释放)')
    } catch (e) {
        console.error("keepAliveStop: 停止失败", e);
    console.error('keepAliveStop: 停止失败', e)
    }
}
@@ -86,20 +86,20 @@
 * 检查保活服务是否正在运行
 */
export function isKeepAliveActive(): boolean {
    return isKeepAliveRunning;
  return isKeepAliveRunning
}
/**
 * 获取电池电量百分比
 */
export function getBatteryCapacity(): string {
    const context = UTSAndroid.getAppContext();
  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 + '%';
    const manager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
    const currentLevel: number = manager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
    return '' + currentLevel + '%'
    }
    return "0%";
  return '0%'
}
/**
@@ -107,27 +107,28 @@
 * 调用此方法会弹出系统设置页面
 */
export function requestIgnoreBatteryOptimization(): void {
    const context = UTSAndroid.getAppContext();
  const context = UTSAndroid.getAppContext()
    if (context == null) {
        return;
    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);
        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);
        console.error('requestIgnoreBatteryOptimization: 打开设置失败', e)
            }
        } else {
            console.log("requestIgnoreBatteryOptimization: 已在白名单中");
      console.log('requestIgnoreBatteryOptimization: 已在白名单中')
        }
    }
}
@@ -136,37 +137,34 @@
 * 检查是否已忽略电池优化
 */
export function isIgnoringBatteryOptimizations(): boolean {
    const context = UTSAndroid.getAppContext();
  const context = UTSAndroid.getAppContext()
    if (context == null) {
        return false;
    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);
    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)
    }
}
@@ -175,50 +173,47 @@
 */
function showForegroundNotification(context: Context): void {
    // 获取应用的启动 Intent
    const packageManager = context.getPackageManager();
    const launchIntent = packageManager.getLaunchIntentForPackage(context.getPackageName());
  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;
  let builder: Notification.Builder
    if (Build.VERSION.SDK_INT >= 26) {
        builder = new Notification.Builder(context, CHANNEL_ID);
    builder = new Notification.Builder(context, CHANNEL_ID)
    } else {
        builder = new Notification.Builder(context);
    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)
  builder
    .setSmallIcon(appIcon)
        .setContentTitle(appName)
        .setContentText("服务运行中")
    .setContentText('服务运行中')
        .setContentIntent(pendingIntent)
        .setOngoing(true) // 常驻通知,不可被滑动删除
        .setPriority(Notification.PRIORITY_LOW);
    .setPriority(Notification.PRIORITY_LOW)
    if (Build.VERSION.SDK_INT >= 21) {
        builder.setCategory(Notification.CATEGORY_SERVICE);
    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)
}
/**
@@ -227,27 +222,24 @@
 */
function acquireWakeLock(context: Context): void {
    if (wakeLock != null && wakeLock!.isHeld()) {
        console.log("acquireWakeLock: WakeLock 已持有");
        return;
    console.log('acquireWakeLock: WakeLock 已持有')
    return
    }
    try {
        const powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager;
    const powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
        // PARTIAL_WAKE_LOCK 保持 CPU 运行
        wakeLock = powerManager.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK,
            "KeepAlive::WakeLock"
        );
    wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 'KeepAlive::WakeLock')
        if (wakeLock != null) {
            // 设置超时时间为无限(传 0 或负数表示无限)
            // 使用 acquire() 无参版本
            wakeLock!.setReferenceCounted(false);
            wakeLock!.acquire();
            console.log("acquireWakeLock: WakeLock 获取成功");
      wakeLock!.setReferenceCounted(false)
      wakeLock!.acquire()
      console.log('acquireWakeLock: WakeLock 获取成功')
        }
    } catch (e) {
        console.error("acquireWakeLock: WakeLock 获取失败", e);
    console.error('acquireWakeLock: WakeLock 获取失败', e)
    }
}
@@ -257,11 +249,11 @@
function releaseWakeLock(): void {
    if (wakeLock != null && wakeLock!.isHeld()) {
        try {
            wakeLock!.release();
            wakeLock = null;
            console.log("releaseWakeLock: WakeLock 已释放");
      wakeLock!.release()
      wakeLock = null
      console.log('releaseWakeLock: WakeLock 已释放')
        } catch (e) {
            console.error("releaseWakeLock: WakeLock 释放失败", e);
      console.error('releaseWakeLock: WakeLock 释放失败', e)
        }
    }
}
@@ -273,28 +265,28 @@
function registerLifecycleCallbacks(): void {
    // 应用进入后台时的回调
    UTSAndroid.onAppActivityPause(() => {
        console.log("onAppActivityPause: 应用进入后台");
    console.log('onAppActivityPause: 应用进入后台')
        // 确保 WakeLock 仍然持有
        const context = UTSAndroid.getAppContext();
    const context = UTSAndroid.getAppContext()
        if (context != null && isKeepAliveRunning) {
            if (wakeLock == null || !wakeLock!.isHeld()) {
                acquireWakeLock(context);
        acquireWakeLock(context)
            }
        }
    });
  })
    // 应用返回前台时的回调
    UTSAndroid.onAppActivityResume(() => {
        console.log("onAppActivityResume: 应用返回前台");
    });
    console.log('onAppActivityResume: 应用返回前台')
  })
    // 应用被销毁时的回调
    UTSAndroid.onAppActivityDestroy(() => {
        console.log("onAppActivityDestroy: 应用被销毁");
    console.log('onAppActivityDestroy: 应用被销毁')
        // 释放资源
        releaseWakeLock();
        isKeepAliveRunning = false;
    });
    releaseWakeLock()
    isKeepAliveRunning = false
  })
    console.log("registerLifecycleCallbacks: 生命周期回调已注册");
  console.log('registerLifecycleCallbacks: 生命周期回调已注册')
}
uniapps/work-app/src/uni_modules/lgh-dialog/utssdk/app-android/index.uts
@@ -1,67 +1,65 @@
import Build from "android.os.Build";
import Context from "android.content.Context";
import WindowManager from "android.view.WindowManager";
import TextView from "android.widget.TextView";
import Gravity from "android.view.Gravity";
import Color from "android.graphics.Color";
import PixelFormat from "android.graphics.PixelFormat";
import Settings from "android.provider.Settings";
import { UTSAndroid } from "io.dcloud.uts";
import Build from 'android.os.Build'
import Context from 'android.content.Context'
import Intent from 'android.content.Intent'
import Settings from 'android.provider.Settings'
import { UTSAndroid } from 'io.dcloud.uts'
import BatteryManager from "android.os.BatteryManager";
let dialogView: TextView | null = null;
// 拉起应用
export function openDialog(): void {
    const context = UTSAndroid.getAppContext();
    if (context == null || dialogView != null) return;
    const context = UTSAndroid.getAppContext()
    if (context == null) return
    try {
        const pm = context.getPackageManager()
        const intent = pm.getLaunchIntentForPackage(context.getPackageName())
        if (intent != null) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            context.startActivity(intent)
        }
    } catch (e) {
        console.error(e)
    }
}
// 跳到允许悬浮窗权限页面
export function allowFloat() {
    const context = UTSAndroid.getAppContext()
    if (context == null) return
    // 1. 检查悬浮窗权限 (Android 6.0+)
    if (Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(context)) {
        console.error("无悬浮窗权限");
        return;
    }
    const wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager;
    if (wm == null) return;
    dialogView = new TextView(context);
    dialogView!.setText("系统接听页面");
    dialogView!.setTextColor(Color.WHITE);
    dialogView!.setTextSize(22.0.toFloat());
    dialogView!.setGravity(Gravity.CENTER);
    dialogView!.setBackgroundColor(Color.parseColor("#CC000000"));
    const type = Build.VERSION.SDK_INT >= 26 ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_PHONE;
    const flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |
        WindowManager.LayoutParams.FLAG_FULLSCREEN |
        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
        WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
        WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
    const params = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.MATCH_PARENT,
        WindowManager.LayoutParams.MATCH_PARENT,
        type,
        flags,
        PixelFormat.TRANSLUCENT
    );
    try {
        wm.addView(dialogView, params);
            // 无权限,跳转到权限设置页面
            const intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
            intent.setData(android.net.Uri.parse('package:' + context.getPackageName()))
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            context.startActivity(intent)
    } catch (e) {
        console.error(e);
        dialogView = null;
            console.error(e)
        }
        return
    }
}
export function closeDialog(): void {
    if (dialogView == null) return;
    try {
/**
 * 获取电池电量百分比
 *
 * uni-app项目中调用示例:
 * import { getBatteryCapacity } from "@/uni_modules/lgh-getbatteryinfo"
 * const capacity = getBatteryCapacity()
 * console.log('电池电量:', capacity)
 */
export function getBatteryCapacity(): string {
    // 获取android系统 application上下文
        const context = UTSAndroid.getAppContext();
        if (context == null) return;
        const wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager;
        wm.removeView(dialogView);
    } catch (e) {
        console.error(e);
    } finally {
        dialogView = null;
    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%";
}
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/changelog.md
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/package.json
File was deleted
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/readme.md
File was deleted
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/app-android/config.json
File was deleted
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/app-android/index.uts
File was deleted
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/app-ios/config.json
File was deleted
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/app-ios/index.uts
File was deleted
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/interface.uts
File was deleted
uniapps/work-app/src/uni_modules/lgh-getbatteryinfo/utssdk/unierror.uts
File was deleted