Android服务监听电话实战:从客服场景到技术实现全解析

一、业务场景与技术背景

在移动端客服系统中,电话监听是提升服务效率的核心功能。例如当用户拨打企业客服热线时,系统需自动识别来电号码、记录通话时长、触发工单分配等操作。Android系统的Service组件因其独立于Activity的生命周期特性,成为实现后台电话监听的最优选择。

技术挑战

  1. 权限管控:Android 10+对电话状态访问实施严格限制
  2. 服务持续性:需应对系统资源回收导致的服务终止
  3. 多场景适配:包括来电、去电、通话状态变更等事件处理

二、核心实现方案

1. 权限声明与动态申请

  1. <!-- AndroidManifest.xml -->
  2. <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  3. <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
  4. <!-- Android 10+需额外声明 -->
  5. <uses-permission android:name="android.permission.READ_CALL_LOG" />

动态权限申请示例:

  1. private fun checkPhonePermissions() {
  2. val permissions = mutableListOf(
  3. Manifest.permission.READ_PHONE_STATE,
  4. Manifest.permission.PROCESS_OUTGOING_CALLS
  5. )
  6. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
  7. permissions.add(Manifest.permission.READ_CALL_LOG)
  8. }
  9. ActivityCompat.requestPermissions(
  10. this,
  11. permissions.toTypedArray(),
  12. PERMISSION_REQUEST_CODE
  13. )
  14. }

2. 监听服务实现

服务基础架构

  1. class PhoneMonitorService : Service() {
  2. private lateinit var telephonyManager: TelephonyManager
  3. private lateinit var phoneStateListener: PhoneStateListener
  4. override fun onCreate() {
  5. super.onCreate()
  6. telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
  7. phoneStateListener = object : PhoneStateListener() {
  8. override fun onCallStateChanged(state: Int, phoneNumber: String?) {
  9. when (state) {
  10. TelephonyManager.CALL_STATE_RINGING -> {
  11. // 处理来电逻辑
  12. handleIncomingCall(phoneNumber)
  13. }
  14. TelephonyManager.CALL_STATE_OFFHOOK -> {
  15. // 通话接通处理
  16. }
  17. TelephonyManager.CALL_STATE_IDLE -> {
  18. // 通话结束处理
  19. }
  20. }
  21. }
  22. }
  23. // 注册监听(需动态权限)
  24. if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) ==
  25. PackageManager.PERMISSION_GRANTED) {
  26. telephonyManager.listen(phoneStateListener,
  27. PhoneStateListener.LISTEN_CALL_STATE)
  28. }
  29. }
  30. // 其他必要方法实现...
  31. }

去电监听实现

  1. class OutgoingCallReceiver : BroadcastReceiver() {
  2. override fun onReceive(context: Context, intent: Intent) {
  3. if (intent.action == Intent.ACTION_NEW_OUTGOING_CALL) {
  4. val phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER)
  5. // 处理去电逻辑
  6. context.startService(Intent(context, PhoneMonitorService::class.java))
  7. }
  8. }
  9. }

3. 服务持久化策略

前台服务方案

  1. // 创建通知渠道
  2. private fun createNotificationChannel() {
  3. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  4. val channel = NotificationChannel(
  5. "phone_monitor",
  6. "Phone Monitor",
  7. NotificationManager.IMPORTANCE_DEFAULT
  8. ).apply {
  9. description = "Continuous phone state monitoring"
  10. }
  11. val manager = getSystemService(NotificationManager::class.java)
  12. manager.createNotificationChannel(channel)
  13. }
  14. }
  15. // 启动前台服务
  16. private fun startForegroundService() {
  17. val notification = NotificationCompat.Builder(this, "phone_monitor")
  18. .setContentTitle("Phone Monitor")
  19. .setContentText("Monitoring phone states...")
  20. .setSmallIcon(R.drawable.ic_phone)
  21. .build()
  22. startForeground(NOTIFICATION_ID, notification)
  23. }

