You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 12/13实现类WhatsApp/TrueCaller来电弹窗与全屏意图求助

Android 12/13 实现来电通知弹窗及全屏意图方案

1. 权限配置

  • 必须申请POST_NOTIFICATIONS权限(Android 13+),在Manifest中声明:
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    
    同时保留READ_PHONE_STATE、FOREGROUND_SERVICE权限,Android 12+需为前台服务指定类型:
    <service
        android:name=".CallForegroundService"
        android:foregroundServiceType="phoneCall" />
    
  • 运行时动态请求POST_NOTIFICATIONS和READ_PHONE_STATE权限,无权限无法触发通知或监听来电。

2. 替换广播接收器的来电监听方案

Android 12+对隐式广播接收器限制严格,需改为动态监听:

  • 使用PhoneStateListener在前台服务中监听来电状态,避免后台监听被系统回收:
    val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
    val phoneStateListener = object : PhoneStateListener() {
        override fun onCallStateChanged(state: Int, phoneNumber: String?) {
            super.onCallStateChanged(state, phoneNumber)
            if (state == TelephonyManager.CALL_STATE_RINGING && phoneNumber != null) {
                // 触发来电通知弹窗逻辑
                showCallNotification(phoneNumber)
            }
        }
    }
    // 在前台服务的onStartCommand中注册监听
    telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE)
    

3. 前台服务的合规启动

Android 12+启动前台服务需满足触发场景(如来电事件),启动后必须立即调用startForeground:

// 启动前台服务
val serviceIntent = Intent(context, CallForegroundService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    context.startForegroundService(serviceIntent)
} else {
    context.startService(serviceIntent)
}

// 服务内部启动前台
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    val foregroundNotification = NotificationCompat.Builder(this, "FOREGROUND_CHANNEL")
        .setContentTitle("来电识别中")
        .setSmallIcon(R.drawable.ic_notification)
        .setPriority(NotificationCompat.PRIORITY_LOW)
        .build()
    startForeground(1, foregroundNotification, ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL)
    return START_STICKY
}

4. 高优先级通知+全屏意图实现弹窗

这是实现类似WhatsApp/TrueCaller来电弹窗的核心:

  • 先创建高优先级通知渠道(Android 8.0+):
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            "CALL_CHANNEL",
            "来电通知",
            NotificationManager.IMPORTANCE_HIGH
        ).apply {
            setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE), null)
            enableVibration(true)
        }
        val notificationManager = getSystemService(NotificationManager::class.java)
        notificationManager.createNotificationChannel(channel)
    }
    
  • 构建带全屏意图的来电通知:
    // 全屏弹窗Activity的PendingIntent
    val fullScreenIntent = Intent(this, CallPopupActivity::class.java).apply {
        putExtra("PHONE_NUMBER", phoneNumber)
    }
    val fullScreenPendingIntent = PendingIntent.getActivity(
        this,
        0,
        fullScreenIntent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )
    
    // 构建通知
    val notification = NotificationCompat.Builder(this, "CALL_CHANNEL")
        .setContentTitle("陌生来电")
        .setContentText(phoneNumber)
        .setSmallIcon(R.drawable.ic_call)
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setCategory(NotificationCompat.CATEGORY_CALL)
        .setFullScreenIntent(fullScreenPendingIntent, true)
        // 添加接听/挂断操作按钮
        .addAction(
            R.drawable.ic_accept,
            "接听",
            PendingIntent.getService(this, 1, acceptIntent, PendingIntent.FLAG_IMMUTABLE)
        )
        .addAction(
            R.drawable.ic_reject,
            "挂断",
            PendingIntent.getService(this, 2, rejectIntent, PendingIntent.FLAG_IMMUTABLE)
        )
        .build()
    
    // 显示通知
    val notificationManager = getSystemService(NotificationManager::class.java)
    notificationManager.notify(2, notification)
    

5. 来电弹窗Activity配置

在Manifest中配置Activity属性,确保锁屏可见、全屏显示:

<activity
    android:name=".CallPopupActivity"
    android:showOnLockScreen="true"
    android:showWhenLocked="true"
    android:turnScreenOn="true"
    android:excludeFromRecents="true"
    android:launchMode="singleInstance"
    android:theme="@style/CallPopupTheme">
</activity>

对应的主题设置:

<style name="CallPopupTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
</style>

关键注意事项

  • Android 12+中,全屏意图对应的Activity必须有可见内容,不能完全透明,否则系统会拦截。
  • 通知渠道必须设置为IMPORTANCE_HIGH,否则无法触发全屏弹窗。
  • 前台服务类型必须指定为phoneCall,避免被系统限制启动。

内容的提问来源于stack exchange,提问作者user1847921

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 21:10:28