如何实现应用监听通话状态与来电通知?是否需用户权限?
实现来电通知监听与通话状态判断(无隐私信息获取)
嘿,刚好做过类似的功能,这就给你拆解实现步骤,完全不需要获取用户电话号码这类隐私信息,放心~
一、权限说明
不同平台的权限要求不一样,我们可以做到只申请必要权限,全程不碰隐私数据:
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




