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

安卓App实现配对蓝牙设备来电同步显示方案及开源项目咨询

实现跨蓝牙设备来电信息同步方案

一、核心实现步骤

1. App A 端:蓝牙发送来电信息

你已完成来电状态监听,现在需要实现sendMessageToAppB(phoneNumber)方法,通过蓝牙配对通道发送数据:

private fun sendMessageToAppB(phoneNumber: String?) {
    val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
    if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled) {
        Log.e("MainActivity", "蓝牙未启用或不可用")
        return
    }

    // 从已配对设备中定位手机B(可通过设备名称或MAC地址筛选)
    val pairedDevices = bluetoothAdapter.bondedDevices
    val targetDevice = pairedDevices.firstOrNull { it.name == "手机B的蓝牙名称" }
        ?: pairedDevices.firstOrNull { it.address == "手机B的MAC地址" }
    if (targetDevice == null) {
        Log.e("MainActivity", "未找到配对的目标设备")
        return
    }

    // 建立RFCOMM蓝牙套接字连接(使用标准串口服务UUID)
    val uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
    try {
        val socket = targetDevice.createRfcommSocketToServiceRecord(uuid)
        socket.connect()

        // 发送格式化的来电数据
        val message = "INCOMING_CALL:$phoneNumber"
        val outputStream = socket.outputStream
        outputStream.write(message.toByteArray())
        outputStream.flush()

        socket.close()
    } catch (e: IOException) {
        Log.e("MainActivity", "蓝牙发送失败: ${e.message}")
    }
}

2. App B 端:蓝牙监听与来电展示

App B需要后台监听蓝牙连接,接收数据后通过通知展示来电信息:

class BluetoothCallReceiverService : Service() {
    private var serverSocket: BluetoothServerSocket? = null
    private var listenThread: Thread? = null
    private val uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        startBluetoothListening()
        return START_STICKY
    }

    private fun startBluetoothListening() {
        val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
        if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled) return

        listenThread = Thread {
            try {
                serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord("AppB_Call_Service", uuid)
                while (!Thread.currentThread().isInterrupted) {
                    val socket = serverSocket?.accept()
                    socket?.let {
                        val inputStream = it.inputStream
                        val buffer = ByteArray(1024)
                        val bytesRead = inputStream.read(buffer)
                        val message = String(buffer, 0, bytesRead)

                        if (message.startsWith("INCOMING_CALL:")) {
                            val phoneNumber = message.substringAfter("INCOMING_CALL:")
                            showIncomingCallNotification(phoneNumber)
                        }
                        it.close()
                    }
                }
            } catch (e: IOException) {
                Log.e("BluetoothService", "监听异常: ${e.message}")
            }
        }
        listenThread?.start()
    }

    private fun showIncomingCallNotification(phoneNumber: String) {
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        val channelId = "APPB_INCOMING_CALL"

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(channelId, "跨设备来电通知", NotificationManager.IMPORTANCE_HIGH)
            notificationManager.createNotificationChannel(channel)
        }

        val intent = Intent(this, MainActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        }
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)

        val notification = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_call_white)
            .setContentTitle("手机A来电")
            .setContentText("号码:$phoneNumber")
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
            .build()

        notificationManager.notify(1, notification)
    }

    override fun onDestroy() {
        super.onDestroy()
        listenThread?.interrupt()
        try {
            serverSocket?.close()
        } catch (e: IOException) {
            Log.e("BluetoothService", "关闭服务异常: ${e.message}")
        }
    }

    override fun onBind(intent: Intent?): IBinder? = null
}

3. 权限配置(两个App都需要)

在AndroidManifest.xml中添加蓝牙相关权限:

<!-- 基础蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Android 12+ 新增权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!-- 后台运行权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<!-- 声明蓝牙硬件依赖 -->
<uses-feature android:name="android.hardware.bluetooth" android:required="true" />

注意:Android 6.0+需动态申请BLUETOOTH_CONNECT、BLUETOOTH_SCAN权限;App B的服务需启动为前台服务,避免被系统后台清理。

二、可参考的开源项目

  • BluetoothChat:Android官方示例项目,完整演示蓝牙点对点通信的核心逻辑(RFCOMM套接字连接、数据收发),可直接参考其连接流程。
  • SimpleBluetoothTerminal:轻量级蓝牙串口通信项目,代码简洁易懂,适合快速学习蓝牙数据传输的基础实现。
  • PhoneCallForwarder:开源来电转发类项目,虽非蓝牙传输,但可参考其来电状态监听、跨设备消息推送的设计思路。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:04:59