• android5.0(Lollipop) BLE Peripheral牛刀小试


    转载请表明作者:http://blog.csdn.net/lansefeiyang08/article/details/46468743

    知道Android L对蓝牙对了一些改进,包括添加A2dp sink、HFP client、BLE Peripheral功能等等。

    我花了一天多时间对Android L BLE Peripheral SDK进行了研究,网上的资料很少,有一个介绍的还不够清晰,所以就自己写了一个测试应用,希望可以对理解BLE Peripheral有一定的帮助。

    此贴主要以讲解代码为主,我会把项目代码也传到CSDN中,帮助大家测试。

    首先说明一点,并不是Android L的系统就可以支持BLE Peripheral,这个和硬件也是有关系的(以前有人告诉我支持BLE Peripheral是纯软件的东西,要不就是扯淡,要不就是我测得有问题)。我用我手上的Pad(支持BLE central,android5.0)发现直接不支持,Android5.0 SDK已经开始支持check手机是否支持BLE Peripheral,后面代码会提到。

    好了,下面我就直接上代码了。为了代码简单整洁,我用一个Activity来完成最基本的功能,如果还有其他需求,只要稍微改一下就可以了。

    我在写这个代码的时候,第一个困惑是BLE Peripheral操作流程是什么?代码流程怎么写?我相信大家和我应该是一样的困惑。所以我不全部贴代码(我上传后,代码直接下载好了)。我按照流程给大家说一下我写的思路。

    首先,我去查SDK的接口,我发现在android L SDK中多了一个package:android.bluetooth.le;里面多了Peripheral和Scanner,Scanner我会后面更新。

    第二步开始写代码,代码里首先检查是否支持BLE、BLE Peripheral。代码如下:

    1. private void init(){  
    2.     if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){  
    3.         Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_LONG).show();  
    4.         finish();  
    5.     }  
    6.       
    7.     final BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);  
    8.     mBluetoothAdapter = mBluetoothManager.getAdapter();  
    9.       
    10.     if(mBluetoothAdapter ==  null){  
    11.         Toast.makeText(this, R.string.bluetooth_not_supported, Toast.LENGTH_LONG).show();  
    12.         finish();  
    13.     }  
    14.       
    15.     mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();  
    16.     if(mBluetoothLeAdvertiser == null){  
    17.         Toast.makeText(this, "the device not support peripheral", Toast.LENGTH_SHORT    ).show();  
    18.         Log.e(TAG, "the device not support peripheral");  
    19.         finish();  
    20.     }  
    21. }  

    前几段代码我就不说了,搞过BLE的基本都是通用的,但是你会发现在代码里多了一句

    1. mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();  

    这一句代码会直接判断你的设备到底支持不支持BLE Peripheral。假如此返回值非空,你才可以继续有机会开发,如果返回空,那说明你的设备搞不了BLE Peripheral(当然,我的代码里没有判断是否打开了蓝牙,这个为了节省时间,你们自己可以添加上)。

    支持不支持BLE Peripheral,你也可以用BluetoothAdapter类的isMultipleAdvertisementSupported()函数去check,实际上getBluetoothLeAdvetiser()也会执行上面的isMultipleAdvertisementSupported函数,所以我就直接一步到位了,但是原理大家要懂。

    第三,你的设备已经支持BLE Peripheral了,那么下一步就是要考虑我怎么发广播了。但是你在发广播之前,要先准备自己的数据,比如你自己是什么service,里面有什么data等等。

    我们先来看看发广播的函数长得什么样子:

    1. mBluetoothLeAdvertiser.startAdvertising(createAdvSettings(true, 0), createAdvertiseData(), mAdvertiseCallback);  

    从广播函数应该可以看到所需要的参数,一个是广播设置参数,一个是广播数据,还有一个是Callback。当然startAdvertising有两种格式,另外一种可以获得广播数据的response。

    下面我们来看一下AdvertiseSettings:

    1. /** create AdvertiseSettings */  
    2.  public static AdvertiseSettings createAdvSettings(boolean connectable, int timeoutMillis) {  
    3.      AdvertiseSettings.Builder mSettingsbuilder = new AdvertiseSettings.Builder();  
    4.      mSettingsbuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED);  
    5.      mSettingsbuilder.setConnectable(connectable);  
    6.      mSettingsbuilder.setTimeout(timeoutMillis);  
    7.      mSettingsbuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);  
    8.      AdvertiseSettings mAdvertiseSettings = mSettingsbuilder.build();  
    9.         if(mAdvertiseSettings == null){  
    10.             if(D){  
    11.                 Toast.makeText(mContext, "mAdvertiseSettings == null", Toast.LENGTH_LONG).show();  
    12.                 Log.e(TAG,"mAdvertiseSettings == null");  
    13.             }  
    14.         }  
    15.     return mAdvertiseSettings;  
    16.  }  

    这里面一共有四个参数,AdvertiseMode、Connectable、Timeout、TxPowerLevel。当然我们可以设置我们需要的,其他的参数会使用默认的值。

    再就是格式很重要,我们一定要是AdvertiseSettings.builder,不然你只能设置一个参数。

    再就是AdvertiseData:

    1. public static AdvertiseData createAdvertiseData(){         
    2.     AdvertiseData.Builder    mDataBuilder = new AdvertiseData.Builder();  
    3.     mDataBuilder.addServiceUuid(ParcelUuid.fromString(HEART_RATE_SERVICE));  
    4.     AdvertiseData mAdvertiseData = mDataBuilder.build();  
    5.     if(mAdvertiseData==null){  
    6.         if(D){  
    7.             Toast.makeText(mContext, "mAdvertiseSettings == null", Toast.LENGTH_LONG).show();  
    8.             Log.e(TAG,"mAdvertiseSettings == null");  
    9.         }  
    10.     }  
    11.       
    12.     return mAdvertiseData;  
    13. }  

    这里面就需要设置很多参数了,我这里为了简单,只广播心跳的UUID,但是没有数据。如果你们有自己的数据等等,可以再这里面去设置,自定义函数也在AdvertiseData类里。

    最后一步就是准备Callback函数:

    1. private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {  
    2.     @Override  
    3.       public void onStartSuccess(AdvertiseSettings settingsInEffect) {  
    4.         super.onStartSuccess(settingsInEffect);  
    5.          if (settingsInEffect != null) {  
    6.              Log.d(TAG, "onStartSuccess TxPowerLv=" + settingsInEffect.getTxPowerLevel()     + " mode=" + settingsInEffect.getMode()  
    7.              + " timeout=" + settingsInEffect.getTimeout());  
    8.              } else {  
    9.              Log.e(TAG, "onStartSuccess, settingInEffect is null");  
    10.              }  
    11.             Log.e(TAG,"onStartSuccess settingsInEffect" + settingsInEffect);  
    12.           
    13.         }  
    14.       
    15.     @Override  
    16.     public void onStartFailure(int errorCode) {  
    17.         super.onStartFailure(errorCode);  
    18.         if(D)   Log.e(TAG,"onStartFailure errorCode" + errorCode);  
    19.           
    20.         if(errorCode == ADVERTISE_FAILED_DATA_TOO_LARGE){  
    21.             if(D){  
    22.                 Toast.makeText(mContext, R.string.advertise_failed_data_too_large, Toast.LENGTH_LONG).show();  
    23.                 Log.e(TAG,"Failed to start advertising as the advertise data to be broadcasted is larger than 31 bytes.");  
    24.             }  
    25.         }else if(errorCode == ADVERTISE_FAILED_TOO_MANY_ADVERTISERS){  
    26.             if(D){  
    27.                 Toast.makeText(mContext, R.string.advertise_failed_too_many_advertises, Toast.LENGTH_LONG).show();  
    28.                 Log.e(TAG,"Failed to start advertising because no advertising instance is available.");  
    29.             }  
    30.         }else if(errorCode == ADVERTISE_FAILED_ALREADY_STARTED){  
    31.             if(D){  
    32.                 Toast.makeText(mContext, R.string.advertise_failed_already_started, Toast.LENGTH_LONG).show();  
    33.                 Log.e(TAG,"Failed to start advertising as the advertising is already started");  
    34.             }  
    35.         }else if(errorCode == ADVERTISE_FAILED_INTERNAL_ERROR){  
    36.             if(D){  
    37.                 Toast.makeText(mContext, R.string.advertise_failed_internal_error, Toast.LENGTH_LONG).show();  
    38.                 Log.e(TAG,"Operation failed due to an internal error");  
    39.             }  
    40.         }else if(errorCode == ADVERTISE_FAILED_FEATURE_UNSUPPORTED){  
    41.             if(D){  
    42.                 Toast.makeText(mContext, R.string.advertise_failed_feature_unsupported, Toast.LENGTH_LONG).show();  
    43.                 Log.e(TAG,"This feature is not supported on this platform");  
    44.             }  
    45.         }  
    46.     }  
    47. };  

    当你广播成功,会受到onStartSuccess的回调,回调的参数也是AdvertiseSettings设置的参数。如果你还有你自己想做的,可以再这里面去做。

    为了大家方便,我把errorcode可能遇到的问题,都做了判断,只有这五种错误情况。

    最后一步就是关闭了,开了广播要关闭,不然会造成未知问题:

    1. private void stopAdvertise() {  
    2.      if (mBluetoothLeAdvertiser != null) {  
    3.          mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);  
    4.          mBluetoothLeAdvertiser = null;  
    5.      }  
    6.  }  

    ok,代码就是这么简单,只要熟悉流程就可以搞定。希望对大家有帮助。

    代码路径为:http://download.csdn.net/detail/lansefeiyang08/8799027

  • 相关阅读:
    Java实现分布式锁
    Java中拦截器实、过滤器和监听器的实现原理
    Version 28 (intended for Android Pie and below) is the last version of the legacy support library
    AndroidManifest.xml文件报Activity supporting ACTION_VIEW is not set as BROWSABLE
    flowable 流程图片中文乱码
    java 常用工具类 (值得收藏)
    Oracle 创建表空间和用户脚本
    spring cloud alibaba springboot nacos 版本对应
    Tomcat 配置支持不同的域名访问各自不同程序的配置方法
    flowable 表结构说明
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/8677982.html
Copyright © 2020-2023  润新知