zoukankan      html  css  js  c++  java
  • android ble蓝牙开发略解

    Android 蓝牙4.0开发

     

    1、  权限和相关属性

    “android:required="true"表示apk只有在具有bluetooth_le属性的系统里运行,这个4.3之前android系统没有

    <uses-featureandroid:name="android.hardware.bluetooth_le"android:required="true"/>

      

    <uses-permissionandroid:name="android.permission.BLUETOOTH"/>

    <uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN"/>

     

    2、  程序开妈操作蓝牙之前,先判断ble是否支持

    if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {

                Toast.makeText(this,R.string.ble_not_supported, Toast.LENGTH_SHORT).show();

                finish();

            }

    3、  打开、关闭蓝牙

    先获取蓝牙的一个代理

    final BluetoothManager bluetoothManager =

                    (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);

           mBluetoothAdapter = bluetoothManager.getAdapter();

     

    发intent通知系统打开蓝牙

    if(!mBluetoothAdapter.isEnabled()) {

                if (!mBluetoothAdapter.isEnabled()){

                    Intent enableBtIntent = newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

                   startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

                }

            }

     

    也可以使用 enable 和disable函数来打开关闭

    4、  搜索ble设备

    mHandler.postDelayed(newRunnable() {

                    @Override

                    public void run() {

                        mScanning = false;

                       mBluetoothAdapter.stopLeScan(mLeScanCallback);

                       

                    }

                }, SCAN_PERIOD);

     

                mScanning = true;

               mBluetoothAdapter.startLeScan(mLeScanCallback);

     

    //SCAN_PERIOD是10000,表示每次的搜索时间为10秒

    需要注意的是mLeScanCallback,在4.3之前的api是通过注册广播来处理搜索时发生的一些事件,而支持ble的新的api中,是通过回调的方式来处理的,mLeScanCallback就是一个接口对象,看一下实现:

    privateBluetoothAdapter.LeScanCallback mLeScanCallback =

                newBluetoothAdapter.LeScanCallback() {

     

            @Override

            public void onLeScan(finalBluetoothDevice device, int rssi, byte[] scanRecord) {

                runOnUiThread(new Runnable() {

                    @Override

                    public void run() {

                        mLeDeviceListAdapter.addDevice(device);

                       mLeDeviceListAdapter.notifyDataSetChanged();

                    }

                });

            }

    };

    5、  连接

    4.3之前的api是通过socket方式在蓝牙之间互相通信,连接的结果是返回一个socket对象

    在支持4.0蓝牙的新的api中,返回的是BluetoothGatt对象

    可以将BluetoothGatt对象看成是远程设备的一个代理

    mBluetoothGatt = device.connectGatt(this, false,mGattCallback);

     

    mGattCallback是一个抽象类对象,之前的广播形式,在新的api中都改成了回调

    BluetoothGattCallback抽象类,只有9个方法,字面意思就都可以看懂,在处理连接事件上,需要处理方法:

    public voidonConnectionStateChange(BluetoothGatt gatt, int status,

                                            intnewState)

     

    条件:if (newState ==BluetoothProfile.STATE_CONNECTED)

    else if (newState ==BluetoothProfile.STATE_DISCONNECTED)分别表示已连接和已断开

    6、 通讯

    这一点与之前形式上完全不一样了

    BLE分为三部分Service、Characteristic、Descriptor,这三部分都由UUID作为唯一标示符。一个蓝牙4.0的终端可以包含多个Service,一个Service可以包含多个Characteristic,一个Characteristic包含一个Value和多个Descriptor,一个Descriptor包含一个Value。

    在连接上某个终端后,可以将其每个结点的UUID全部打印出来,但每个结点不是都能读写。

    一般来说,Characteristic是手机与BLE终端交换数据的关键,Characteristic有较多的跟权限相关的字段,例如PERMISSION和PROPERTY,而其中最常用的是PROPERTY,本文所用的BLE蓝牙模块竟然没有标准的Characteristic的PERMISSION。Characteristic的PROPERTY可以通过位运算符组合来设置读写属性,例如READ|WRITE、READ|WRITE_NO_RESPONSE|NOTIFY,因此读取PROPERTY后要分解成所用的组合

    我是这么去和ble终端通信的:

    得到某个service的对象

    BluetoothGattService linkLossService =mBluetoothGatt

                                          .getService(UUID.fromString("49535343-fe7d-4ae5-8fa9-9fafd205e455"));

    一般说来,ble设备都带有几个标准的服务,其UUID已经定义好了,这些结点里的值只能读了,因为我一个一个试过了,终于找到了我的设备里可以读写的服务,其中49535343-fe7d-4ae5-8fa9-9fafd205e455就是对应这个服务的

     

    获取此服务结点下的某个Characteristic对象

    BluetoothGattCharacteristic alertLevel =linkLossService.getCharacteristic(UUID.fromString("49535343-8841-43f4-a8d4-ecbe34729bb3"));

    一般供应商会给出多个Characteristic,你需要找到到底哪个才是让你去写的,怎么找需要看对应的终端的一些开发文档之类的,在这里我经过测试已经找到我要的了

     

    设置要写的值

    alertLevel.setValue(values_on);

    这里的values_on是一个byte数组

     

    status = mBluetoothGatt.writeCharacteristic(alertLevel);

    status如果为true,表示写操作已经成功执行,BluetoothGattCallback抽象类的一个方法会被执行,如果刚好你又重写了这个方法,就可以打印一些消息了

    public void onCharacteristicWrite(BluetoothGatt gatt,

               BluetoothGattCharacteristiccharacteristic, int status)

     

    读某个Characteristic

    public void readCharacteristic(BluetoothGattCharacteristiccharacteristic) {

            if (mBluetoothAdapter == null || mBluetoothGatt == null) {

                Log.w(TAG, "BluetoothAdapter not initialized");

                return;

            }

            mBluetoothGatt.readCharacteristic(characteristic);

    }

     

    如果成功,数据会在下面的方法回调中传进来

    public voidonCharacteristicRead(BluetoothGatt gatt,

                                            BluetoothGattCharacteristic characteristic,

                                             int status)

     

    当终端有数据要传过来的时候,表面上正常的话,手机这边下面的方法会被调用

    public voidonCharacteristicRead(BluetoothGatt gatt,

                                            BluetoothGattCharacteristic characteristic,

                                             intstatus)

    这个也是可以控制的,设置descriptor的value不同,可以控制这个重写的方法是否会被调用,没有测试其他的设备,感觉这个应该是会对应不同的设备,具体设置的地方会有不同,在我这边是这么操作的:

    public void enableNotification(boolean b)

        {

        if(b)

        {

                   BluetoothGattService service =mBluetoothGatt

                                 .getService(UUID.fromString("49535343-fe7d-4ae5-8fa9-9fafd205e455"));

                 BluetoothGattCharacteristicale =service.getCharacteristic(UUID.fromString("49535343-1E4D-4BD9-BA61-23C647249616"));

                 booleanset = mBluetoothGatt.setCharacteristicNotification(ale, true);

                 Log.d(TAG," setnotification = " + set);

                 BluetoothGattDescriptordsc =ale.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));

                 byte[]bytes = {0x01,0x00};

            dsc.setValue(bytes);

            boolean success =mBluetoothGatt.writeDescriptor(dsc);

            Log.d(TAG, "writing enabledescriptor:" + success);

        }

        else

        {

                   BluetoothGattService service =mBluetoothGatt

                                 .getService(UUID.fromString("49535343-fe7d-4ae5-8fa9-9fafd205e455"));

                 BluetoothGattCharacteristicale =service.getCharacteristic(UUID.fromString("49535343-1E4D-4BD9-BA61-23C647249616"));

                 booleanset = mBluetoothGatt.setCharacteristicNotification(ale, false);

                 Log.d(TAG," setnotification = " + set);

                 BluetoothGattDescriptordsc =ale.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));

                 byte[]bytes = {0x00, 0x00};

            dsc.setValue(bytes);

            boolean success =mBluetoothGatt.writeDescriptor(dsc);

            Log.d(TAG, "writing enabledescriptor:" + success);

        }

       

        }

    7、 总结

    网上的一些资料大都以上面的命名来标识自己的文档,有必要解释一下,应该分开来看这个命题:

    android指的安装的4.3及以上版本的android系统的设备

    4.0蓝牙指的蓝牙芯片使用4.0协议的设备

    这种开发的一种标准用处是:用4.3以上android版本的手机,与4.0蓝牙穿戴式设备进行通信

    按网上的一种中央与周边的说法,手机就是中央,4.0蓝牙设备就中周边

    如果要开发4.0蓝牙,应该知道4.0蓝牙具有高速、低功耗的优点,这些优点对手机的提升不大,但对其他一些终端设备的提升就比较大。

    有意思的是,android对与4.0蓝牙通信的封装,不需要本身设备的蓝牙芯片是4.0协议的蓝牙芯片

    于是android 蓝牙4.0开发的这么一个“大环境”下的真实情景就是:一个没有必要拥有蓝牙4.0协议的蓝牙芯片的android4.3以上系统的手机,与一些4.0蓝牙协议的蓝牙芯片设备终端的故事

    以上是一些事实,以下是一些猜想

    1、 蓝牙4.0与之前版本协议之间可以通讯,说明:4.0蓝牙协议并不是修改的无线波的调制与解调,而是修改的数据的组成

    2、 对蓝牙4.0协议的支持,是由google提出的,而不是各个手机厂商提出的,说明:android系统在软件上可以一致对待不同的蓝牙芯片,不同的蓝牙芯片对同一段数据的调制解调结果是一样的,于是在这段数据通过串口传到手机主控的时候,也是一样的,在这个环境里,蓝牙芯片只是一个调制解调器,android封装了对数据全部的处理。

  • 相关阅读:
    Head first javascript(七)
    Python Fundamental for Django
    Head first javascript(六)
    Head first javascript(五)
    Head first javascript(四)
    Head first javascript(三)
    Head first javascript(二)
    Head first javascript(一)
    Sicily 1090. Highways 解题报告
    Python GUI programming(tkinter)
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4683685.html
Copyright © 2011-2022 走看看