藍(lán)牙開(kāi)發(fā)相關(guān)
使用Android Bluetooth APIs
將設(shè)備通過(guò)藍(lán)牙連接并通信凫岖,設(shè)置藍(lán)牙,查找藍(lán)牙設(shè)備痛单,配對(duì)藍(lán)牙設(shè)備
連接并傳輸數(shù)據(jù)塑顺,以下是Android
系統(tǒng)提供的藍(lán)牙相關(guān)的類和接口
- BluetoothAdapter
- BluetoothDevice
- BluetoothSocket
- BluetoothServerSocket
- BluetoothClass
- BluetoothProfile
- BluetoothHeadset
- BluetoothA2dp
- BluetoothHealth
- BluetoothHealthCallback
- BluetoothHealthAppConfiguration
- BluetoothProfile.ServiceListener
藍(lán)牙權(quán)限
使用藍(lán)牙功能,需要在AndroidManifest.xml
中聲明藍(lán)牙相關(guān)的權(quán)限
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
建立藍(lán)牙
- 初始化連接
在通過(guò)藍(lán)牙通信之前畅哑,需要先確定設(shè)備是否支持藍(lán)牙功能肴楷,先初始化一個(gè)BluetoothAdapter
的實(shí)例,
BluetoothAdapter
提供了一個(gè)靜態(tài)方法getDefaultAdapter()
來(lái)獲得BluetoothAdapter
的實(shí)例
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// 設(shè)備不支持藍(lán)牙功能
}
- 打開(kāi)藍(lán)牙
下一步就是打開(kāi)藍(lán)牙荠呐,調(diào)用isEnabled()
方法檢查藍(lán)牙功能是否已經(jīng)打開(kāi)赛蔫,返回true
說(shuō)明藍(lán)牙已開(kāi)啟,
返回false
說(shuō)明藍(lán)牙功能未開(kāi)啟泥张,開(kāi)啟藍(lán)牙可以通過(guò)發(fā)送廣播ACTION_REQUEST_ENABLE
,也可以通過(guò)方法
enable()
直接打開(kāi)呵恢,這兩種方法都會(huì)有藍(lán)牙權(quán)限的提示,選擇允許
媚创,否則無(wú)法打開(kāi)藍(lán)牙
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
mBluetoothAdapter.enable();
在應(yīng)用中可以設(shè)置藍(lán)牙的狀態(tài)的監(jiān)聽(tīng)ACTION_STATE_CHANGED
廣播渗钉,當(dāng)藍(lán)牙的狀態(tài)的變化時(shí),就會(huì)觸發(fā)這個(gè)
廣播,接收到這個(gè)廣播之后鳄橘,在intent中可以獲得當(dāng)前藍(lán)牙的狀態(tài)和前一次的藍(lán)牙的狀態(tài)
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
藍(lán)牙的狀態(tài)值有:
int STATE_OFF = 10;//藍(lán)牙關(guān)閉狀態(tài)
int STATE_TURNING_ON = 11;//藍(lán)牙正在打開(kāi)
int STATE_ON = 12;//藍(lán)牙打開(kāi)狀態(tài)
int STATE_TURNING_OFF = 13;//藍(lán)牙正在關(guān)閉
查找藍(lán)牙設(shè)備
打開(kāi)藍(lán)牙之后声离,下一步就是查找可以使用的藍(lán)牙設(shè)備,藍(lán)牙的api中也提供了相關(guān)的接口,由于藍(lán)牙的掃描
是一個(gè)耗電的操作瘫怜,不用時(shí)計(jì)時(shí)取消掃描藍(lán)牙
mBluetoothAdapter.isDiscovering(); //監(jiān)測(cè)藍(lán)牙是否正在掃描
mBluetoothAdapter.startDiscovery();//開(kāi)始掃描
mBluetoothAdapter.cancelDiscovery();//取消掃描
為了發(fā)現(xiàn)可用的藍(lán)牙的設(shè)備术徊,必須在應(yīng)用中注冊(cè)ACTION_FOUND
的廣播,調(diào)用方法startDiscovery()
如果查找到可用的
設(shè)備會(huì)觸發(fā)這個(gè)廣播鲸湃,這個(gè)廣播中帶有EXTRA_DEVICE
的設(shè)備信息可以通過(guò)下面的方法獲得設(shè)備的信息
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)配對(duì)的設(shè)備列表
在進(jìn)行查找之前赠涮,可以先獲得之前已經(jīng)配對(duì)成功的藍(lán)牙設(shè)備的列表,可以調(diào)用方法getBondedDevices()
獲得
已經(jīng)配對(duì)的藍(lán)牙設(shè)備列表
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
//可以獲得已經(jīng)配對(duì)的藍(lán)牙的名稱和地址
Log.e("tag","device name: "+device.getName()+" address: "+device.getAddress());
}
}
- 是其他設(shè)備可見(jiàn)
上面講的都是發(fā)現(xiàn)其他的藍(lán)牙設(shè)備暗挑,也可以設(shè)置設(shè)備本身是否對(duì)其他設(shè)備可見(jiàn)世囊,通過(guò)發(fā)送ACTION_REQUEST_DISCOVERABLE
的廣播,會(huì)調(diào)用系統(tǒng)的方法窿祥,還可以設(shè)置多長(zhǎng)時(shí)間內(nèi)是可見(jiàn)的,在intent中設(shè)置EXTRA_DISCOVERABLE_DURATION
,最大值是
3600s株憾,超過(guò)3600s會(huì)設(shè)置為120s,點(diǎn)擊允許
會(huì)回調(diào)onActivityResult()
方法
//設(shè)置設(shè)備在300s內(nèi)是可見(jiàn)的
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
如果沒(méi)有打開(kāi)藍(lán)牙晒衩,執(zhí)行上面的操作會(huì)自動(dòng)打開(kāi)藍(lán)牙
可以通過(guò)監(jiān)聽(tīng)ACTION_SCAN_MODE_CHANGED
廣播嗤瞎,可以在intent中根據(jù)EXTRA_SCAN_MODE
的參數(shù)獲得當(dāng)前設(shè)備的SCAN MODE
有一些幾種模式
int SCAN_MODE_NONE = 20;//這個(gè)模式不能被發(fā)現(xiàn)也不能連接
int SCAN_MODE_CONNECTABLE = 21;//這個(gè)模式不能被掃描到,但是可以連接
int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;//這個(gè)模式可以被發(fā)現(xiàn)听系,也能被連接
藍(lán)牙的連接
- Server 端
通過(guò)BluetoothAdapter
的listenUsingRfcommWithServiceRecord(String, UUID)
方法獲得BluetoothServerSocket
對(duì)象
的實(shí)例贝奇,然后socket就會(huì)通過(guò)accept()
監(jiān)聽(tīng)客戶端的連接的狀態(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;
// 在后臺(tái)一直監(jiān)聽(tīng)客戶端的請(qǐng)求
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
對(duì)象的實(shí)例
然后調(diào)用connect()
方法,這時(shí)server端會(huì)監(jiān)聽(tīng)到這個(gè)請(qǐng)求靠胜,之后就建立連接掉瞳,然后就可以進(jì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)聽(tīng)
可以通過(guò)注冊(cè)廣播監(jiān)聽(tīng)藍(lán)牙設(shè)備連接的狀態(tài)變化,廣播BluetoothDevice.ACTION_BOND_STATE_CHANGED
,監(jiān)聽(tīng)到這個(gè)廣播之后浪漠,可以
在intent中獲得連接的狀態(tài)
int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
設(shè)備連接的狀態(tài)值
int BOND_NONE = 10;//沒(méi)有連接
int BOND_BONDING = 11;//正在連接
int BOND_BONDED = 12;//已經(jīng)建立連接