吉安感知网项目-前端
罗广辉
2026-02-26 81b8c688c80520b2beb38088dcee8fa5f2754e80
feat: 权限获取调整
3 files modified
226 ■■■■ changed files
uniapps/work-app/src/App.vue 58 ●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/keep-app/utssdk/app-android/index.uts 2 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/uni_modules/lgh-dialog/utssdk/app-android/index.uts 166 ●●●●● 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, isIgnoringBatteryOptimizations } from '@/uni_modules/keep-app'
import { openDialog, allowFloat, getBatteryCapacity } from '@/uni_modules/lgh-dialog'
import { openDialog, allowFloat, getBatteryCapacity, allowBackgroundPopup, allowLockScreen } from '@/uni_modules/lgh-dialog'
// #endif
const appStore = useAppStore()
@@ -22,15 +22,6 @@
//     }, 1000)
// }
// testKeep()
// 开启悬浮窗
// allowFloat()
// 假设五秒后来电
// #endif
// #ifdef APP-PLUS
//显示悬浮窗权限
allowFloat()
// #endif
useGlobalWS()
@@ -58,12 +49,57 @@
function setKeepFun() {
    // #ifdef APP-PLUS
    keepAliveStart()
    //显示悬浮窗权限
    // setTimeout(allowFloat, 5000)
    // 请求用户允许忽略电池优化(重要:用于保活)
    setTimeout(() => {
        if (!isIgnoringBatteryOptimizations()) {
            requestIgnoreBatteryOptimization()
            uni.showModal({
                title: '权限提示',
                content: '为了在后台收到来电时能弹出通话界面,请将应用添加到电池优化白名单',
                confirmText: '去设置',
                cancelText: '暂不',
                success(res) {
                    if (res.confirm) {
                        requestIgnoreBatteryOptimization()
                    }
                }
            })
        }
    }, 10000)
    // 引导用户开启「后台弹出界面」权限
    // setTimeout(() => {
    //     uni.showModal({
    //         title: '权限提示',
    //         content: '为了在后台收到来电时能弹出通话界面,请开启“后台弹出界面”权限',
    //         confirmText: '去设置',
    //         cancelText: '暂不',
    //         success(res) {
    //             if (res.confirm) {
    //                 allowBackgroundPopup()
    //             }
    //         }
    //     })
    // }, 15000)
    //
    // // 引导用户开启「锁屏显示」权限
    // setTimeout(() => {
    //     uni.showModal({
    //         title: '权限提示',
    //         content: '为了在锁屏时能显示来电通知,请开启“锁屏显示通知”权限',
    //         confirmText: '去设置',
    //         cancelText: '暂不',
    //         success(res) {
    //             if (res.confirm) {
    //                 allowLockScreen()
    //             }
    //         }
    //     })
    // }, 20000)
    // #endif
}
uniapps/work-app/src/uni_modules/keep-app/utssdk/app-android/index.uts
@@ -118,8 +118,6 @@
    const packageName = context.getPackageName()
    if (!powerManager.isIgnoringBatteryOptimizations(packageName)) {
      // 给个提示
      uni.showToast({  title: '请将应用添加到电池优化白名单'})
      try {
        const intent = new Intent()
        intent.setAction('android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS')
uniapps/work-app/src/uni_modules/lgh-dialog/utssdk/app-android/index.uts
@@ -4,6 +4,16 @@
import Settings from 'android.provider.Settings'
import { UTSAndroid } from 'io.dcloud.uts'
import BatteryManager from 'android.os.BatteryManager'
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 KeyguardManager from 'android.app.KeyguardManager'
// 来电通知相关常量
const CALL_CHANNEL_ID = 'incoming_call_channel'
const CALL_NOTIFICATION_ID: Int = 2001
// 拉起应用
export function openDialog(): void {
@@ -28,19 +38,25 @@
    // 1. 检查悬浮窗权限 (Android 6.0+)
    const noneFloat = Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(context)
    if (noneFloat) {
        uni.showToast({ title: '请允许应用悬浮在屏幕上', icon: 'none' })
    } else {
        setTimeout(() => {
            try {
                // 无权限,跳转到权限设置页面
                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)
            }
        }, 2000)
        uni.showModal({
            title: '权限提示',
            content: '为了在后台收到来电时能弹出通话界面,请开启“悬浮”权限',
            confirmText: '去设置',
            cancelText: '暂不',
            success(res) {
                if (res.confirm) {
            try {
              // 无权限,跳转到权限设置页面
              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)
            }
                }
            }
        })
    }
}
@@ -100,3 +116,127 @@
    return '0%'
}
/**
 * 显示来电通知(锁屏/后台可弹出)
 * 利用高优先级通知 + fullScreenIntent 实现锁屏/后台来电提醒
 * @param callerName 来电者名称
 */
