藍牙開發(fā)相關
使用Android Bluetooth APIs將設備通過藍牙連接并通信,設置藍牙,查找藍牙設備,配對藍牙設備
連接并傳輸數(shù)據(jù),以下是Android系統(tǒng)提供的藍牙相關的類和接口
- BluetoothAdapter
- BluetoothDevice
- BluetoothSocket
- BluetoothServerSocket
- BluetoothClass
- BluetoothProfile
- BluetoothHeadset
- BluetoothA2dp
- BluetoothHealth
- BluetoothHealthCallback
- BluetoothHealthAppConfiguration
- BluetoothProfile.ServiceListener
藍牙權限
使用藍牙功能,需要在AndroidManifest.xml中聲明藍牙相關的權限
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
建立藍牙
- 初始化連接
在通過藍牙通信之前,需要先確定設備是否支持藍牙功能,先初始化一個BluetoothAdapter的實例,
BluetoothAdapter提供了一個靜態(tài)方法getDefaultAdapter()來獲得BluetoothAdapter的實例
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// 設備不支持藍牙功能
}
- 打開藍牙
下一步就是打開藍牙,調用isEnabled()方法檢查藍牙功能是否已經(jīng)打開,返回true說明藍牙已開啟,
返回false說明藍牙功能未開啟,開啟藍牙可以通過發(fā)送廣播ACTION_REQUEST_ENABLE,也可以通過方法
enable()直接打開,這兩種方法都會有藍牙權限的提示,選擇允許,否則無法打開藍牙
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
mBluetoothAdapter.enable();
在應用中可以設置藍牙的狀態(tài)的監(jiān)聽ACTION_STATE_CHANGED廣播,當藍牙的狀態(tài)的變化時,就會觸發(fā)這個
廣播,接收到這個廣播之后,在intent中可以獲得當前藍牙的狀態(tài)和前一次的藍牙的狀態(tài)
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
藍牙的狀態(tài)值有:
int STATE_OFF = 10;//藍牙關閉狀態(tài)
int STATE_TURNING_ON = 11;//藍牙正在打開
int STATE_ON = 12;//藍牙打開狀態(tài)
int STATE_TURNING_OFF = 13;//藍牙正在關閉
查找藍牙設備
打開藍牙之后,下一步就是查找可以使用的藍牙設備,藍牙的api中也提供了相關的接口,由于藍牙的掃描
是一個耗電的操作,不用時計時取消掃描藍牙
mBluetoothAdapter.isDiscovering(); //監(jiān)測藍牙是否正在掃描
mBluetoothAdapter.startDiscovery();//開始掃描
mBluetoothAdapter.cancelDiscovery();//取消掃描
為了發(fā)現(xiàn)可用的藍牙的設備,必須在應用中注冊ACTION_FOUND的廣播,調用方法startDiscovery()如果查找到可用的
設備會觸發(fā)這個廣播,這個廣播中帶有EXTRA_DEVICE的設備信息可以通過下面的方法獲得設備的信息
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.e("tag","device name: "+device.getName()+" address: "+device.getAddress());
}
}
};
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
- 查詢已經(jīng)配對的設備列表
在進行查找之前,可以先獲得之前已經(jīng)配對成功的藍牙設備的列表,可以調用方法getBondedDevices()獲得
已經(jīng)配對的藍牙設備列表
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
//可以獲得已經(jīng)配對的藍牙的名稱和地址
Log.e("tag","device name: "+device.getName()+" address: "+device.getAddress());
}
}
- 是其他設備可見
上面講的都是發(fā)現(xiàn)其他的藍牙設備,也可以設置設備本身是否對其他設備可見,通過發(fā)送ACTION_REQUEST_DISCOVERABLE
的廣播,會調用系統(tǒng)的方法,還可以設置多長時間內是可見的,在intent中設置EXTRA_DISCOVERABLE_DURATION,最大值是
3600s,超過3600s會設置為120s,點擊允許會回調onActivityResult()方法
//設置設備在300s內是可見的
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
如果沒有打開藍牙,執(zhí)行上面的操作會自動打開藍牙
可以通過監(jiān)聽ACTION_SCAN_MODE_CHANGED廣播,可以在intent中根據(jù)EXTRA_SCAN_MODE的參數(shù)獲得當前設備的SCAN MODE
有一些幾種模式
int SCAN_MODE_NONE = 20;//這個模式不能被發(fā)現(xiàn)也不能連接
int SCAN_MODE_CONNECTABLE = 21;//這個模式不能被掃描到,但是可以連接
int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;//這個模式可以被發(fā)現(xiàn),也能被連接
藍牙的連接
- Server 端
通過BluetoothAdapter的listenUsingRfcommWithServiceRecord(String, UUID)方法獲得BluetoothServerSocket對象
的實例,然后socket就會通過accept()監(jiān)聽客戶端的連接的狀態(tài)
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) { }
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// 在后臺一直監(jiān)聽客戶端的請求
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
break;
}
if (socket != null) {
mmServerSocket.close();
break;
}
}
}
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) { }
}
}
- Client 端
使用BluetoothDevice的createRfcommSocketToServiceRecord(UUID)方法獲得BluetoothSocket對象的實例
然后調用connect()方法,這時server端會監(jiān)聽到這個請求,之后就建立連接,然后就可以進行通信了
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
BluetoothSocket tmp = null;
mmDevice = device;
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
mBluetoothAdapter.cancelDiscovery();
try {
mmSocket.connect();
} catch (IOException connectException) {
try {
mmSocket.close();
} catch (IOException closeException) { }
return;
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
連接的監(jiān)聽
可以通過注冊廣播監(jiān)聽藍牙設備連接的狀態(tài)變化,廣播BluetoothDevice.ACTION_BOND_STATE_CHANGED,監(jiān)聽到這個廣播之后,可以
在intent中獲得連接的狀態(tài)
int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
設備連接的狀態(tài)值
int BOND_NONE = 10;//沒有連接
int BOND_BONDING = 11;//正在連接
int BOND_BONDED = 12;//已經(jīng)建立連接