You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何实现应用监听通话状态与来电通知?是否需用户权限?

实现来电通知监听与通话状态判断(无隐私信息获取)

嘿,刚好做过类似的功能,这就给你拆解实现步骤,完全不需要获取用户电话号码这类隐私信息,放心~

一、权限说明

不同平台的权限要求不一样,我们可以做到只申请必要权限,全程不碰隐私数据

Android

  • Android 10(API 29)及以上:需要申请 READ_PHONE_STATE(用于监听通话状态)和 POST_NOTIFICATIONS(用于显示来电通知)权限。但从Android 10开始,READ_PHONE_STATE 权限已经无法读取用户电话号码,刚好契合你的隐私要求;
  • Android 9及以下:同样需要 READ_PHONE_STATE 权限,我们的代码只会监听状态,不会读取任何隐私数据。

iOS

  • 不需要额外申请隐私权限!只需导入 CallKit 框架,通过 CXCallObserver 就能监听通话状态,全程不会接触到用户电话号码等敏感信息。

二、核心实现思路

核心逻辑就是监听系统的通话状态变更事件,根据状态触发通知或响应逻辑,全程不读取任何隐私数据

  • 来电触发时,捕获系统状态事件,显示自定义来电通知;
  • 通过判断当前通话状态(空闲/响铃/通话中),执行对应的应用响应逻辑。

三、代码示例

Android(Kotlin)

1. 配置权限与广播接收器(AndroidManifest.xml)

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<!-- 注册通话状态广播接收器 -->
<receiver android:name=".PhoneStateReceiver">
    <intent-filter>
        <action android:name="android.intent.action.PHONE_STATE" />
    </intent-filter>
</receiver>

2. 实现广播接收器(PhoneStateReceiver.kt)

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.telephony.TelephonyManager
import android.widget.Toast
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat

class PhoneStateReceiver : BroadcastReceiver() {
    private val CHANNEL_ID = "call_notification_channel"

    override fun onReceive(context: Context?, intent: Intent?) {
        val telephonyManager = context?.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        when (telephonyManager.callState) {
            TelephonyManager.CALL_STATE_RINGING -> {
                // 来电响铃,显示通知
                showCallNotification(context, "来电提醒", "有电话接入")
                // 这里添加你的响应逻辑,比如暂停应用播放、暂停任务等
            }
            TelephonyManager.CALL_STATE_OFFHOOK -> {
                // 用户正在通话中
                Toast.makeText(context, "用户当前正在通话", Toast.LENGTH_SHORT).show()
                // 执行通话中的响应逻辑,比如隐藏弹窗、暂停后台任务
            }
            TelephonyManager.CALL_STATE_IDLE -> {
                // 通话结束或无通话
                Toast.makeText(context, "当前无通话", Toast.LENGTH_SHORT).show()
                // 恢复应用正常逻辑
            }
        }
    }

    private fun showCallNotification(context: Context, title: String, content: String) {
        val notificationManager = NotificationManagerCompat.from(context)
        // 注:Android 8.0+ 需要先创建通知渠道,可自行补充渠道创建代码

        val notification = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(title)
            .setContentText(content)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .build()

        notificationManager.notify(1, notification)
    }
}

3. 权限请求(在Activity/Fragment中)

import android.Manifest
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat

class MainActivity : AppCompatActivity() {
    private val PERMISSION_REQUEST_CODE = 1001

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        requestNecessaryPermissions()
    }

    private fun requestNecessaryPermissions() {
        val permissions = arrayOf(
            Manifest.permission.READ_PHONE_STATE,
            Manifest.permission.POST_NOTIFICATIONS
        )
        val needRequest = permissions.any {
            ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
        }
        if (needRequest) {
            ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE)
        }
    }
}

iOS(Swift)

1. 导入CallKit并实现监听逻辑

import CallKit
import UserNotifications

class CallStatusManager: NSObject, CXCallObserverDelegate {
    private let callObserver = CXCallObserver()

    override init() {
        super.init()
        callObserver.setDelegate(self, queue: DispatchQueue.main)
    }

    func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
        // 判断来电状态
        if !call.hasEnded && !call.isOutgoing && !call.isOnHold {
            showCallNotification(title: "来电提醒", content: "有电话接入")
        }

        // 判断是否正在通话
        if call.isConnected {
            print("用户当前正在通话")
            // 执行通话中的响应逻辑,比如暂停播放、隐藏交互弹窗
        } else if call.hasEnded {
            print("当前无通话")
            // 恢复应用正常逻辑
        }
    }

    private func showCallNotification(title: String, content: String) {
        let notificationContent = UNMutableNotificationContent()
        notificationContent.title = title
        notificationContent.body = content
        notificationContent.sound = UNNotificationSound.default

        let request = UNNotificationRequest(
            identifier: UUID().uuidString,
            content: notificationContent,
            trigger: nil
        )
        UNUserNotificationCenter.current().add(request)
    }
}

2. 初始化监听并请求通知权限(AppDelegate)

import UIKit
import UserNotifications

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var callStatusManager: CallStatusManager?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 初始化通话状态管理器
        callStatusManager = CallStatusManager()
        
        // 请求通知权限(显示来电通知需要)
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
            if granted {
                DispatchQueue.main.async {
                    application.registerForRemoteNotifications()
                }
            }
        }
        return true
    }
}

四、关键注意事项

  • 隐私合规:以上代码全程未读取用户电话号码、联系人等隐私信息,完全符合你的需求;
  • Android 适配:Android 13+ 必须申请 POST_NOTIFICATIONS 权限才能显示通知,别忘了在代码中处理权限请求;
  • iOS 后台监听CXCallObserver 在应用后台也能正常接收通话状态回调,无需额外配置后台模式(特殊场景除外)。

内容的提问来源于stack exchange,提问作者Y.D

火山引擎 最新活动