寫在前面:
作為一個程序員,各種苦逼啊,作為一個Android程序員,苦逼死了。
Android手機可以使用WIFI、藍牙和數據網絡進行網絡通信,那作為Android程序員,就必須得會這些了。如果不會,都不好意思給別人說你是21世紀的屌絲程序員。
通過WIFI和數據網絡通信的Socket編程(基於IP的TCP、UDP、HTTP通信 )相信大家都是駕輕就熟了。而現階段,隨著物聯網的發展和藍牙的BLE低功耗方案的成熟,BLE設備應用越來越廣泛,尤其是智能穿戴設備。
那麼BLE編程是和怎麼回事呢?到底難不難呢?網上已經很多關於BLE的文章了,有些寫的很好,有些真的沒有什麼毛用,完全是官方的Demo。
由於項目需要,最近一直在研究BLE編程,現在做好了,就做一下總結,與大家分享,能力有限,大牛莫笑!
一、什麼是BLE
藍牙低能耗(BLE)技術是低成本、短距離、可互操作的魯棒性無線技術,工作在免許可的2.4GHz ISM射頻頻段。它從一開始就設計為超低功耗(ULP)無線技術。它利用許多智能手段最大限度地降低功耗。藍牙低能耗技術采用可變連接時間間隔,這個間隔根據具體應用可以設置為幾毫秒到幾秒不等。另外,因為BLE技術采用非常快速的連接方式,因此平時可以處於“非連接”狀態(節省能源),此時鏈路兩端相互間只是知曉對方,只有在必要時才開啟鏈路,然後在盡可能短的時間內關閉鏈路。
其實就是藍牙的一種新技術而已,特點就是低功耗,連接速度快,但是只能傳輸小數據。
二、一些關於BLE的概念
Generic Attribute Profile (GATT)
通過BLE連接,讀寫屬性類小數據的Profile通用規范。現在所有的BLE應用Profile都是基於GATT的。
Attribute Protocol (ATT)
GATT是基於ATT Protocol的。ATT針對BLE設備做了專門的優化,具體就是在傳輸過程中使用盡量少的數據。每個屬性都有一個唯一的UUID,屬性將以characteristics and services的形式傳輸。
Characteristic
Characteristic可以理解為一個數據類型,它包括一個value和0至多個對次value的描述(Descriptor)。
Descriptor
對Characteristic的描述,例如范圍、計量單位等。
Service
Characteristic的集合。例如一個service叫做“Heart Rate Monitor”,它可能包含多個Characteristics,其中可能包含一個叫做“heart rate measurement的Characteristic。
請記住:一個BLE設備可以有多個Service,一個Service可以有多個Chracteristic,一個Chracteristic有一個Value和多個Descriptor,一個Descriptor包含一個Value。
三、關於BLE的一個API
BluetoothGatt
繼承BluetoothProfile,通過BluetoothGatt可以連接設備(connect),發現服務(discoverServices),並把相應地屬性返回到BluetoothGattCallback
BluetoothGattCharacteristic
相當於一個數據類型,它包括一個value和0~n個value的描述(BluetoothGattDescriptor)
BluetoothGattDescriptor
描述符,對Characteristic的描述,包括范圍、計量單位等
BluetoothGattService
服務,Characteristic的集合。
BluetoothProfile
一個通用的規范,按照這個規范來收發數據。
BluetoothManager
通過BluetoothManager來獲取BluetoothAdapter
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter
一個Android系統只有一個BluetoothAdapter ,通過BluetoothManager 獲取
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
BluetoothGattCallback
private BluetoothGattCallback GattCallback = new BluetoothGattCallback() {
// 這裡有9個要實現的方法,看情況要實現那些,用到那些就實現那些
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState){};
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){};
};
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
BluetoothGatt gatt = device.connectGatt(this, false, mGattCallback);
:notification對應onCharacteristicChanged;
gatt.setCharacteristicNotification(characteristic, true);
:readCharacteristic對應onCharacteristicRead;
gatt.readCharacteristic(characteristic);
: writeCharacteristic對應onCharacteristicWrite;
gatt.wirteCharacteristic(mCurrentcharacteristic);
:連接藍牙或者斷開藍牙 對應 onConnectionStateChange;
:readDescriptor對應onDescriptorRead;
:writeDescriptor對應onDescriptorWrite;
gatt.writeDescriptor(descriptor);
:readRemoteRssi對應onReadRemoteRssi;
gatt.readRemoteRssi()
:executeReliableWrite對應onReliableWriteCompleted;
:discoverServices對應onServicesDiscovered。
gatt.discoverServices()
BluetoothDevice
四、開始上代碼
代碼主要實現功能:首先進入BLEActivity,然後即可掃描BLE設備,選擇你想要連接的BLE設備,點擊,程序會開啟BLEService,BLEService將開始與設備建立GATT連接,並根據UUID或取相應的Service和相應的Chracteristic然後就可以進行數據讀寫了。
本程序,我留出了三個接口函數(均在BLEService中)
一個是self(),用於獲得BLEService的實例
一個是writeToBle(byte[]),可以通過此方法接口向BLE設備寫數據
一個是readFromBle(),通過此函數從BLE設備讀取數據
AndroidManifest.xml
package=com.study.blestudy
android:versionCode=1
android:versionName=1.0 >
android:minSdkVersion=8
android:targetSdkVersion=21 />
android:name=android.hardware.bluetooth_le
android:required=false />
android:allowBackup=true
android:icon=@drawable/ic_launcher
android:label=@string/app_name
android:theme=@style/AppTheme >
android:name=.BLEActivity
android:label=@string/app_name >
BLEActivity.java
package com.study.blestudy;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;
@SuppressLint(NewApi)
public class BLEActivity extends Activity {
private static Context mContext;// 上下文
private static final String TAG = BLEActivity.class.getSimpleName();// 標志
private SharedPreferences sp = null;
private BluetoothAdapter mBluetoothAdapter = null;// 本地藍牙設備
private Handler mHandler = null;// 用於postDelay
private boolean mScanning = false;// 循環標志位
private static final long SCAN_PERIOD = 10000;// 掃描10s
private static final int REQUEST_ENABLE_BT = 1;// 請求碼
private ListView mListView = null;
private BLEAdapter mAdapter = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ble);
if (!checkBluetooth()) {
finish();
}
init();
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
// 為了確保設備上藍牙能使用, 如果當前藍牙設備沒啟用,彈出對話框向用戶要求授予權限來啟用
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
mAdapter = new BLEAdapter(mContext);
mListView.setAdapter(mAdapter);
if (mBluetoothAdapter.isEnabled()) {
scanLeDevice(true);
}
}
@Override
protected void onPause() {
super.onPause();
scanLeDevice(false);
mAdapter.clear();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
suiside();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
if (requestCode == REQUEST_ENABLE_BT
&& resultCode == Activity.RESULT_CANCELED) {
finish();
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
if (!mScanning) {
menu.findItem(R.id.menu_stop).setVisible(false);
menu.findItem(R.id.menu_scan).setVisible(true);
menu.findItem(R.id.menu_refresh).setActionView(null);
} else {
menu.findItem(R.id.menu_stop).setVisible(true);
menu.findItem(R.id.menu_scan).setVisible(false);
menu.findItem(R.id.menu_refresh).setActionView(
R.layout.actionbar_indeterminate_progress);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_scan:
mAdapter.clear();
scanLeDevice(true);
break;
case R.id.menu_stop:
scanLeDevice(false);
break;
}
return true;
}
/**
* 判斷是否支持藍牙和BLE
*
* @return
*/
private boolean checkBluetooth() {
// 判斷是否支持BLE
if (!getPackageManager().hasSystemFeature(
PackageManager.FEATURE_BLUETOOTH_LE)) {
toast(ble not supported);
return false;
}
// 初始化BluetoothAdapter
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// 檢查設備上是否支持藍牙不支 持就退出程序
if (mBluetoothAdapter == null) {
toast(bluetooth not supported);
return false;
}
return true;
}
/**
* 初始化數據
*/
private void init() {
mContext = this;
mHandler = new Handler();
sp = getSharedPreferences(Constant.SP_NAME, Context.MODE_PRIVATE);
mListView = (ListView) findViewById(R.id.lv_device_ble);
mListView.setOnItemClickListener(mItemClickListener);
}
/**
* 列表單擊事件
*/
private OnItemClickListener mItemClickListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterViewarg0, View arg1, int position,
long arg3) {
// TODO Auto-generated method stub
/**
* 跳轉到BLEService 傳遞一個參數 一個地址 並把名字和地址保存起來
*/
BluetoothDevice mDevice = mAdapter.getDevice(position);
toast(mDevice.getAddress());
saveDeviceAddress(mDevice.getAddress());
startTheService();
finish();
}
};
/**
* 啟動BLE通信服務
*/
private void startTheService() {
Intent service = new Intent();
service.setClass(mContext, BLEService.class);
startService(service);
}
/**
* 把地址保存起來 以便服務可以使用
*
* @param address
*/
private void saveDeviceAddress(String address) {
Editor editor = sp.edit();
editor.putString(Constant.KEY_DEVICE_ADDRESS, address);
editor.commit();
}
/**
* 吐絲
*
* @param text
*/
private void toast(String text) {
Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
}
/**
* 掃描BLE設備
*
* @param enable
*/
private void scanLeDevice(final boolean enable) {
if (enable) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
invalidateOptionsMenu();
}
/**
* BLE掃描回調函數,設備保存在remoteDevice裡面
*/
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
// TODO Auto-generated method stub
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.addDevice(device);
mAdapter.notifyDataSetChanged();
}
});
}
};
/**
* 自殺
*/
private void suiside() {
scanLeDevice(false);
sp = null;
}
}
BLEAdapter.java
package com.study.blestudy;
import java.util.ArrayList;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
/**
* @date 2015-07-22
* @detail 設備列表適配器
* @author Leo
*
*/
@SuppressLint(InflateParams)
public class BLEAdapter extends BaseAdapter {
private ArrayList
mLeDevices;
private LayoutInflater mInflater;
public BLEAdapter(Context context) {
mLeDevices = new ArrayList();
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mLeDevices.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
if (mLeDevices.size() <= arg0) {
return null;
}
return mLeDevices.get(arg0);
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
@Override
public View getView(int position, View view, ViewGroup arg2) {
// TODO Auto-generated method stub
ViewHolder viewHolder;
if (null == view) {
viewHolder = new ViewHolder();
view = mInflater.inflate(R.layout.item_ble, null);
viewHolder.deviceName = (TextView) view
.findViewById(R.id.device_name);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
BluetoothDevice device = mLeDevices.get(position);
final String deviceName = device.getName();
if (deviceName != null && deviceName.length() > 0)
viewHolder.deviceName.setText(deviceName);
else
viewHolder.deviceName.setText(unknown name);
return view;
}
/**
* 列表顯示控件類
*
* @author Leo
*
*/
private class ViewHolder {
public TextView deviceName;
}
/**
* 設置數據源
*
* @param mDevices
*/
public void setData(ArrayList mDevices) {
this.mLeDevices = mDevices;
}
/**
* 添加設備
*
* @param mDevice
*/
public void addDevice(BluetoothDevice mDevice) {
if (!mLeDevices.contains(mDevice)) {
mLeDevices.add(mDevice);
}
}
/**
* 得到設備
*
* @param position
* @return
*/
public BluetoothDevice getDevice(int position) {
if (mLeDevices.size() <= position) {
return null;
}
return mLeDevices.get(position);
}
/**
* 清空設備
*/
public void clear() {
mLeDevices.clear();
}
}
BLEService.java
package com.study.blestudy;
import java.util.List;
import android.annotation.SuppressLint;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
/**
* @date 2015-07-22
* @detail BLE連接通信
* @author Leo
*
*/
@SuppressLint(NewApi)
public class BLEService extends Service {
private static byte[] testData = { 1, 2, 3 };
private static Context mContext;// 上下文
private static final String TAG = BLEService.class.getSimpleName();// TAG
private BluetoothManager mBluetoothManager = null;// 藍牙管理器
private BluetoothAdapter mBluetoothAdapter = null;// 本地設備
private String mBluetoothDeviceAddress = null;// 遠程設備地址
private BluetoothGatt mBluetoothGatt = null;// GATT通信
private BluetoothGattCharacteristic mCharacteristic = null;// 可讀寫可通知的
private SharedPreferences sp = null;
private static final boolean AUTO_CONNECT = true;// 是否自動連接
private static final boolean NOTIFICATION_ENABLED = true;
private int mConnectionState = STATE_DISCONNECTED;// 連接狀態
private static final int STATE_DISCONNECTED = 0;// 斷開連接
private static final int STATE_CONNECTING = 1;// 連接中
private static final int STATE_CONNECTED = 2;// 已連接
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
init();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
suiside();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
// 如果地址不為空就嘗試連接 如果為空就跳到BLEActivity讓用戶去選擇BLE設備
if (mBluetoothDeviceAddress != null) {
if (connect(mBluetoothDeviceAddress)) {
} else {
}
} else {
Intent bleIntent = new Intent();
bleIntent.setClass(mContext, BLEActivity.class);
bleIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(bleIntent);
}
// return super.onStartCommand(intent, flags, startId);
return Service.START_STICKY;
}
/**
* 各種初始化信息
*/
private void init() {
mContext = this;
if (!initBluetooth()) {
stopSelf();
}
sp = getSharedPreferences(Constant.SP_NAME, Context.MODE_PRIVATE);
mBluetoothDeviceAddress = sp.getString(Constant.KEY_DEVICE_ADDRESS,
null);
}
/**
* 吐絲
*/
private void toast(String text) {
Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
}
/**
* 初始化BluetoothManager和BluetoothAdapter
*
* @return
*/
private boolean initBluetooth() {
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
return false;
}
return true;
}
/**
* 自殺
*/
private void suiside() {
disconnect();
close();
try {
if (mBluetoothAdapter != null) {
mBluetoothAdapter.disable();
mBluetoothAdapter = null;
mBluetoothManager = null;
sp = null;
}
} catch (Exception e) {
toast(關閉藍牙失敗,請手動關閉);
}
}
/**
* 關閉通信
*/
private void close() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
/**
* 建立通信連接
*
* @param address
* @return
*/
private boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
return false;
}
if (mBluetoothDeviceAddress != null
&& address.equals(mBluetoothDeviceAddress)
&& mBluetoothGatt != null) {
if (mBluetoothGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter
.getRemoteDevice(address);
if (device == null) {
return false;
}
mBluetoothGatt = device.connectGatt(this, AUTO_CONNECT, mGattCallback);
mBluetoothDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
/**
* 斷開GATT連接
*/
private void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
mBluetoothGatt.disconnect();
}
/**
* GATT通信回調函數
*/
@SuppressLint(NewApi)
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
// TODO Auto-generated method stub
// super.onCharacteristicChanged(gatt, characteristic);
System.out.println(我收到的: + new String(characteristic.getValue()));
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
// TODO Auto-generated method stub
super.onCharacteristicRead(gatt, characteristic, status);
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
// TODO Auto-generated method stub
super.onCharacteristicWrite(gatt, characteristic, status);
}
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
// TODO Auto-generated method stub
// super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
if (mBluetoothGatt != null)
mBluetoothGatt.discoverServices();
mConnectionState = STATE_CONNECTED;
System.out.println(state connected);
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
// connect(mBluetoothDeviceAddress);
mConnectionState = STATE_DISCONNECTED;
System.out.println(state disconnected);
}
}
@Override
public void onDescriptorRead(BluetoothGatt gatt,
BluetoothGattDescriptor descriptor, int status) {
// TODO Auto-generated method stub
super.onDescriptorRead(gatt, descriptor, status);
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt,
BluetoothGattDescriptor descriptor, int status) {
// TODO Auto-generated method stub
super.onDescriptorWrite(gatt, descriptor, status);
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
// TODO Auto-generated method stub
super.onReadRemoteRssi(gatt, rssi, status);
}
@Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
// TODO Auto-generated method stub
super.onReliableWriteCompleted(gatt, status);
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
// TODO Auto-generated method stub
// super.onServicesDiscovered(gatt, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
if (mBluetoothGatt != null) {
BluetoothGattService mGattService = mBluetoothGatt
.getService(SampleGattAttributes.UUID_SERVICE);
mCharacteristic = mGattService
.getCharacteristic(SampleGattAttributes.UUID_CHARACTERISTIC);
List mDescriptors = mCharacteristic
.getDescriptors();
for (BluetoothGattDescriptor mDescriptor : mDescriptors) {
System.out.println(mDescriptor.getUuid().toString());
}
setCharacteristicNotification(mCharacteristic,
NOTIFICATION_ENABLED);
wirteToBLE(testData);
System.out.println(new String(readFromBLE()));
wirteToBLE(testData);
System.out.println(new String(readFromBLE()));
}
}
}
};
/**
* 設置後可以使用通知 設備給手機發送通知時可觸發onCharacteristicChanged()
*
* @param characteristic
* @param enabled
*/
private void setCharacteristicNotification(
BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return;
}
mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor descriptor = characteristic
.getDescriptor(SampleGattAttributes.UUID_DESCRIPTOR);
if (descriptor != null) {
descriptor
.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
}
/**
* 獲取此實例
*
* @return
*/
public static BLEService self() {
if (mContext != null)
return (BLEService) mContext;
return null;
}
/**
* 通信接口 通過此函數即可向BLE設備寫入數據
*
* @param value
* @return
*/
public boolean wirteToBLE(byte[] value) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, BluetoothAdapter not initialized);
return false;
}
mCharacteristic.setValue(value);
boolean isSuccess = mBluetoothGatt.writeCharacteristic(mCharacteristic);
return isSuccess;
}
/**
* 通信接口 從BLE設備讀數據
*
* @return
*/
public byte[] readFromBLE() {
byte[] value = null;
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
return null;
}
boolean isSuccess = mBluetoothGatt.readCharacteristic(mCharacteristic);
if (isSuccess) {
value = mCharacteristic.getValue();
}
return value;
}
}
五、小結
BLE編程,最重要的不是代碼,而是理解其工作模式和編程步驟。工作模式呢,其實就是中心設備和外圍設備,其次就是他的GATT/ATT通信。
編程步驟呢:
步驟:
1、開始准備(包括:添加權限,判斷支持,打開藍牙)
2、掃描設備(掃描BLE設備)
3、建立連接(能過地址,並建立GATT連接)
4、列舉服務(列舉BLE設備開啟了哪些服務,並找出相關特征)
5、開始通信(讀寫數據,通知等)
6、關閉連接