吉安感知网项目-前端
chenyao
2026-02-27 4af871597f94631e18cc03a35bedea2679e14d9f
uniapps/work-app/src/uni_modules/lgh-dialog/utssdk/app-android/index.uts
@@ -4,6 +4,18 @@
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'
import AlertDialog from 'android.app.AlertDialog'
import DialogInterface from 'android.content.DialogInterface'
// 来电通知相关常量
const CALL_CHANNEL_ID = 'incoming_call_channel'
const CALL_NOTIFICATION_ID: Int = 2001
// 拉起应用
export function openDialog(): void {
@@ -27,12 +39,14 @@
   if (context == null) return
   // 1. 检查悬浮窗权限 (Android 6.0+)
   const noneFloat = Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(context)
   if (noneFloat) {
      uni.showToast({ title: '请允许应用悬浮在屏幕上', icon: 'none' })
   } else {
      setTimeout(() => {
   if (!noneFloat) return
   const activity = UTSAndroid.getUniActivity()
   if (activity == null) return
   AlertDialog.Builder(activity)
      .setTitle('权限提示')
      .setMessage('为了在后台收到来电时能弹出通话界面,请开启"悬浮窗"权限')
      .setPositiveButton('去设置', (_dialog : DialogInterface, _which : Int) => {
         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)
@@ -40,45 +54,71 @@
         } catch (e) {
            console.error(e)
         }
      }, 2000)
   }
      })
      .setNegativeButton('暂不', null)
      .show()
}
// 跳到后台弹出界面权限页面(应用详情设置)
export function allowBackgroundPopup() {
   const context = UTSAndroid.getAppContext()
   if (context == null) return
   try {
      const intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
      intent.setData(android.net.Uri.parse('package:' + context.getPackageName()))
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
      context.startActivity(intent)
   } catch (e) {
      console.error(e)
   }
  const context = UTSAndroid.getAppContext()
  if (context == null) return
  // 后台弹出界面无标准API,用悬浮窗权限作为代理判断(有悬浮窗权限通常也允许后台弹出)
  const nonePermission = Build.VERSION.SDK_INT >= 23 && !Settings.canDrawOverlays(context)
  if (!nonePermission) return
  const activity = UTSAndroid.getUniActivity()
  if (activity == null) return
  AlertDialog.Builder(activity)
    .setTitle('权限提示')
    .setMessage('为了在后台收到来电时能弹出通话界面,请开启"后台弹出界面"权限')
    .setPositiveButton('去设置', (_dialog : DialogInterface, _which : Int) => {
      try {
        const intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
        intent.setData(android.net.Uri.parse('package:' + context.getPackageName()))
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
      } catch (e) {
        console.error(e)
      }
    })
    .setNegativeButton('暂不', null)
    .show()
}
// 跳到锁屏显示权限页面(通知设置)
export function allowLockScreen() {
   const context = UTSAndroid.getAppContext()
   if (context == null) return
   try {
      if (Build.VERSION.SDK_INT >= 26) {
         // Android 8.0+ 跳转到应用通知设置
         const intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
         intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName())
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
         context.startActivity(intent)
      } else {
         // 低版本跳转到应用详情
         const intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
         intent.setData(android.net.Uri.parse('package:' + context.getPackageName()))
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
         context.startActivity(intent)
      }
   } catch (e) {
      console.error(e)
   }
  const context = UTSAndroid.getAppContext()
  if (context == null) return
  // 锁屏显示依赖通知权限,检查通知是否开启
  const nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
  const nonePermission = !nm.areNotificationsEnabled()
  if (!nonePermission) return
  const activity = UTSAndroid.getUniActivity()
  if (activity == null) return
  AlertDialog.Builder(activity)
    .setTitle('权限提示')
    .setMessage('为了在锁屏时能显示来电通知,请开启"锁屏显示通知"权限')
    .setPositiveButton('去设置', (_dialog : DialogInterface, _which : Int) => {
      try {
        if (Build.VERSION.SDK_INT >= 26) {
          // Android 8.0+ 跳转到应用通知设置
          const intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
          intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName())
          intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
          context.startActivity(intent)
        } else {
          // 低版本跳转到应用详情
          const intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
          intent.setData(android.net.Uri.parse('package:' + context.getPackageName()))
          intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
          context.startActivity(intent)
        }
      } catch (e) {
        console.error(e)
      }
    })
    .setNegativeButton('暂不', null)
    .show()
}
/**
@@ -100,3 +140,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)
   }
}