加入权限
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
一、本机蓝牙
1 得到本机蓝牙适配器
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.getName();//得到蓝牙名称(设备名称)
mBluetoothAdapter.getAddress();//得到本机蓝牙地址
mBluetoothAdapter.getBondedDevices();//得到已配对的蓝牙集合(Set集合)
mBluetoothAdapter.setName(name);//待验证:设置蓝牙名称,短时间有效,过段时间恢复为设备名称 ?
mBluetoothAdapter.getRemoteDevice(mInfo.getmAddress());//通过地址得到远程蓝牙设备
2 打开蓝牙
mBluetoothAdapter.isEnabled();//判断蓝牙是否已经打开
mBluetoothAdapter.enable();//打开蓝牙,无提示框
Intent enabler=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);//
startActivity(enabler);//打开蓝牙,有提示框
Intent enablerTime = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
enablerTime.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);//设置持续时间(最多300秒),默认120秒
con.startActivity(enablerTime);// 蓝牙可被其它设备发现
二、搜索蓝牙
1 注册蓝牙广播
//注册广播
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
//filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mReceiver, filter);
//广播接收者
private BroadcastReceiver mReceiver=new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
String action=intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(mDevice.getBondState()!=BluetoothDevice.BOND_BONDED){
//设备配对状态,BOND_BONDED为已配对
}
}else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
}
}
}
//注销广播
unregisterReceiver(mReceiver);
2 搜索
mBluetoothAdapter.cancelDiscovery();//待验证:有的手机如魅族会在此方法后发送ACTION_DISCOVERY_FINISHED广播,有的手机不会如小米。? mBluetoothAdapter.startDiscovery();
//一轮搜索时间为12s
三、蓝牙配对
反射技术
Method creMethod = BluetoothDevice.class.getMethod("createBond");
boolean peidui=(Boolean) creMethod.invoke(mBluetoothAdapter.getRemoteDevice(mInfo.getmAddress()));
//此方法后会有弹出框确认是否配对,待解决:怎么用代码判断配对成功或失败????
我的解决办法,开个10s的线程去检测蓝牙配对状态:
new Thread(new Runnable() {
@Override
public void run() {
int i=0;
while(i<GameForPartyUtils.PAIR_TIME){
if(mBluetoothAdapter.getRemoteDevice(mInfo.getmAddress()).getBondState()==BluetoothDevice.BOND_BONDED){
mhandler.sendEmptyMessage(0);//配对成功
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
if(i==GameForPartyUtils.PAIR_TIME){
mhandler.sendEmptyMessage(1);//配对失败
}
}
}).start();
四、蓝牙连接
蓝牙连接是通过BluetoothSocket建立连接,服务器端(BluetoothServerSocket)和客户端(BluetoothSocket)需指定同样的UUID,才能建立连接,因为建立连接的方法会阻塞线程,所以服务器端和客户端都应启动新线程连接。
1 服务器端:
public class ServerThread extends Thread{
public static final String PROTOCOL_SCHEME_RFCOMM = "btspp";
private BluetoothSocket socket = null;
private final BluetoothServerSocket mserverSocket;
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private Context con;
private Handler mHandler;
private boolean mAcceptFlag=true;
public ServerThread(Context con,Handler h){
this.con=con;
this.mHandler=h;
BluetoothServerSocket tmp = null; //使用一个临时对象代替,因为mserverSocket定义为final,必须定义为final,才能连接多个客户端
try {
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(PROTOCOL_SCHEME_RFCOMM,
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
} catch (IOException e) {
e.printStackTrace();
}
mserverSocket=tmp;
}
@Override
public void run() {
while(mAcceptFlag){
try {
socket = mserverSocket.accept();//阻塞操作,等待连接
String deviceName=socket.getRemoteDevice().getName();连接成功后,得到连接设备的名称
ReadThread mreadThread = new ReadThread(con,socket,mHandler,deviceName);
mreadThread.start();//接收客户端的数据
Thread.sleep(1000);
} catch (IOException e) {
e.printStackTrace();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
待解决:怎么判断客户端已从服务端断开???
2 客户端
public class ClientThread extends Thread{
private final BluetoothSocket mSocket;
private BluetoothDevice mDevice;
private Context mCon;
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private Handler mHandler;
public ClientThread(Context con,BluetoothDevice device,Handler h){
this.mDevice=device;
this.mCon=con;
this.mHandler=h;
BluetoothSocket tmp= null;
try {
tmp = mDevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
} catch (IOException e) {
e.printStackTrace();
}
mSocket=tmp;
}
public BluetoothSocket getmSocket() {
return mSocket;
}
@Override
public void run() {
mBluetoothAdapter.cancelDiscovery();//有利于提高连接性能
try {
mSocket.connect();//阻塞操作,连接服务器
mHandler.sendEmptyMessage(0);
}catch (IOException e){
e.printStackTrace();
mHandler.sendEmptyMessage(1);
Log.i("server", "连接服务端异常!断开连接重新试一试");
}
}
}
五、通信
public class ReadThread extends Thread{
private BluetoothSocket mSocket;
private Handler mHandler;
private String mDeviceName;
private boolean mReadFlag=true;
public ReadThread(){}
public ReadThread(Context con, BluetoothSocket socket,Handler h,String name) {
this.mSocket=socket;
this.mHandler=h;
this.mDeviceName=name;
}
@Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
InputStream mmInStream = null;
try {
mmInStream = mSocket.getInputStream();
} catch (IOException e1) {
e1.printStackTrace();
}
while (mReadFlag) {
try {
// Read from the InputStream
if( (bytes = mmInStream.read(buffer)) > 0 ){
byte[] buf_data = new byte[bytes];
for(int i=0; i<bytes; i++){
buf_data[i] = buffer[i];
}
String s = new String(buf_data);
Message msg = new Message();
msg.obj=mDeviceName+": "+s;
msg.what=GameForPartyUtils.HANDLER_DEVICE_OUTINFO;
mHandler.sendMessage(msg);
Log.i("server", "output="+s);
}
} catch (IOException e) {
e.printStackTrace();
break;
}
}
try {
mmInStream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
public boolean ismReadFlag() {
return mReadFlag;
}
public void setmReadFlag(boolean mReadFlag) {
this.mReadFlag = mReadFlag;
}
}