export function showIncomingCallNotification(callerName: string): void {
    const context = UTSAndroid.getAppContext()
    if (context == null) return
    try {
        // 1. 创建来电通知渠道(IMPORTANCE_HIGH → Heads-up 弹出)
        if (Build.VERSION.SDK_INT >= 26) {
            const channel = new NotificationChannel(
                CALL_CHANNEL_ID,
                '来电通知',
                NotificationManager.IMPORTANCE_HIGH
            )
            channel.setDescription('语音来电通知')
            channel.enableVibration(true)
            channel.enableLights(true)
            channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC)
            channel.setBypassDnd(true)
            const nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            nm.createNotificationChannel(channel)
        }
        // 2. 构建点击通知后打开应用的 Intent
        const pm = context.getPackageManager()
        const launchIntent = pm.getLaunchIntentForPackage(context.getPackageName())
        if (launchIntent != null) {
            launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        }
        let pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT
        if (Build.VERSION.SDK_INT >= 31) {
            pendingIntentFlags = pendingIntentFlags | PendingIntent.FLAG_IMMUTABLE
        }
        const contentIntent = PendingIntent.getActivity(context, 0, launchIntent, pendingIntentFlags)
        // fullScreenIntent 用于锁屏时全屏展示
        const fullScreenIntent = PendingIntent.getActivity(context, 1, launchIntent, pendingIntentFlags)
        // 3. 构建通知
        const appInfo = context.getApplicationInfo()
        const appIcon = appInfo.icon
        let builder: Notification.Builder
        if (Build.VERSION.SDK_INT >= 26) {
            builder = new Notification.Builder(context, CALL_CHANNEL_ID)
        } else {
            builder = new Notification.Builder(context)
        }
        builder
            .setSmallIcon(appIcon)
            .setContentTitle('语音来电')
            .setContentText(callerName + ' 正在呼叫您')
            .setContentIntent(contentIntent)
            .setFullScreenIntent(fullScreenIntent, true)  // 🔑 锁屏全屏弹出
            .setOngoing(true)
            .setAutoCancel(false)
            .setPriority(Notification.PRIORITY_MAX)
            .setVisibility(Notification.VISIBILITY_PUBLIC) // 锁屏显示完整内容
        if (Build.VERSION.SDK_INT >= 21) {
            builder.setCategory(Notification.CATEGORY_CALL) // 标记为来电类型
        }
        const notification = builder.build()
        // 设置通知标志:保持常亮、不可清除
        notification.flags = notification.flags | Notification.FLAG_INSISTENT | Notification.FLAG_NO_CLEAR
        // 4. 发送通知
        const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(CALL_NOTIFICATION_ID, notification)
        // 5. 如果在锁屏状态,尝试亮屏
        wakeUpScreen(context)
        console.log('showIncomingCallNotification: 来电通知已发送,来电者:', callerName)
    } catch (e) {
        console.error('showIncomingCallNotification: 发送来电通知失败', e)
    }
}
/**
 * 取消来电通知
 * 在接听或拒接后调用
 */
export function cancelIncomingCallNotification(): void {
    const context = UTSAndroid.getAppContext()
    if (context == null) return
    try {
        const notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.cancel(CALL_NOTIFICATION_ID)
        console.log('cancelIncomingCallNotification: 来电通知已取消')
    } catch (e) {
        console.error('cancelIncomingCallNotification: 取消来电通知失败', e)
    }
}
/**
 * 唤醒屏幕(锁屏时亮屏)
 */
function wakeUpScreen(context: Context): void {
    try {
        const powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
        if (!powerManager.isInteractive()) {
            // 屏幕关闭,唤醒屏幕
            const screenLock = powerManager.newWakeLock(
                PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                'IncomingCall::WakeUp'
            )
            screenLock.acquire(10000) // 保持亮屏 10 秒
        }
    } catch (e) {
        console.error('wakeUpScreen: 唤醒屏幕失败', e)
    }
}