系统绑定策略

  1. // 在AndroidManifest.xml中声明
  2. <service
  3. android:name=".PhoneMonitorService"
  4. android:enabled="true"
  5. android:exported="false"
  6. android:stopWithTask="false" />

三、进阶优化方案

1. 电池优化白名单

  1. private fun requestIgnoreBatteryOptimizations() {
  2. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  3. val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply {
  4. data = Uri.parse("package:${packageName}")
  5. }
  6. startActivity(intent)
  7. }
  8. }

2. 多进程架构设计

  1. <!-- AndroidManifest.xml -->
  2. <service
  3. android:name=".PhoneMonitorService"
  4. android:process=":monitor_process" />

3. 异常恢复机制

  1. class ServiceRestartReceiver : BroadcastReceiver() {
  2. override fun onReceive(context: Context, intent: Intent) {
  3. if (Intent.ACTION_BOOT_COMPLETED == intent.action ||
  4. "android.intent.action.QUICKBOOT_POWERON" == intent.action) {
  5. context.startForegroundService(
  6. Intent(context, PhoneMonitorService::class.java)
  7. )
  8. }
  9. }
  10. }

四、合规性注意事项

  1. 隐私政策声明:必须明确告知用户电话监听功能及数据用途
  2. 最小化数据收集:仅收集通话状态、号码等必要信息
  3. 用户控制机制:提供关闭监听功能的入口
  4. 数据加密存储:通话记录等敏感信息需加密处理

五、完整实现示例

  1. class PhoneMonitorService : Service() {
  2. companion object {
  3. const val NOTIFICATION_ID = 1001
  4. const val ACTION_STOP_SERVICE = "STOP_SERVICE"
  5. }
  6. private lateinit var telephonyManager: TelephonyManager
  7. private lateinit var notificationManager: NotificationManager
  8. override fun onCreate() {
  9. super.onCreate()
  10. createNotificationChannel()
  11. telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
  12. notificationManager = getSystemService(NotificationManager::class.java)
  13. registerPhoneStateListener()
  14. startForegroundService()
  15. }
  16. private fun registerPhoneStateListener() {
  17. val listener = object : PhoneStateListener() {
  18. override fun onCallStateChanged(state: Int, phoneNumber: String?) {
  19. // 实现状态处理逻辑
  20. when (state) {
  21. TelephonyManager.CALL_STATE_RINGING -> {
  22. // 来电处理
  23. val customerInfo = fetchCustomerInfo(phoneNumber)
  24. showIncomingNotification(customerInfo)
  25. }
  26. // 其他状态处理...
  27. }
  28. }
  29. }
  30. if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) ==
  31. PackageManager.PERMISSION_GRANTED) {
  32. telephonyManager.listen(listener,
  33. PhoneStateListener.LISTEN_CALL_STATE or
  34. PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR)
  35. }
  36. }
  37. private fun showIncomingNotification(customerInfo: CustomerInfo?) {
  38. val notification = NotificationCompat.Builder(this, "phone_monitor")
  39. .setContentTitle("Incoming Call")
  40. .setContentText("${customerInfo?.name} (${customerInfo?.phone})")
  41. .setSmallIcon(R.drawable.ic_phone)
  42. .setPriority(NotificationCompat.PRIORITY_HIGH)
  43. .build()
  44. notificationManager.notify(NOTIFICATION_ID, notification)
  45. }
  46. // 其他必要方法实现...
  47. }

六、部署与测试要点

  1. 真机测试:模拟器无法完整模拟电话状态变化
  2. 多版本兼容:重点测试Android 8-13的权限差异
  3. 压力测试:验证高频来电场景下的服务稳定性
  4. 电量测试:使用Battery Historian分析功耗

通过上述技术方案,开发者可以构建稳定可靠的电话监听服务,既满足企业客服系统的业务需求,又符合Android平台的权限管理规范。实际开发中需根据具体业务场景调整实现细节,并持续关注Android系统的权限策略更新。