最近做一个项目,看了官方API,学习了关于蓝牙的一些知识,分享一下,如果有错,欢迎指正。
一、权限设置
<uses-permission android:name="android.permission.BLUETOOTH" />
二、创建蓝牙
1、获得本地适配器
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { // 设备不支持蓝牙功能 }2、a使能蓝牙
if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); }
REQUEST_ENABLE_BT,大于0的整型数,系统通过传递该参数回到onActivityResult()实现请求码参数,请求码有:RESULT_OK(成功使能蓝牙)和RESULT_CANCELED(使能蓝牙失败或者发生错误).
监听广播意图 ACTION_STATE_CHANGED ,包含两个属性EXTRA_STATE和EXTRA_PREVIOUS_STATE,可能取值有STATE_TURNING_ON、STATE_ON、STATE_TURNING_OFFSTATE_OFF,监听广播可以有效地检测蓝牙状态变化当运行APP时。
b定时使能蓝牙
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);//定时区间为[0,3600],不在区间内默认为1200s startActivity(discoverableIntent);类似的,ACTION_SCAN_MODE_CHANGED广播意图包含两个属性:EXTRA_SCAN_MODE和EXTRA_PREVIOUS_SCAN_MODE。可能取值有:发现模式SCAN_MODE_CONNECTABLE_DISCOVERABLE 、非发现模式可连接SCAN_MODE_CONNECTABLE 、非发现模式不可连接SCAN_MODE_NONE。
3、发现设备 a、查找配对设备 调用getBondedDevices()方法查找配对设备Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); // 如果有配对设备 if (pairedDevices.size() > 0) { // 遍历撇对设备 for (BluetoothDevice device : pairedDevices) { // 在ListView显示存到数组适配器中的名字、地址 mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } }b、搜索设备 调用startDiscovery()方法搜索设备 为了ACTION_FOUND意图,注册广播接收器,以便于接受每个发现设备的信息,在每个设备,系统会广播ACTION_FOUND意图。ACTION_FOUND包含EXTRA_DEVICE、EXTRA_CLASS两个属性值。(包含了BluetoothDecice和BluetoothClass包)// 为ACTION_FOUND注册广播接收机 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // 当搜索到一个设备 if (BluetoothDevice.ACTION_FOUND.equals(action)) { // 从意图中获得BluetoothDevice对象 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } }; // 注册广播接收机 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // 记得在onDestroy取消注册注意:当找到可连接设备,调用cancelDiscovery()方法在尝试连接之前停止搜索设备。连接时不要执行搜索。
4、连接设备 a作为服务器连接 建立server socket接受一个连接: 调用listenUsingRfcommWithServiceRecord(String, UUID)方法获得BluetoothServerSocket(UUID:Universally Unique Identifier通用唯一识别码) b调用accept()方法监听连接请求 c调用close()方法 注意:accept()是阻塞调用,不能用在主活动的UI线程。private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; public AcceptThread() { // Use a temporary object that is later assigned to mmServerSocket, // because mmServerSocket is final BluetoothServerSocket tmp = null; try { // MY_UUID is the app's UUID string, also used by the client code tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } catch (IOException e) { } mmServerSocket = tmp; } public void run() { BluetoothSocket socket = null; // Keep listening until exception occurs or a socket is returned while (true) { try { socket = mmServerSocket.accept(); } catch (IOException e) { break; } // If a connection was accepted if (socket != null) { // Do work to manage the connection (in a separate thread) manageConnectedSocket(socket); mmServerSocket.close(); break; } } } /** Will cancel the listening socket, and cause the thread to finish */ public void cancel() { try { mmServerSocket.close(); } catch (IOException e) { } } }上述例子中,只需要传入一个连接,一旦连接,就需要Bluetooth分开线程,关闭BluetoothServerSocket,打断循环。 注意:当accept()方法返回BluetoothServerSocket时已连接,所以你不需要调用connect()方法。当完成对连接的监听后,总是关闭BluetoothServerSocket,如上述例子。你也可以提供一个公用方法在新线程中以关闭私有的BluetoothSocket在需要监听Sercer socket的事件中。
b作为客户端连接 1、调用createRfcommSocketToServiceRecord(UUID)获取BluetoothSocket对象,完成初始化。 2、调用connect()初始化连接(阻塞,需分开线程)下面是一个初始化蓝牙连接的线程rivate class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; public ConnectThread(BluetoothDevice device) { // Use a temporary object that is later assigned to mmSocket, // because mmSocket is final BluetoothSocket tmp = null; mmDevice = device; // Get a BluetoothSocket to connect with the given BluetoothDevice try { // MY_UUID is the app's UUID string, also used by the server code tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { } mmSocket = tmp; } public void 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 (IOException connectException) { // Unable to connect; close the socket and get out try { mmSocket.close(); } catch (IOException closeException) { } return; } // Do work to manage the connection (in a separate thread) manageConnectedSocket(mmSocket); } /** Will cancel an in-progress connection, and close the socket */ public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }注意:在连接之前调用cancelDiscovery()方法c管理连接 ——传输任意数据private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket) { mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Get the input and output streams, using temp objects because // member streams are final try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { byte[] buffer = new byte[1024]; // buffer store for the stream int bytes; // bytes returned from read() // Keep listening to the InputStream until an exception occurs while (true) { try { // Read from the InputStream bytes = mmInStream.read(buffer); // Send the obtained bytes to the UI activity mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer) .sendToTarget(); } catch (IOException e) { break; } } } /* Call this from the main activity to send data to the remote device */ public void write(byte[] bytes) { try { mmOutStream.write(bytes); } catch (IOException e) { } } /* Call this from the main activity to shutdown the connection */ public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }