接上一篇Android BLE4.0(基本知識)罩缴,本篇記錄在Android中的藍牙4.0開發(fā)他爸。要想與藍牙設(shè)備進行通訊,首先要連接到相應的設(shè)備夕膀,連接到相應的設(shè)備之前虚倒,我們要能夠搜索到它美侦。所以我們先從找到設(shè)備開始。
1魂奥、申請權(quán)限
在Android中要想使用藍牙菠剩,需要添加以下兩個權(quán)限
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN"/>
一般情況下,添加上面兩個權(quán)限應該是可以了耻煤,但是老司機們都應該知道Android 6.0采用新的權(quán)限機制來保護用戶的隱私具壮,將權(quán)限分為Normal Permissions (不涉及用戶隱私,不需要用戶授權(quán))和Dangerous Permission (涉及用戶隱私哈蝇,使用時需要用戶實時授權(quán))兩種棺妓。
藍牙權(quán)限本身不屬于用戶隱私的權(quán)限,但是在Android 6.0之后要用藍牙還需要添加一個模糊定位的權(quán)限
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
這個權(quán)限就屬于隱私權(quán)限的范圍了炮赦。怜跑。。吠勘。一股淡淡的憂傷性芬。。剧防。
所以想要兼容6.0還要在代碼中檢測權(quán)限:
1.1植锉、Android 6.0 檢測并申請權(quán)限
/*
* 檢測并申請權(quán)限
*/
private void checkBluetoothPermission() {
if (Build.VERSION.SDK_INT >= 23) {
//校驗是否已具有模糊定位權(quán)限
if (ContextCompat.checkSelfPermission(TYMposActivity.this,
Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
//申請模糊定位權(quán)限
ActivityCompat.requestPermissions(TYMposActivity.this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);
} else {
//具有權(quán)限
connectBluetooth();
}
} else {
//系統(tǒng)不高于6.0直接執(zhí)行
connectBluetooth();
}
}
這里用到了兩個API
ContextCompat.checkSelfPermission
主要用于檢測某個權(quán)限是否已經(jīng)被授予,
返回值為PackageManager.PERMISSION_DENIED
或者是PackageManager.PERMISSION_GRANTED峭拘。當返回DENIED就需要進行申請授權(quán)了ActivityCompat.requestPermissions
這是個異步方法汽煮,有三個參數(shù)
第一個參數(shù)是Context,這個不多說棚唆;
第二個參數(shù)是需要申請的權(quán)限的字符串數(shù)組暇赤;
第三個參數(shù)為requestCode,主要用于回調(diào)的時候檢測宵凌。
可以從方法名requestPermissions以及第二個參數(shù)看出鞋囊,是支持一次性申請多個權(quán)限的,系統(tǒng)會通過對話框 逐一 詢問用戶是否授權(quán)瞎惫。
1.2溜腐、授權(quán)返回處理:
對授權(quán)返回值進行處理,有點類似于startActivityForResult
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION: {
// 如果請求被取消瓜喇,則結(jié)果數(shù)組為空.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//已授權(quán)
} else {
// 未授權(quán)
}
return;
}
}
}
關(guān)于6.0的權(quán)限申請到此結(jié)束挺益,另外補充一下:
如果想聲明你的app只為具有BLE的設(shè)備提供,在manifest文件中包括:
<uses-feature android:name="android.hardware.bluetooth_le"
android:required="true"/>
但如果想讓你的app提供給那些不支持BLE的設(shè)備乘寒,需要在manifest中包括上面代碼并設(shè)置required="false"望众,然后在運行時可以通過使用PackageManager.hasSystemFeature()確定BLE的可用性。
2、檢查設(shè)備是否支持藍牙
注意:Android系統(tǒng)版本在4.3及以上才能使用藍牙4.0烂翰。
使用此檢查確定BLE是否支持在設(shè)備上夯缺,然后你可以有選擇性禁用BLE相關(guān)的功能
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "設(shè)備不支持藍牙4.0", Toast.LENGTH_SHORT).show();
finish();
}
3、藍牙搜索
大致步驟
- **獲取BluetoothManager **
- 獲取BluetoothAdapter
- 調(diào)用BluetoothAdapter.startLeScan開始掃描設(shè)備
獲取BluetoothManager:
BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
獲取BluetoothAdapter
獲取BluetoothAdapter有兩種方式:
- 第一種:
BluetoothAdapter adapter = manager.getAdapter();
- 第二種
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
掃描附近BLE設(shè)備
在開始掃描之前先打開藍牙,打開之前需要先判斷藍牙是否已經(jīng)打開:
/**
* 藍牙是否打開
*
* @return
*/
public boolean isBleOpen() {
if (adapter == null) {
return false;
}
return adapter.isEnabled();
}
打開藍牙有兩種方式
- 跳轉(zhuǎn)到系統(tǒng)的界面甘耿,手動打開
/**
* 系統(tǒng)打開藍牙
*/
public void sysOpenBLE(Activity activity, int requestCode) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
activity.startActivityForResult(intent, requestCode);
}
- 自動打開藍牙
/**
* 打開藍牙
*/
public boolean openBLE() {
if (adapter == null) {
return false;
}
return adapter.enable();
}
確保藍牙打開之后開始掃描設(shè)備:
通過adapter.startLeScan()方法來進行掃描踊兜。這里有兩個方法:
/**
*
*/
public boolean startLeScan(LeScanCallback callback) {
return startLeScan(null, callback);
}
/**
* @param serviceUuids Array of services to look for
* 需要過濾的UUID服務(wù),掃描的時候佳恬,只返回與指定UUID相同的設(shè)備
*/
public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {
if (DBG) Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids));
if (callback == null) {
if (DBG) Log.e(TAG, "startLeScan: null callback");
return false;
}
BluetoothLeScanner scanner = getBluetoothLeScanner();
if (scanner == null) {
if (DBG) Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner");
return false;
}
......
}
以上代碼摘自Android源碼捏境,這兩個不多說什么,重點在 serviceUuids這里毁葱,大家都知道每個藍牙都有一個服務(wù)UUID,這個參數(shù)就是針對這個UUID進行過濾的典蝌,掃描返回結(jié)果的時候,只會返回與UUID相同的設(shè)備头谜,另外一個是LeScanCallback**骏掀,這個是返回搜索結(jié)果的回調(diào),如果這個LeScanCallback不傳柱告,掃描是不會啟動的截驮。
BluetoothAdapter.LeScanCallback scanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice bluetoothDevice, int rssi, byte[] scanRecord) {
}
};
在這個掃描回調(diào)中,回調(diào)了三個參數(shù):
- BluetoothDevice
/**
* Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
* create a connection with the respective device or query information about
* it, such as the name, address, class, and bonding state.
* 藍牙信息相關(guān)的類际度,可以獲取藍牙的名稱葵袭,地址,已經(jīng)綁定狀態(tài)等
*/
public final class BluetoothDevice implements Parcelable {
.....
//綁定狀態(tài)相關(guān)
/**
* Indicates the remote device is not bonded (paired).
* <p>There is no shared link key with the remote device, so communication
* (if it is allowed at all) will be unauthenticated and unencrypted.
*/
public static final int BOND_NONE = 10;
/**
* Indicates bonding (pairing) is in progress with the remote device.
*/
public static final int BOND_BONDING = 11;
/**
* Indicates the remote device is bonded (paired).
* <p>A shared link keys exists locally for the remote device, so
* communication can be authenticated and encrypted.
* <p><i>Being bonded (paired) with a remote device does not necessarily
* mean the device is currently connected. It just means that the pending
* procedure was completed at some earlier time, and the link key is still
* stored locally, ready to use on the next connection.
* </i>
*/
public static final int BOND_BONDED = 12;
.....
//設(shè)備類型
/**
* Bluetooth device type, Unknown
*/
public static final int DEVICE_TYPE_UNKNOWN = 0;
/**
* Bluetooth device type, Classic - BR/EDR devices乖菱,傳統(tǒng)
*/
public static final int DEVICE_TYPE_CLASSIC = 1;
/**
* Bluetooth device type, Low Energy - LE-only 坡锡,低功耗
*/
public static final int DEVICE_TYPE_LE = 2;
/**
* Bluetooth device type, Dual Mode - BR/EDR/LE 雙模式
*/
public static final int DEVICE_TYPE_DUAL = 3;
............
}
其實就是藍牙的設(shè)備的一個實體類。沒什么可以說的窒所。
-
rssi
RSSI的值作為對遠程藍牙設(shè)備信號值鹉勒,正常為負值; 值越大信號越強; -
scanRecord
遠程設(shè)備提供的配對號,一般用不到吵取。
小結(jié)
如果不出意外禽额,到這里是可以掃描到周邊的藍牙設(shè)備了,對于藍牙開發(fā)已經(jīng)算是邁出了第一步皮官,也有了一個初步了解脯倒,接下來記錄怎么連接到一個搜索到的設(shè)備。