首先,先简单介绍一下ble的特征(注意:蓝牙4.0只有android4.3或4.3以上才支持)html
1.BLE(Bluetooth Low Energy),蓝牙4.0核心profile,主要特色是快速搜索,快速链接,超低功耗保持链接和数据传输,缺点:数据传输速率低,因为其具备低功耗特色,因此常常用在可穿戴设备之中。android
2.关于BLE数据传输:api
a.profile能够理解为一种规范,一个标准的通讯协议,其存在于手机中,蓝牙组织规定了一些标准的profile:HID OVER GATT ,防丢器等,每一个profile中包含了多个service。app
b.service 能够理解为一个服务,在BLE从机中有多个服务,电量信息,系统服务信息等,每个service中包含了多个characteristic特征值,每个具体的characteristic特征值才是BLE通讯的主题。ide
c.characteristic特征值:BLE主机从机通讯均是经过characteristic进行,能够将其理解为一个标签,经过该标签能够读取或写入相关信息。函数
d. UUID(统一标识码):service和characteristic均须要这个惟一的UUID进行标识。工具
e. 角色和职责,看到这里我以为您老人家应该知道了,就是中心设备和外围设备(GATT server vs. GATT client.),不过呢在这里我就不这样说了,其实也不太懂那么的官方说法,我就简单粗暴点就是运用了ble的app和ble设备之间的通讯,当app搜索到了ble设备,app会收到ble反馈过来的信息好比电量什么的,对于怎么得来的不用说都知道确定是在一个规范好的一个对象中啦(先不须要知道这个对象是什么鬼东西由于我也不知道,官方叫characteristic也就是上面说的特征值),相反咱们app也能够经过写入一些信息到这个对象(characteristic)发送给设备,设备收到以后就会执行咱们的要它作的动做了。其实也就和日常咱们的对象赋值同样(setValue("fuzhi")),只是方法不一样而已,一个是set一个是write。ui
最后来举个例子简答说明一下:其实说白了characteristic特征值就比如一支球队的各个球员,service比如这个球队的名称,profile就当国家吧,假如咱们要找到某一个球员,世界这么多国家第一须要知道是哪一个国家的,第二须要知道是哪一个球队的,最后才知道是那个球员,只有这样最后才能了解这个球员的一些信息(相似从ble设备获取信息),相反也只有这样找到球员后告诉这个球员应该怎么打球的(相似对ble设备设置信息)。例子很难懂吧,若是你看懂了说明你和我同样小学毕业,看不懂的话就直接看代码吧,由于本人小学毕业,识字很少,脑壳不能转太快,怕翻车,,,this
/****************************************************代码块*****************************************************.net
一、 权限和相关属性这是最基本的啦
<uses-featureandroid:name="android.hardware.bluetooth_le"android:required="true"/>
<uses-permissionandroid:name="android.permission.BLUETOOTH"/>
<uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN"/>
二、初始化蓝牙,这个方法通常能够写在项目的启动activity,否则怕在写完ble代码执行后发现没有打开蓝牙还须要手动去打开对项目体验感很差,固然只要您老人家开心,写不写均可以。
private void initBluetooth() {
BluetoothManager mBluetoothManager = (BluetoothManager) this.getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager != null) {
BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter != null) {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable(); //打开蓝牙
}
}
}
}
三、获取本地ble对象(BluetoothAdapter),它对应本地Android设备的蓝牙模块,可能这么称呼为本地ble对象不太准确,但我老人家开心这么称呼。今后段代码开始能够把这些有关ble通讯的代码写到一个class中当作一个ble工具class,以便代码清晰查看和方便调用。这里咱们就当这个工具类叫BleManager
private BluetoothAdapter mBluetoothAdapter;
private BluetoothDevice mBluetoothDevice;
private BluetoothGatt mBluetoothGatt;
private boolean isScanning = false;
//以上所定义的对象在下面的方法中都有用到,(建议在看蓝牙这方面的东西时,无论看谁的文章,都先把以上或者还有些蓝牙基本用的对象先熟悉是什么意思和基本做用)。
private BleManager(Context context) {
this.mContext = context;
BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); //BluetoothManager只在android4.3以上有
if (bluetoothManager == null) {
TLog.e(TAG, "Unable to initialize BluetoothManager.");
return;
}
mBluetoothAdapter = bluetoothManager.getAdapter();
}
四、既然得到了BluetoothAdapter对象,那么接下来就能够搜索ble设备了,这时就须要用到BluetoothAdapter的startLeScan()这个方法了
public void startLeScan() {
if (mBluetoothAdapter == null) {
return;
}
if (isScanning) {
return;
}
isScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback); //此mLeScanCallback为回调函数
mHandler.sendEmptyMessageDelayed(STOP_LESCAN, 10000); //这个搜索10秒,若是搜索不到则中止搜索
}
在4.3以前的api是经过注册广播来处理搜索时发生的一些事件,而支持ble的新的api中,是经过回调的方式来处理的,而mLeScanCallback就是一个接口对象
private LeScanCallback mLeScanCallback = new LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int arg1, byte[] arg2) {
TLog.i(TAG, "onLeScan() DeviceName------>"+device.getName()); //在这里可经过device这个对象来获取到搜索到的ble设备名称和一些相关信息
if(device.getName() == null){
return;
}
if (device.getName().contains("Ble_Name")) { //判断是否搜索到你须要的ble设备
TLog.i(TAG, "onLeScan() DeviceAddress------>"+device.getAddress());
mBluetoothDevice = device; //获取到周边设备
stopLeScan(); //一、当找到对应的设备后,当即中止扫描;二、不要循环搜索设备,为每次搜索设置适合的时间限制。避免设备不在可用范围的时候持续不停扫描,消耗电量。
connect(); //链接
}
}
};
//
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case STOP_LESCAN:
T.showLong(mContext, mContext.getResources().getString(R.string.msg_connect_failed));
mBluetoothAdapter.stopLeScan(mLeScanCallback);
broadcastUpdate(Config.ACTION_GATT_DISCONNECTED);
isScanning = false;
TLog.i(TAG, "Scan time is up");
break;
}
};
};
五、搜索到固然就是链接了,就是上面那个connect()方法了
public boolean connect() {
if (mBluetoothDevice == null) {
TLog.i(TAG, "BluetoothDevice is null.");
return false;
}
//两个设备经过BLE通讯,首先须要创建GATT链接。这里咱们讲的是Android设备做为client端,链接GATT Server
mBluetoothGatt = mBluetoothDevice.connectGatt(mContext, false, mGattCallback); //mGattCallback为回调接口
if (mBluetoothGatt != null) {
if (mBluetoothGatt.connect()) {
TLog.d(TAG, "Connect succeed.");
return true;
} else {
TLog.d(TAG, "Connect fail.");
return false;
}
} else {
TLog.d(TAG, "BluetoothGatt null.");
return false;
}
}
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices(); //执行到这里其实蓝牙已经链接成功了
TLog.i(TAG, "Connected to GATT server.");
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
if(mBluetoothDevice != null){
TLog.i(TAG, "从新链接");
connect();
}else{
TLog.i(TAG, "Disconnected from GATT server.");
}
}
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
TLog.i(TAG, "onServicesDiscovered");
getBatteryLevel(); //获取电量
} else {
TLog.i(TAG, "onServicesDiscovered status------>" + status);
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
TLog.d(TAG, "onCharacteristicRead------>" + Utils.bytesToHexString(characteristic.getValue()));
//判断UUID是否相等
if (Values.UUID_KEY_BATTERY_LEVEL_CHARACTERISTICS.equals(characteristic.getUuid().toString())) {
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
TLog.d(TAG, "onCharacteristicChanged------>" + Utils.bytesToHexString(characteristic.getValue()));
//判断UUID是否相等
if (Values.UUID_KEY_BATTERY_LEVEL_CHARACTERISTICS.equals(characteristic.getUuid().toString())) {
}
}
//接受Characteristic被写的通知,收到蓝牙模块的数据后会触发onCharacteristicWrite
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
TLog.d(TAG,"status = " + status);
TLog.d(TAG, "onCharacteristicWrite------>" + Utils.bytesToHexString(characteristic.getValue()));
}
};
public void getBatteryLevel() {
BluetoothGattCharacteristic batteryLevelGattC = getCharcteristic(
Values.UUID_KEY_BATTERY_LEVEL_SERVICE, Values.UUID_KEY_BATTERY_LEVEL_CHARACTERISTICS);
if (batteryLevelGattC != null) {
readCharacteristic(batteryLevelGattC);
setCharacteristicNotification(batteryLevelGattC, true); //设置当指定characteristic值变化时,发出通知。
}
}
六、获取服务与特征
//a.获取服务
public BluetoothGattService getService(UUID uuid) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
TLog.e(TAG, "BluetoothAdapter not initialized");
return null;
}
return mBluetoothGatt.getService(uuid);
}
//b.获取特征
private BluetoothGattCharacteristic getCharcteristic(String serviceUUID, String characteristicUUID) {
//获得服务对象
BluetoothGattService service = getService(UUID.fromString(serviceUUID)); //调用上面获取服务的方法
if (service == null) {
TLog.e(TAG, "Can not find 'BluetoothGattService'");
return null;
}
//获得此服务结点下Characteristic对象
final BluetoothGattCharacteristic gattCharacteristic = service.getCharacteristic(UUID.fromString(characteristicUUID));
if (gattCharacteristic != null) {
return gattCharacteristic;
} else {
TLog.e(TAG, "Can not find 'BluetoothGattCharacteristic'");
return null;
}
}
//获取数据
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
TLog.e(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
TLog.e(TAG, "BluetoothAdapter not initialized");
return false;
}
return mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
}
七、写入数据,在上面的方法中咱们已经获得了设备服务和服务里的特征characteristic,那么就能够对这个特征写入或者说是赋值
public void write(byte[] data) { //通常都是传byte
//获得可写入的characteristic Utils.isAIRPLANE(mContext) &&
if(!mBleManager.isEnabled()){
TLog.e(TAG, "writeCharacteristic 开启飞行模式");
//closeBluetoothGatt();
isGattConnected = false;
broadcastUpdate(Config.ACTION_GATT_DISCONNECTED);
return;
}
BluetoothGattCharacteristic writeCharacteristic = getCharcteristic(Values.UUID_KEY_SERVICE, Values.UUID_KEY_WRITE); //这个UUID都是根据协议号的UUID
if (writeCharacteristic == null) {
TLog.e(TAG, "Write failed. GattCharacteristic is null.");
return;
}
writeCharacteristic.setValue(data); //为characteristic赋值
writeCharacteristicWrite(writeCharacteristic);
}
public void writeCharacteristicWrite(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
TLog.e(TAG, "BluetoothAdapter not initialized");
return;
}
TLog.e(TAG, "BluetoothAdapter 写入数据");
boolean isBoolean = false;
isBoolean = mBluetoothGatt.writeCharacteristic(characteristic);
TLog.e(TAG, "BluetoothAdapter_writeCharacteristic = " +isBoolean); //若是isBoolean返回的是true则写入成功
}
八、写到这其实基本差很少了,最后再就是在activity中调用了,其实在调用的时候直接在须要搜索蓝牙的activity调用startLeScan()这个方法就能够了,至于搜索到的结果也显示在这个方法里面了,找到了对应的设备名称而后再链接,对于中间一系列的回调函数,不论是成功仍是失败都是根据您老人家的实际项目需求去写的,你能够用一个广播把回调信息发送出来到activity,告诉activity应该作什么........
举个简单的例子:
在MainActivity调用搜索蓝牙的方法
public class MainActivity extends Activity{
private BleManager manager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
manager = new BleManager(this); //这个this是一个上下文,只要在上面的BleManager工具类定义一个有参数就好
manager.startLeScan(); //调用此方法,若是搜索到有设备则天然的去链接它了,到时候链接时回回调mGattCallback 这个回调函数,若是成功你能够发送一个广播出来提醒用户蓝牙与设备链接成功
}
搜索成功后,你就能够根据你的须要写入信息传送了。简单说说,就是你在一个button事件中调用上面的write(byte[] byte)这个方法,对于里面的参数byte就是根据大家所设置的byte了,最后写入的成功与否就看writeCharacteristicWrite这个方法下面的返回值是true仍是false了,true表示成成功。
九、总结了,菜鸟我其实也刚接触蓝牙不久,也是看了一些文章,而后结合本身的一些总结,写出了这么一篇小学生文章(也是想为本身增长一些印象),请各位老人家们多多理解,固然要是有哪位大神看不过去或者以为那里不对了请指教出来,不要让小菜鸟一直错下去,谢谢!