Android藍牙開發(二)
有問題可以加羣討論:517018699
Android 可以通過Android BlueTooth訪問藍牙功能的途徑,這些API允許應用以無線的形式連接到其他藍牙,從而實現點到點和多點無線功能。
使用BlueTooth API,Android應用可以執行以下操作
* 掃描其他藍牙設備
* 查詢本地藍牙適配器的配對藍牙設備
* 建立RFCOMM通道
* 通過服務發現連接到其他設備
* 與其他設備進行雙向數據傳輸
* 管理多個連接
Android藍牙採用的是SDP協議進行通信,通信方式類似於平常使用的socket
權限
<!--需要硬件支持低功耗藍牙-->
<uses-feature android:name"android.permission.BLUETOOTH_ADMIN"/>
<!--藍牙權限-->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!--Android 5.0以上藍牙好需要位置權限-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="andriod.permission.ACCESS_FINE_LOCATION"/>
是的,你會發現使用藍牙還需要位置權限?我開始也覺得一個藍牙也要位置權限,後來在翻看官方文檔的時候才知道的,不然你在5.0以上的手機上掃不出藍牙的!詳情請翻閱官方文檔:
API提供的方法
在Android API裏面提供了Bluetooth相關的類21個和一個接口
1.BluetoothAdapter
2.BluetoothAssignedNumbers
3.BluetoothA2dp
4.BluetoothClass
5.BluetoothDevice
6.BluetoothGatt
7.BluetoothGattCallback
8.BluetoothGattCharacteristic
9.BluetoothGattDescriptor
10.BluetoothGattServer
11.BluetoothGattService
12.BluetoothGattServerCallback
13.BluetoothHeadset
14.BluetoothLeAdvertiser
15.BluetoothLeScanner
16.BluetoothManager
17.BluetoothHealth
18.BluetoothHealthAppConfiguration
19.BluetoothHealthCallback
20.BluetoothServerSocket
21.BluetoothSocket
22.BluetoothProfile ----接口
日常開發中我們使用到的
BluetoothAdapter——藍牙適配器
* 用於:建立藍牙連接(bluetoothSocket)之前使用
* 提供方法:
* cancelDiscovery();——取消發現藍牙設備
* disable()——關閉藍牙
* enable()——打開藍牙
* isEnabled()——判斷本地藍牙是否打開——true打開
* getAddress()——獲取本地藍牙地址
* getDefaultAdapter()——獲取默認BluetoothAdapter,實際上,也只有這一種方法獲取BluetoothAdapter
* getName()——獲取本地藍牙名稱
* getRemoteDevice(String address)——根據藍牙地址獲取遠程藍牙設備
* getState()獲取本地藍牙是適配器當前狀態
* isDiscovering()判斷當前是否在查找設備——是返回true
* startDiscovery()——開始搜索
* listenUsingRfcommWithServiceRecord(String name,UUID uuid)根據名稱,UUID創建並返回BluetoothServerSocket,這是創建BluetoothSocket服務器端的第一步
BluetoothDevice——藍牙設備
- 提供方法:
- createRfcommSocketToServiceRecord(UUIDuuid)根據UUID創建並返回一個BluetoothSocket
- getState()藍牙狀態:只有在BluetoothAdapter.STATE_ON 狀態下纔可以監聽
- getName()——獲取本地藍牙名稱
- getAddress()——獲取本地藍牙地址
BluetoothServerSocket——服務端藍牙通信
* 提供方法:
* 兩個重載accept(),accept(inttimeout)兩者的區別在於後面的方法指定了過時時間,需要注意的是,執行這兩個方法的時候,直到接收到了客戶端的請求(或是過期之後),都會阻塞線程,應該放在新線程裏運行!兩個方法都返回一個BluetoothSocket,最後的連接也是服務器端與客戶端的兩個BluetoothSocket的連接
* close()——關閉!
BluetoothSocket——客戶端藍牙通信
* 提供方法:
* connect()——連接
* getInptuStream()——獲取輸入流
* getOutputStream()——獲取輸入流
* getRemoteDevice()——獲取遠程設備——這裏指的是獲取bluetoothSocket指定連接的那個遠程藍牙設備
* close()——關閉
獲取藍牙適配器
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter==null){
//改設備不支持藍牙
}
開啓藍牙
if(!mBluetoothAdapter.isEnabled()){
//彈出對話框提示用戶是後打開
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);
private static final int REQUEST_BLUETOOTH_PERMISSION=10;
private void requestBluetoothPermission(){
//判斷系統版本
if (Build.VERSION.SDK_INT >= 23) {
//檢測當前app是否擁有某個權限
int checkCallPhonePermission = ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION);
//判斷這個權限是否已經授權過
if(checkCallPhonePermission != PackageManager.PERMISSION_GRANTED){
//判斷是否需要 向用戶解釋,爲什麼要申請該權限
if(ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_COARSE_LOCATION))
ActivityCompat.requestPermissions(this ,new String[]
{Manifest.permission.ACCESS_COARSE_LOCATION},REQUEST_BLUETOOTH_PERMISSION);
return;
}else{
}
} else {
}
}
//接下來我們就可以靜默開啓藍牙了:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.enable(); //開啓
//mBluetoothAdapter.disable(); //關閉
}
獲取本地藍牙信息
//獲取本機藍牙名稱
String name = mBluetoothAdapter.getName();
//獲取本機藍牙地址
String address = mBluetoothAdapter.getAddress();
Log.d(TAG,"bluetooth name ="+name+" address ="+address);
//獲取已配對藍牙設備
Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();
Log.d(TAG, "bonded device size ="+devices.size());
for(BluetoothDevice bonddevice:devices){
Log.d(TAG, "bonded device name ="+bonddevice.getName()+" address"+bonddevice.getAddress());
}
搜索設備——停止搜索
mBluetoothAdapter.startDiscovery(); //——————搜索
mBluetoothAdapter.cancelDiscovery(); //——————停止搜索
public boolean isDiscovering ();//返回true——正處於掃描設備中
設置藍牙可見性
/*
*有時候掃描不到某設備,這是因爲該設備對外不可見或者距離遠,需要設備該藍牙可見,這樣該才能被搜索到。
*可見時間默認值爲120s,最多可設置300。
*/
if (mBluetoothAdapter.isEnabled()) {
if (mBluetoothAdapter.getScanMode() !=
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);
startActivity(discoverableIntent);
}
}
監聽掃描結果
/**
*通過廣播接收者查看掃描到的藍牙設備,每掃描到一個設備,系統都會發送此廣播(BluetoothDevice.ACTION_FOUNDE)。
*其中參數intent可以獲取藍牙設備BluetoothDevice。
*/
private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG,"mBluetoothReceiver action ="+action);
if(BluetoothDevice.ACTION_FOUND.equals(action)){//每掃描到一個設備,系統都會發送此廣播。
//獲取藍牙設備
BluetoothDevice scanDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if(scanDevice == null || scanDevice.getName() == null) return;
Log.d(TAG, "name="+scanDevice.getName()+"address="+scanDevice.getAddress());
//藍牙設備名稱
String name = scanDevice.getName();
if(name != null && name.equals(VnApplication.BLUETOOTH_NAME)){
mBluetoothAdapter.cancelDiscovery();
//取消掃描
mProgressDialog.setTitle(getResources().getString
(R.string.progress_connecting)); //連接到設備。
mBlthChatUtil.connect(scanDevice);
}
}else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
}
}
};
連接設備
public BluetoothGatt connectGatt(Content content,boolean autoConnect,BluetoothGattCallback callback){
return(connectGatt(context,autoConnect,callback,TRANSPORT_AUTO));
}
/**
*第一個 Context 就不說了;第二個參數 autoConnect 的解釋是“是否直接連接到遠程設備(false)或一旦遠程設備可用即可自動連接(true)”;
*第三個參數也是上面提到的抽象類,這個類在連接過程中起到關鍵作用。最後方法會返回一個 BluetoothGatt 對象,後續我們通過這個對
*象可以重連、斷開、關閉設備。貼下我例子中的連接方法:
*/
/**
*連接設備,如果服務未開啓或者地址爲空的情況就返回false;
*如果地址存在是否連接成功取決於藍牙底層
*@param address
*@return 是否連接到
*/
@Override
public boole connectDevice(String address){
if(address.equals(mAddress)&&mBluetoothGatt !=null){
return mBluetoothGatt.connect();
}
BluetoothDevice device=arshowBluetooth.getBluetoothAdaoter().
getRemoteDevice(address);
if(device ==null){
return fasle;
}
//false表示直接連接,ture表示遠程設備可用之後連接
mBluetoothGatt=device.connectGatt(context,false,mGattCallback);
mAddress=address;
return true;
}