一.蓝牙API
与蓝牙开发主要的相关类是以下四个
BluetoothAdapter
字面上则理解为蓝牙适配器,打开蓝牙,关闭蓝牙,搜索设备,获取蓝牙Socket连接都是通过这个类来实现的。对应的方法就有
enable():用来打开蓝牙,一般在5.0后的话则会出现弹框提示是否开启蓝牙,其他则没有提示,也可以调用来进行弹窗打开
Intent intent =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivity(intent );
disable():关闭蓝牙
getDefaultAdapter():获取蓝牙适配器BluetoothAdapter,只有这个方法来获取
getAddress():获取本地蓝牙的MAC地址,这个则是每一个蓝牙设备的唯一
getName():获取本地蓝牙的名称
getRemoteDevice(String address):获取蓝牙地址获取到远程的设备
startDiscovery():开启蓝牙设备搜索
cancelDiscovery():关闭扫描
listenUsingRfcommWithServiceRecord(serverSocketName,UUID):获取BluetoothServerSocket
BluetoothDevice
代表一个蓝牙设备
createRfcommSocketToServiceRecord(UUIDuuid):根据UUID创建并返回一个BluetoothSocket
getName():获取蓝牙设备名称
getAddress():获取蓝牙的MAC地址
BluetoothServerSocket:类似于ServerSocket,方法都差不多,可以说蓝牙之间的通讯跟Socket相似。这个相当于服务器Socket
accept():这个方法会阻塞,直到连接建立,用来监听连接
close():关闭socket连接
BluetoothSocket:相当于客户端Socket
connect():用来向服务器BluetoothServerSocket发起连接
getInputStream():获取输入流
getOutputStream():获取输出流
close():关闭连接
getRemoteDevice():获取这个Socket连接的远程设备
二.搜索蓝牙设备
知道对应API后就可以进行对应的蓝牙开发,这里以获取蓝牙设备为例子
1.获取本地蓝牙适配器
BluetoothAdapter
mAdapter= BluetoothAdapter.getDefaultAdapter();
2.打开蓝牙
if(!mAdapter.isEnabled()){//弹出对话框提示用户是后打开Intent enabler =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enabler, REQUEST_ENABLE);//不做提示,强行打开// mAdapter.enable();
}
3.搜索设备
mAdapter.startDiscovery();//开启搜索
搜索设备的回调则需要通过注册广播的形式来获取
//发现设备的ActionIntentFilter filter =newIntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter);//设备搜索完毕的actionfilter =newIntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); registerReceiver(mReceiver, filter);
定义广播
BroadcastReceiver mReceiver =newBroadcastReceiver() {publicvoidonReceive(Context context, Intent intent){ String action = intent.getAction();//当扫描到设备的时候if(BluetoothDevice.ACTION_FOUND.equals(action)) {// 获取设备对象BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);//提取强度信息intrssi = intent.getExtras().getShort(BluetoothDevice.EXTRA_RSSI); Log.e(TAG, device.getName() +"\n"+ device.getAddress() +"\n强度:"+ rssi); }//搜索完成elseif(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { Log.e(TAG,"onReceive: 搜索完成"); } } };
之后就可以进行个人的一些操作
三.蓝牙聊天的实现
要实现蓝牙聊天则涉及到蓝牙之间的传输通信,前面也说到了,这里肯定就是用到BluetoothServerSocket以及BluetoothSocket。
蓝牙传输通信相当于服务器端与客户端之间的通信,只不过不同是这里每一个蓝牙设备本身自己既充当服务器端也充当客户端,大致的关系就是
蓝牙连接
注意,这些连接都是阻塞式的,都要放在线程里去执行。
1.对于BluetoothServerSocket,建立一个AcceptThread,来监听是否有设备发起连接
//连接等待线程classAcceptThreadextendsThread{privatefinalBluetoothServerSocket serverSocket;publicAcceptThread(){ BluetoothServerSocket tmp =null;try{//获取实例tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, MY_UUID_SECURE); }catch(IOException e) { e.printStackTrace(); } serverSocket = tmp; }@Overridepublicvoidrun(){super.run();//监听是否有端口连接BluetoothSocket socket =null;while(mState != STATE_TRANSFER) {try{ Log.e(TAG,"run: AcceptThread 阻塞调用,等待连接"); socket = serverSocket.accept(); }catch(IOException e) { e.printStackTrace(); Log.e(TAG,"run: ActivityThread fail");break; }//获取到连接Socket后则开始通信if(socket !=null){synchronized(BluetoothChatService.this) {switch(mState) {caseSTATE_LISTEN:caseSTATE_CONNECTING://传输数据,服务器端调用Log.e(TAG,"run: 服务器AcceptThread传输"); sendMessageToUi(MainActivity.BLUE_TOOTH_DIALOG ,"正在与"+ socket.getRemoteDevice().getName() +"连接");//开始数据传输dataTransfer(socket, socket.getRemoteDevice());break;caseSTATE_NONE:caseSTATE_TRANSFER:// 没有准备好或者终止连接try{ socket.close(); }catch(IOException e) { Log.e(TAG,"Could not close unwanted socket"+ e); }break; } } } } }publicvoidcancel(){ Log.e(TAG,"close: activity Thread");try{if(serverSocket !=null) serverSocket.close(); }catch(IOException e) { e.printStackTrace(); Log.e(TAG,"close: activity Thread fail"); } } }
可以看到,当BluetoothServerSocket监听到有设备连接的时候,就会调用dataTransfer开启一个数据传输。
2.同样如何发起连接BluetoothSocket呢
需要一个ConnectThread来发起
classConnectThreadextendsThread{privatefinalBluetoothSocket socket;privatefinalBluetoothDevice device;publicConnectThread(BluetoothDevice device){this.device = device; BluetoothSocket mSocket =null;try{//获取SocketmSocket = device.createRfcommSocketToServiceRecord( MY_UUID_SECURE); }catch(IOException e) { e.printStackTrace(); Log.e(TAG,"ConnectThread: fail"); sendMessageToUi(MainActivity.BLUE_TOOTH_TOAST ,"连接失败,请重新连接"); } socket = mSocket; }@Overridepublicvoidrun(){super.run();//建立后取消扫描bluetoothAdapter.cancelDiscovery();try{//开启连接socket.connect(); }catch(IOException e) { e.printStackTrace();try{ socket.close(); }catch(IOException e1) { e1.printStackTrace(); Log.e(TAG,"run: unable to close"); }//TODO 连接失败显示sendMessageToUi(MainActivity.BLUE_TOOTH_TOAST ,"连接失败,请重新连接"); BluetoothChatService.this.start(); }// 重置synchronized(BluetoothChatService.this) { mConnectThread =null; }//连接建立,开始传输dataTransfer(socket, device); }publicvoidcancel(){try{if(socket !=null) socket.close(); }catch(IOException e) { e.printStackTrace(); } } }
之后建立连接之后就会调用dataTransfer来进行数据传输,同样也需要一个线程来维护数据传输
classTransferThreadextendsThread{privatefinalBluetoothSocket socket;privatefinalOutputStream out;privatefinalInputStream in;publicTransferThread(BluetoothSocket mBluetoothSocket){ socket = mBluetoothSocket; OutputStream mOutputStream =null; InputStream mInputStream =null;try{if(socket !=null){//获取连接的输入输出流mOutputStream = socket.getOutputStream(); mInputStream = socket.getInputStream(); } }catch(IOException e) { e.printStackTrace(); } out = mOutputStream; in = mInputStream; isTransferError =false; }@Overridepublicvoidrun(){super.run();//读取数据byte[] buffer =newbyte[1024];intbytes;while(true){try{ bytes = in.read(buffer);//TODO 分发到主线程显示uiHandler.obtainMessage(MainActivity.BLUE_TOOTH_READ, bytes, -1, buffer) .sendToTarget(); Log.e(TAG,"run: read "+newString(buffer ,0, bytes) ); }catch(IOException e) { e.printStackTrace(); Log.e(TAG,"run: Transform error"+ e.toString()); BluetoothChatService.this.start();//TODO 连接丢失显示并重新开始连接sendMessageToUi(MainActivity.BLUE_TOOTH_TOAST ,"设备连接失败/传输关闭"); isTransferError =true;break; } } }/** * 写入数据传输 *@parambuffer */publicvoidwrite(byte[] buffer){try{ out.write(buffer);//TODO 到到UI显示uiHandler.obtainMessage(MainActivity.BLUE_TOOTH_WRAITE , -1, -1, buffer) .sendToTarget(); }catch(IOException e) { Log.e(TAG,"Exception during write "+ e); } }publicvoidcancel(){try{if(socket !=null) socket.close(); }catch(IOException e) { Log.e(TAG,"close() of connect socket failed"+ e); } } }
蓝牙聊天则是基于上面三个线程来进行实现,同样,对于蓝牙文件间的传输也是同个道理,通过输入输出流来进行处理。之后的操作就比较容易处理了
四.简单实现
https://github.com/ZengZeHong/BlueToothChat