Android实现蓝牙的搜索,配对(不需要输入PIN,自动匹配),连接,通信
android实现蓝牙的搜索,配对(不需要输入pin,自动匹配),连接,通信
一、蓝牙设置权限
需要在androidmanifest.xml配置获得蓝牙权限。
按照sdk说明需要下面两个权限就可以进行蓝牙的开发。
在android6.0之后为了更好的保护用户的数据安全,所有需要访问硬件唯一标识符的地方都需要申请位置权限,也就是需要申请以下权限
二、蓝牙搜索
1.首先需要获得蓝牙适配器。
mbluetoothadapter = bluetoothadapter.getdefaultadapter();
2.判断蓝牙是否打开,然后请求打开蓝牙
private void openbluetooth() { if (!mbluetoothadapter.isenabled()) { //通过这个方法来请求打开我们的蓝牙设备 intent intent = new intent(bluetoothadapter.action_request_enable); startactivityforresult(intent,bluetooth_response); } }
通过这个方法可以判断是否允许打开蓝牙,然后进行下面相应的操作
case bluetooth_response: if(resultcode == result_ok){ //获得蓝牙权限成功 //需要再写一次,oncreate里的下面的方法无法执行 duringdialog("正在连接蓝牙!"); //搜索蓝牙 searchbluetooth(); }else if(resultcode == result_canceled){ //获得蓝牙权限失败 toast(controlparkingactivity.this,"蓝牙权限获取失败,请打开蓝牙!"); } break;
3.搜索蓝牙
如果已经打开蓝牙上面的搜索蓝牙不会执行,所以还需在oncreate方法中写搜索方法
//请求判断蓝牙是否提前打开 //如果没有提前打开则不会执行这句,执行openbluetooth的响应结果 //如果提前打开则执行下面 if(mbluetoothadapter.isenabled()){ duringdialog("正在连接蓝牙!"); searchbluetooth(); }
搜索蓝牙方法如下:
//搜索蓝牙设备 private void searchbluetooth() { //判断蓝牙是否已经绑定 if(isbond()){ log.d(tag,"蓝牙已经绑定"); //已经绑定,直接连接蓝牙 log.d(tag,device.getname() + "1"); }else{ log.d(tag,"搜索蓝牙中"); //搜索蓝牙设备 mbluetoothadapter.startdiscovery(); } }
三、蓝牙配对
蓝牙配对是通过广播接收器,搜索附近蓝牙设备,通过判断设备的address和name来判断是否为目标设备。之后利用clsutils工具类实现自动匹配蓝牙设备的功能。
1.动态注册广播接收器
mbluetoothreceiver = new bluetoothreceiver(); // 动态注册注册广播接收器。接收蓝牙发现讯息 intentfilter btfilter = new intentfilter(); btfilter.setpriority(1000); btfilter.addaction(bluetoothdevice.action_found); btfilter.addaction(bluetoothdevice.action_pairing_request); this.registerreceiver(mbluetoothreceiver,btfilter); //设置广播信息接口监听器 mbluetoothreceiver.setreceivermessagelistener(this);
setpriority(1000):设置优先级,如果优先级比较低可能仍然会弹出输入pin的对话框
bluetoothdevice.action_found:发现设备时的action
bluetoothdevice.action_pairing_request:当调用createbond()后就会发起bluetoothdevice.action_pairing_request的广播
2.判断蓝牙设备是否为目标设备,并且创建绑定
//获得action string action=intent.getaction(); //获取设备 device = intent.getparcelableextra(bluetoothdevice.extra_device); //获取搜索到的设备的名称和地址 string name = device.getname(); string address = device.getaddress(); if(action.equals(bluetoothdevice.action_found)) { log.d(tag, "发现设备:" + name); if ((name != null && btname.equals(name)) || btaddress.equals(address)) { //判断远程设备是否已经被绑定 if(device.getbondstate() != bluetoothdevice.bond_bonded){ log.d(tag, "发现目标设备,开始配对!"); try { // 调用配对的方法,此方法是异步的,系统会触发bluetoothdevice.action_pairing_request的广播 // 收到此广播后,设置配对的密码 clsutils.createbond(bluetoothdevice.class, device); } catch (exception e) { e.printstacktrace(); } }else{ //远程设备已经被绑定,取消搜索,返回信息 } }
3.利用clsutils和事先获得的pin进行配对
else if(action.equals("android.bluetooth.device.action.pairing_request")){ //createbond后再次得到action,就会等于pairing_request log.d(tag,"action2 = " + action); log.d(tag, "发现设备:" + device.getaddress() + " " + device.getname()); if ((name != null && name.equals(btname)) || address.equals(btaddress)) { log.d(tag, "发现目标设备,开始配对!"); try { //1.确认配对 // clsutils.setpairingconfirmation(device.getclass(), device, true); // //2.终止有序广播 // log.i("order...", "isorderedbroadcast:"+isorderedbroadcast()+",isinitialstickybroadcast:"+isinitialstickybroadcast()); abortbroadcast();//如果没有将广播终止,则会出现一个一闪而过的配对框。 //3.调用setpin方法进行配对... boolean ret = clsutils.setpin(device.getclass(), device, pin); mreceivermessage.setmessage(device); } catch (exception e) { // todo auto-generated catch block e.printstacktrace(); log.d(tag,"action2 = 配对失败!"); } }else { //提示不是目标设备 log.d(tag,"action2 = 不是目标设备!"); } }
4.将绑定状态返回给activity,通知其绑定成功,可以进行蓝牙连接
广播中无法直接调用蓝牙连接的方法,在试了很多种方法后,最后通过接口实现了广播向activity传值的功能。
在bluetoothreceiver中写接口和接口监听器
public interface bluetoothreceivermessage{ public void setmessage(bluetoothdevice device); } public void setreceivermessagelistener(bluetoothreceivermessage bluetoothreceivermessage){ this.mreceivermessage = bluetoothreceivermessage; }
绑定成功后,向activity发送消息(绑定设备)
mreceivermessage.setmessage(device);
首先activity中要设置广播信息接口监听器
//设置广播信息接口监听器 mbluetoothreceiver.setreceivermessagelistener(this);
在activity中需要实现bluetoothreceivermessage接口,重写对应的方法,进行蓝牙连接操作。
public class controlparkingactivity extends appcompatactivity implements bluetoothreceiver.bluetoothreceivermessage @override public void setmessage(bluetoothdevice device) { if(device != null){ log.d(tag,"蓝牙绑定成功,开始连接!"); this.device = device; mchatservice.connect(device,true); } }
四、蓝牙连接和通信
利用google官方的bluetoothservice进行蓝牙的连接和通信。
1.初始化bluetoothservice
mchatservice = new bluetoothchatservice(this, mhandler);
2.通过handle获取bluetoothservice返回的信息和接收的数据
private final handler mhandler = new handler() { @override public void handlemessage(message msg) { switch (msg.what) { case message_state_change: switch (msg.arg1) { case bluetoothchatservice.state_connected: //蓝牙已连接 break; case bluetoothchatservice.state_connecting: //蓝牙正在连接 break; case bluetoothchatservice.state_listen: case bluetoothchatservice.state_none: //蓝牙未连接 break; } break; case message_write: //发送数据返回的结果 break; case message_read: byte[] readbuf = (byte[]) msg.obj; // construct a string from the valid bytes in the buffer string readmessage = new string(readbuf, 0, msg.arg1); //读取数据 case message_device_name: // 保存已连接的设备名称 mconnecteddevicename = msg.getdata().getstring(device_name); toast.maketext(getapplicationcontext(), "connected to " + mconnecteddevicename, toast.length_short).show(); break; case message_toast: break; } } };
3.向蓝牙设备发送数据
private void sendmessage(string message) { // check that we're actually connected before trying anything if (mchatservice.getstate() != bluetoothchatservice.state_connected) { toast.maketext(this, r.string.not_connected, toast.length_short).show(); return; } // check that there's actually something to send if (message.length() > 0) { // get the message bytes and tell the bluetoothchatservice to write byte[] send = message.getbytes(); mchatservice.write(send); } }
五、结束连接、通信
动态注册广播需要在活动结束时解除注册,如果有需要也可以调用clsutils.removebond解除绑定。
@override protected void ondestroy() { super.ondestroy(); mbluetoothadapter.canceldiscovery(); unregisterreceiver(mbluetoothreceiver); try { log.d(tag,device + " " + device.getbondstate()); clsutils.removebond(device.getclass(), device); } catch (exception e) { log.d(tag,"解除绑定失败!"); e.printstacktrace(); } }
六、另附bluetoothchatservice代码
/* * copyright (c) 2009 the android open source project * * licensed under the apache license, version 2.0 (the "license"); * you may not use this file except in compliance with the license. * you may obtain a copy of the license at * * https://www.apache.org/licenses/license-2.0 * * unless required by applicable law or agreed to in writing, software * distributed under the license is distributed on an "as is" basis, * without warranties or conditions of any kind, either express or implied. * see the license for the specific language governing permissions and * limitations under the license. */ package com.example.sharingparking.utils; import android.bluetooth.bluetoothadapter; import android.bluetooth.bluetoothdevice; import android.bluetooth.bluetoothserversocket; import android.bluetooth.bluetoothsocket; import android.content.context; import android.os.bundle; import android.os.handler; import android.os.message; import android.util.log; import com.example.sharingparking.activity.controlparkingactivity; import java.io.ioexception; import java.io.inputstream; import java.io.outputstream; import java.util.uuid; /** * this class does all the work for setting up and managing bluetooth * connections with other devices. it has a thread that listens for * incoming connections, a thread for connecting with a device, and a * thread for performing data transmissions when connected. */ public class bluetoothchatservice{ // debugging private static final string tag = "bluetoothchatservice"; private static final boolean d = true; // name for the sdp record when creating server socket private static final string name_secure = "bluetoothchatsecure"; private static final string name_insecure = "bluetoothchatinsecure"; // unique uuid for this application private static final uuid my_uuid_secure = uuid.fromstring("00001101-0000-1000-8000-00805f9b34fb"); private static final uuid my_uuid_insecure = uuid.fromstring("00001101-0000-1000-8000-00805f9b34fb"); // member fields private final bluetoothadapter madapter; private final handler mhandler; private acceptthread msecureacceptthread; private acceptthread minsecureacceptthread; private connectthread mconnectthread; private connectedthread mconnectedthread; private int mstate; // constants that indicate the current connection state public static final int state_none = 0; // 蓝牙未连接 public static final int state_listen = 1; // 正在监听来的连接 public static final int state_connecting = 2; // 正在连接 public static final int state_connected = 3; // 已经连接 /** * constructor. prepares a new mainactivity session. * @param context the ui activity context * @param handler a handler to send messages back to the ui activity */ public bluetoothchatservice(context context, handler handler) { madapter = bluetoothadapter.getdefaultadapter(); mstate = state_none; mhandler = handler; } /** * set the current state of the chat connection * @param state an integer defining the current connection state */ private synchronized void setstate(int state) { if (d) log.d(tag, "setstate() " + mstate + " -> " + state); mstate = state; //通过handle返回给主活动连接状态 mhandler.obtainmessage(controlparkingactivity.message_state_change, state, -1).sendtotarget(); } /** * return the current connection state. */ public synchronized int getstate() { return mstate; } /** * start the chat service. specifically start acceptthread to begin a * session in listening (server) mode. called by the activity onresume() */ public synchronized void start() { if (d) log.d(tag, "start"); // cancel any thread attempting to make a connection if (mconnectthread != null) { mconnectthread.cancel(); mconnectthread = null; } // cancel any thread currently running a connection if (mconnectedthread != null) { mconnectedthread.cancel(); mconnectedthread = null; } setstate(state_listen); // start the thread to listen on a bluetoothserversocket if (msecureacceptthread == null) { msecureacceptthread = new acceptthread(true); msecureacceptthread.start(); } if (minsecureacceptthread == null) { minsecureacceptthread = new acceptthread(false); minsecureacceptthread.start(); } } /** * start the connectthread to initiate a connection to a remote device. * @param device the bluetoothdevice to connect * @param secure socket security type - secure (true) , insecure (false) */ public synchronized void connect(bluetoothdevice device, boolean secure) { if (d) log.d(tag, "connect to: " + device); // cancel any thread attempting to make a connection if (mstate == state_connecting) { if (mconnectthread != null) {mconnectthread.cancel(); mconnectthread = null;} } // cancel any thread currently running a connection if (mconnectedthread != null) {mconnectedthread.cancel(); mconnectedthread = null;} // start the thread to connect with the given device mconnectthread = new connectthread(device, secure); mconnectthread.start(); setstate(state_connecting); } /** * start the connectedthread to begin managing a bluetooth connection * @param socket the bluetoothsocket on which the connection was made * @param device the bluetoothdevice that has been connected */ public synchronized void connected(bluetoothsocket socket, bluetoothdevice device, final string sockettype) { if (d) log.d(tag, "connected, socket type:" + sockettype); // cancel the thread that completed the connection if (mconnectthread != null) {mconnectthread.cancel(); mconnectthread = null;} // cancel any thread currently running a connection if (mconnectedthread != null) {mconnectedthread.cancel(); mconnectedthread = null;} // cancel the accept thread because we only want to connect to one device if (msecureacceptthread != null) { msecureacceptthread.cancel(); msecureacceptthread = null; } if (minsecureacceptthread != null) { minsecureacceptthread.cancel(); minsecureacceptthread = null; } // start the thread to manage the connection and perform transmissions mconnectedthread = new connectedthread(socket, sockettype); mconnectedthread.start(); // send the name of the connected device back to the ui activity message msg = mhandler.obtainmessage(controlparkingactivity.message_device_name); bundle bundle = new bundle(); bundle.putstring(controlparkingactivity.device_name, device.getname()); msg.setdata(bundle); mhandler.sendmessage(msg); setstate(state_connected); } /** * stop all threads */ public synchronized void stop() { if (d) log.d(tag, "stop"); if (mconnectthread != null) { mconnectthread.cancel(); mconnectthread = null; } if (mconnectedthread != null) { mconnectedthread.cancel(); mconnectedthread = null; } if (msecureacceptthread != null) { msecureacceptthread.cancel(); msecureacceptthread = null; } if (minsecureacceptthread != null) { minsecureacceptthread.cancel(); minsecureacceptthread = null; } setstate(state_none); } /** * write to the connectedthread in an unsynchronized manner * @param out the bytes to write * @see connectedthread#write(byte[]) */ public void write(byte[] out) { // create temporary object connectedthread r; // synchronize a copy of the connectedthread synchronized (this) { if (mstate != state_connected) return; r = mconnectedthread; } // perform the write unsynchronized r.write(out); } /** * indicate that the connection attempt failed and notify the ui activity. */ private void connectionfailed() { // send a failure message back to the activity message msg = mhandler.obtainmessage(controlparkingactivity.message_toast); bundle bundle = new bundle(); bundle.putstring(controlparkingactivity.toast, "unable to connect device"); msg.setdata(bundle); mhandler.sendmessage(msg); // start the service over to restart listening mode bluetoothchatservice.this.start(); } /** * indicate that the connection was lost and notify the ui activity. */ private void connectionlost() { // send a failure message back to the activity message msg = mhandler.obtainmessage(controlparkingactivity.message_toast); bundle bundle = new bundle(); bundle.putstring(controlparkingactivity.toast, "device connection was lost"); msg.setdata(bundle); mhandler.sendmessage(msg); // start the service over to restart listening mode bluetoothchatservice.this.start(); } /** * this thread runs while listening for incoming connections. it behaves * like a server-side client. it runs until a connection is accepted * (or until cancelled). */ private class acceptthread extends thread { // the local server socket private final bluetoothserversocket mmserversocket; private string msockettype; public acceptthread(boolean secure) { bluetoothserversocket tmp = null; msockettype = secure ? "secure":"insecure"; // create a new listening server socket try { if (secure) { tmp = madapter.listenusingrfcommwithservicerecord(name_secure, my_uuid_secure); } else { tmp = madapter.listenusinginsecurerfcommwithservicerecord( name_insecure, my_uuid_insecure); } } catch (ioexception e) { log.e(tag, "socket type: " + msockettype + "listen() failed", e); } mmserversocket = tmp; } public void run() { if (d) log.d(tag, "socket type: " + msockettype + "begin macceptthread" + this); setname("acceptthread" + msockettype); bluetoothsocket socket = null; // listen to the server socket if we're not connected while (mstate != state_connected) { try { // this is a blocking call and will only return on a // successful connection or an exception socket = mmserversocket.accept(); } catch (ioexception e) { log.e(tag, "socket type: " + msockettype + "accept() failed", e); break; } // if a connection was accepted if (socket != null) { synchronized (bluetoothchatservice.this) { switch (mstate) { case state_listen: case state_connecting: // situation normal. start the connected thread. connected(socket, socket.getremotedevice(), msockettype); break; case state_none: case state_connected: // either not ready or already connected. terminate new socket. try { socket.close(); } catch (ioexception e) { log.e(tag, "could not close unwanted socket", e); } break; } } } } if (d) log.i(tag, "end macceptthread, socket type: " + msockettype); } public void cancel() { if (d) log.d(tag, "socket type" + msockettype + "cancel " + this); try { mmserversocket.close(); } catch (ioexception e) { log.e(tag, "socket type" + msockettype + "close() of server failed", e); } } } /** * this thread runs while attempting to make an outgoing connection * with a device. it runs straight through; the connection either * succeeds or fails. */ private class connectthread extends thread { private final bluetoothsocket mmsocket; private final bluetoothdevice mmdevice; private string msockettype; public connectthread(bluetoothdevice device, boolean secure) { mmdevice = device; bluetoothsocket tmp = null; msockettype = secure ? "secure" : "insecure"; // get a bluetoothsocket for a connection with the // given bluetoothdevice try { if (secure) { tmp = device.createrfcommsockettoservicerecord( my_uuid_secure); } else { tmp = device.createinsecurerfcommsockettoservicerecord( my_uuid_insecure); } } catch (ioexception e) { log.e(tag, "socket type: " + msockettype + "create() failed", e); } mmsocket = tmp; } public void run() { log.i(tag, "begin mconnectthread sockettype:" + msockettype); setname("connectthread" + msockettype); // always cancel discovery because it will slow down a connection madapter.canceldiscovery(); // make a connection to the bluetoothsocket try { // this is a blocking call and will only return on a // successful connection or an exception mmsocket.connect(); } catch (ioexception e) { // close the socket try { mmsocket.close(); } catch (ioexception e2) { log.e(tag, "unable to close() " + msockettype + " socket during connection failure", e2); } connectionfailed(); return; } // reset the connectthread because we're done synchronized (bluetoothchatservice.this) { mconnectthread = null; } // start the connected thread connected(mmsocket, mmdevice, msockettype); } public void cancel() { try { mmsocket.close(); } catch (ioexception e) { log.e(tag, "close() of connect " + msockettype + " socket failed", e); } } } /** * this thread runs during a connection with a remote device. * it handles all incoming and outgoing transmissions. */ private class connectedthread extends thread { private final bluetoothsocket mmsocket; private final inputstream mminstream; private final outputstream mmoutstream; public connectedthread(bluetoothsocket socket, string sockettype) { log.d(tag, "create connectedthread: " + sockettype); mmsocket = socket; inputstream tmpin = null; outputstream tmpout = null; // get the bluetoothsocket input and output streams try { tmpin = socket.getinputstream(); tmpout = socket.getoutputstream(); } catch (ioexception e) { log.e(tag, "temp sockets not created", e); } mminstream = tmpin; mmoutstream = tmpout; } public void run() { log.i(tag, "begin mconnectedthread"); byte[] buffer = new byte[1024]; int bytes; // keep listening to the inputstream while connected while (true) { try { // read from the inputstream bytes = mminstream.read(buffer); // send the obtained bytes to the ui activity mhandler.obtainmessage(controlparkingactivity.message_read, bytes, -1, buffer).sendtotarget(); } catch (ioexception e) { log.e(tag, "disconnected", e); connectionlost(); // start the service over to restart listening mode bluetoothchatservice.this.start(); break; } } } /** * write to the connected outstream. * @param buffer the bytes to write */ public void write(byte[] buffer) { try { mmoutstream.write(buffer); // share the sent message back to the ui activity mhandler.obtainmessage(controlparkingactivity.message_write, -1, -1, buffer).sendtotarget(); } catch (ioexception e) { log.e(tag, "exception during write", e); } } public void cancel() { try { mmsocket.close(); } catch (ioexception e) { log.e(tag, "close() of connect socket failed", e); } } } }
上一篇: 06-表的操作
下一篇: 07-Mysql数据库----数据类型