流程
获取蓝牙操作对象-BluetoothAdapter
开启蓝牙
通过intent,需要用户同意
mBluetoothAdapter.enable() 不用用户同意
查看自己配对信息 bondedDevices
开启可检测性-intent
搜索设备-广播监听、startDiscovery()
统一UUID
成为客户端(写出信息)- BluetoothSocket
成为服务端(读出信息)- BluetoothServerSocket
基础配置
获取蓝牙操作对象
private val mBluetoothAdapter by lazy { BluetoothAdapter.getDefaultAdapter() }123
开启蓝牙
需要用户同意
if (!mBluetoothAdapter.isEnabled) { startActivityForResult(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), START_BLUE) } else { toast("蓝牙已经开启了")} override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == START_BLUE && resultCode == Activity.RESULT_OK) { toast("蓝牙开启成功") } }1234567891011121314
不需要用户同意
if (!mBluetoothAdapter.isEnabled) { mBluetoothAdapter.enable() } else { mBluetoothAdapter.disable() }12345
查看自己配对信息
val bondedDevices = mBluetoothAdapter.bondedDevices if (bondedDevices.isEmpty()) { toast("当前设备没有配对成功过") } else { val names = bondedDevices.map { it.name + " " + it.address } alert { items(items = names) { dialogInterface: DialogInterface, i: Int -> dialogInterface.dismiss() } }.show() }12345678910111213
扫描设配(通过广播监听)
private val mReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val action = intent.action // When discovery finds a device if (BluetoothDevice.ACTION_FOUND == action) { // Get the BluetoothDevice object from the Intent val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE) // Add the name and address to an array adapter to show in a ListView mListAdapter.add(device.name + "-" + device.address) } } } val filter = IntentFilter(BluetoothDevice.ACTION_FOUND) registerReceiver(mReceiver, filter) //开启该方法 if (mBluetoothAdapter.isDiscovering) { mBluetoothAdapter.cancelDiscovery() } mBluetoothAdapter.startDiscovery()12345678910111213141516171819202122
客户端
成为客户端BluetoothSocket
不需要代码,默认就是客户端1
连接连接端(根据服务端DeviceAddress)
ConnectThread(mBluetoothAdapter.getRemoteDevice(address)).start()private inner class ConnectThread(val mmDevice: BluetoothDevice) : Thread() { private val mmSocket: BluetoothSocket? init { var tmp: BluetoothSocket? = null try { // MY_UUID is the app's UUID string, also used by the server code tmp = mmDevice.createRfcommSocketToServiceRecord(UUID.fromString("2987f694-71d4-4a08-885a-5d07bd3ca0c4")) } catch (e: IOException) { } mmSocket = tmp } override fun run() { // Cancel discovery because it will slow down the connection mBluetoothAdapter.cancelDiscovery() try { // Connect the device through the socket. This will block // until it succeeds or throws an exception mmSocket?.connect() } catch (connectException: IOException) { // Unable to connect; close the socket and get out try { mmSocket?.close() } catch (closeException: IOException) { } return } // 开始写入数据 manageWriteSocket(mmSocket) } /** Will cancel an in-progress connection, and close the socket */ fun cancel() { try { mmSocket!!.close() } catch (e: IOException) { } } }12345678910111213141516171819202122232425262728293031323334353637383940414243444546
成功后写入数据(可以先把String转成byte[])
private fun manageWriteSocket(mmSocket: BluetoothSocket?) { WriteThread(mmSocket).start() }private inner class WriteThread(private val mmSocket: BluetoothSocket?) : Thread() { private val mmInStream: InputStream? private val mmOutStream: OutputStream? init { var tmpIn: InputStream? = null var tmpOut: OutputStream? = null // Get the input and output streams, using temp objects because // member streams are final try { tmpIn = mmSocket?.inputStream tmpOut = mmSocket?.outputStream } catch (e: IOException) { } mmInStream = tmpIn mmOutStream = tmpOut } override fun run() {// val buffer = ByteArray(1024) // buffer store for the stream val buffer = byteArrayOf() // buffer store for the stream write("用户名|132000000|") } /* Call this from the main activity to send data to the remote device */ fun write(bytes: String) { try { Log.e("shen", "发送:${bytes.toByteArray()}") mmOutStream?.write(bytes.toByteArray()) } catch (e: IOException) { Log.e("shen", "1231") } } /* Call this from the main activity to shutdown the connection */ fun cancel() { try { mmSocket?.close() } catch (e: IOException) { } } }12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
服务端
开启扫描设配可检测性
val discoverableIntent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE) discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300) startActivity(discoverableIntent)123
成为服务端
private inner class AcceptThread : Thread() { private val mmServerSocket: BluetoothServerSocket? init { // Use a temporary object that is later assigned to mmServerSocket, // because mmServerSocket is final var tmp: BluetoothServerSocket? = null try { // MY_UUID is the app's UUID string, also used by the client code tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("test", UUID.fromString("2987f694-71d4-4a08-885a-5d07bd3ca0c4")) } catch (e: IOException) { } mmServerSocket = tmp } override fun run() { var socket: BluetoothSocket? = null Log.e("shen", "startReadThread") // Keep listening until exception occurs or a socket is returned //死循环进行数据接收 while (true) { try { socket = mmServerSocket?.accept() } catch (e: IOException) { break } // If a connection was accepted if (socket != null) { // Do work to manage the connection (in a separate thread) manageReadSocket(socket) mmServerSocket?.close() break } } } /** Will cancel the listening socket, and cause the thread to finish */ fun cancel() { try { mmServerSocket!!.close() } catch (e: IOException) { } } }1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
读取数据(通过String(byteArrayOf)方式把byte[]转成String)
private fun manageReadSocket(socket: BluetoothSocket) { ReadThread(socket).start() }private inner class ReadThread(private val mmSocket: BluetoothSocket) : Thread() { private val mmInStream: InputStream? // private val mmOutStream: OutputStream? init { var tmpIn: InputStream? = null // Get the input and output streams, using temp objects because // member streams are final try { tmpIn = mmSocket.inputStream } catch (e: IOException) { } mmInStream = tmpIn// mmOutStream = tmpOut } override fun run() { val byteArrayOf = ByteArray(1024) var bytes: Int = 0 // bytes returned from read() Log.e("shen", "test") // Keep listening to the InputStream until an exception occurs while (true) { try { bytes = mmInStream?.read(byteArrayOf) ?: 0 val toString = byteArrayOf.toString() val string = String(byteArrayOf) //可以成功转换 Log.e("shen", "bytes===${byteArrayOf}") Log.e("shen", "bytes===${toString}") Log.e("shen", "bytes===${string}") break } catch (e: Exception) {// break } } } /* Call this from the main activity to shutdown the connection */ fun cancel() { try { mmSocket.close() } catch (e: IOException) { } } }1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
注意点
UUID:客户端和服务端必须保持一致才能连接成功
String转换:使用String(byteArrayOf)方式
数据读取一次后就需要重启一次蓝牙,这样还能重新发送数据