流程
- 获取蓝牙操作对象-BluetoothAdapter
- 开启蓝牙
- 通过intent,需要用户同意
- mBluetoothAdapter.enable() 不用用户同意
- 查看自己配对信息 bondedDevices
- 开启可检测性-intent
- 搜索设备-广播监听、startDiscovery()
- 统一UUID
- 成为客户端(写出信息)- BluetoothSocket
- 成为服务端(读出信息)- BluetoothServerSocket
基础配置
- 获取蓝牙操作对象
private val mBluetoothAdapter by lazy {
BluetoothAdapter.getDefaultAdapter()
}
- 开启蓝牙
需要用户同意
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("蓝牙开启成功")
}
}
不需要用户同意
if (!mBluetoothAdapter.isEnabled) {
mBluetoothAdapter.enable()
} else {
mBluetoothAdapter.disable()
}
- 查看自己配对信息
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()
}
- 扫描设配(通过广播监听)
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()
客户端
- 成为客户端BluetoothSocket
不需要代码,默认就是客户端
- 连接连接端(根据服务端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) {
}
}
}
- 成功后写入数据(可以先把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) {
}
}
}
服务端
- 开启扫描设配可检测性
val discoverableIntent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE)
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
startActivity(discoverableIntent)
- 成为服务端
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) {
}
}
}
- 读取数据(通过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) {
}
}
}
注意点
- UUID:客户端和服务端必须保持一致才能连接成功
- String转换:使用String(byteArrayOf)方式
- 数据读取一次后就需要重启一次蓝牙,这样还能重新发送数据