Android

个人Android学习总结


Bluetooth 蓝牙 4.x

<p>1、[ 深入了解Android蓝牙Bluetooth ——《总结篇》](<a href="http://blog.csdn.net/androidstarjack/article/details/60781892">http://blog.csdn.net/androidstarjack/article/details/60781892</a> &quot; 深入了解Android蓝牙Bluetooth ——《总结篇》&quot;) 2、[ 深入了解Android蓝牙Bluetooth——《基础篇》](<a href="http://blog.csdn.net/androidstarjack/article/details/60468468">http://blog.csdn.net/androidstarjack/article/details/60468468</a> &quot; 深入了解Android蓝牙Bluetooth——《基础篇》&quot;) 3、[深入了解Android蓝牙Bluetooth——《进阶篇》](<a href="http://blog.csdn.net/androidstarjack/article/details/60595241">http://blog.csdn.net/androidstarjack/article/details/60595241</a> &quot;深入了解Android蓝牙Bluetooth——《进阶篇》&quot;) 4、[Android实现主动连接蓝牙耳机](<a href="http://gqdy365.iteye.com/blog/2227454">http://gqdy365.iteye.com/blog/2227454</a> &quot;Android实现主动连接蓝牙耳机&quot;)</p> <h2>BLE蓝牙设备连接读取的顺序:</h2> <p><a href="http://p1.bpimg.com/583828/4dfd76c9f9faf19a.jpg"><img src="https://www.showdoc.cc/home/common/visitfile/sign/5aec9b9c62ef1db81e17a4f5c127cfe0?showdoc=.jpg" alt="" /></a></p> <p>`蓝牙BLE4.x</p> <p>BLE分为三部分:</p> <p>Service Characteristic Descriptor</p> <p>这三部分都用UUID作为唯一标识符。UUID为这种格式:0000ffe1-0000-1000-8000-00805f9b34fb。比如有3个Service,那么就有三个不同的UUID与Service对应。这些UUID都写在硬件里,我们通过BLE提供的API可以读取到。</p> <p>一个BLE终端可以包含多个Service, 一个Service可以包含多个Characteristic,一个Characteristic包含一个value和多个Descriptor,一个Descriptor包含一个Value。Characteristic是比较重要的,是手机与BLE终端交换数据的关键,读取设置数据等操作都是操作Characteristic的相关属性。</p> <p>API相关介绍</p> <p>1.先介绍一下关于蓝牙4.0中的一些名词吧: (1)GATT(Gneric Attibute Profile)</p> <p>通过ble连接,读写属性类小数据Profile通用的规范。现在所有的ble应用Profile 都是基于GATT</p> <p>(2)ATT(Attribute Protocal) GATT是基于ATT Potocal的ATT针对BLE设备专门做的具体就是传输过程中使用尽量少的数据,每个属性都有个唯一的UUID,属性chartcteristics and Service的形式传输。 (3)Service是Characteristic的集合。 (4).Characteristic 特征类型。 比如。有个蓝牙ble的血压计。他可能包括多个Servvice,每个Service有包括多个Characteristic</p> <p>注意:蓝牙ble只能支持Android 4.3以上的系统 SDK&gt;=18</p> <p>2.以下是开发的步骤:</p> <p>2.1首先获取BluetoothManager</p> <p>2.2获取BluetoothAdapter 2.3创建BluetoothAdapter.LeScanCallback 2.4.开始搜索设备。 2.5.BluetoothDevice 描述了一个蓝牙设备 提供了getAddress()设备Mac地址,getName()设备的名称。 2.6开始连接设备 2.7连接到设备之后获取设备的服务(Service)和服务对应的Characteristic。 2.8获取到特征之后,找到服务中可以向下位机写指令的特征,向该特征写入指令。 2.9写入成功之后,开始读取设备返回来的数据。 2.10、断开连接 2.11、数据的转换方法 大概整体就是如上的步骤。但是也是要具体根据厂家的协议来实现通信的过程。</p> <p>那么具体要怎么使用呢?我们据需开车往下走。</p> <p>一.添加权限</p> <p>  和经典蓝牙一样,应用使用蓝牙,需要声明BLUETOOTH权限,如果需要扫描设备或者操作蓝牙设置,则还需要BLUETOOTH_ADMIN权限:`</p> <pre><code>&amp;lt;uses-permission android:name=&amp;quot;android.permission.BLUETOOTH&amp;quot;/&amp;gt; &amp;lt;uses-permission android:name=&amp;quot;android.permission.BLUETOOTH_ADMIN&amp;quot;/&amp;gt;</code></pre> <p><code>除了蓝牙权限外,如果需要BLE feature则还需要声明uses-feature:</code></p> <pre><code>&amp;lt;uses-feature android:name=&amp;quot;android.hardware.bluetooth_le&amp;quot; android:required=&amp;quot;true&amp;quot;/&amp;gt;</code></pre> <p><code>按时required为true时,则应用只能在支持BLE的Android设备上安装运行;required为false时,Android设备均可正常安装运行,需要在代码运行时判断设备是否支持BLE feature:</code></p> <pre><code>// Use this check to determine whether BLE is supported on the device. Then // you can selectively disable BLE-related features. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); finish(); }</code></pre> <p><code>第一步:开启蓝牙:</code></p> <p>1.首先获取有BluetoothAdapter两种方式:`</p> <pre><code>private BluetoothManager bluetoothManager; bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter();</code></pre> <p>或者是:</p> <pre><code>mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();</code></pre> <p>两行方式都是可以的。</p> <p>注:这里通过getSystemService获取BluetoothManager,再通过BluetoothManager获取BluetoothAdapter。BluetoothManager在Android4.3以上支持(API level 18)。 </p> <p><code>2.判断手机设备是否有蓝牙模块</code></p> <pre><code> // 检查设备上是否支持蓝牙 if (mBluetoothAdapter == null) { showToast(&amp;quot;没有发现蓝牙模块&amp;quot;); return; }</code></pre> <p><code>3.开启蓝牙设备</code> 开启蓝牙设备有两种方式: 第一种直接简单暴力不给用户进行提示:</p> <pre><code>if (!mBluetoothAdapter.isEnabled()) { mBluetoothAdapter.enable(); }</code></pre> <p>第二种直优雅的践行开启并且有弹框进行提示,隐式启动Intent:</p> <pre><code>if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); }</code></pre> <p><code>4.扫描蓝牙设备</code></p> <p>我这里是把扫描到的BLE地址存放到List集合中去。这里我们可以写一个方法进行封装一下。</p> <pre><code> /*********** * 扫描设备 ********/ private void scanLeDevice(final boolean enable) { if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.JELLY_BEAN_MR2) { if (enable) { devices.clear();//清空集合 // Stops scanning after a pre-defined scan period. mHandler.postDelayed(new Runnable() { @Override public void run() { if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.JELLY_BEAN_MR2) { mBluetoothAdapter.stopLeScan(mLeScanCallback); } } }, INTERVAL_TIME); mBluetoothAdapter.startLeScan(mLeScanCallback); } else { try { mBluetoothAdapter.stopLeScan(mLeScanCallback); } catch (Exception e) { } } } }</code></pre> <p>在这个扫描方法中,我们在AndroidStudio或者是Eclipse中会看到startLeScan方法会有横线,表明这个方式显示过期的方法,那么</p> <p>如果你只需要搜索指定UUID的外设,你可以调用 startLeScan(UUID[], BluetoothAdapter.LeScanCallback)方法。 其中UUID数组指定你的应用程序所支持的GATT Services的UUID。</p> <p>那么LeScanCallback的初始化代码如下:</p> <pre><code>private void initCallBack(){ if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.JELLY_BEAN_MR2) { mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { runOnUiThread(new Runnable() { @Override public void run() { if (device != null) { if (!TextUtils.isEmpty(device.getName())) { // devices.add(device); String name = device.getName(); if (name.contains(BluetoothDeviceAttr.OYGEN_DEVICE_NAME)) { if (!devices.contains(device)) { devices.add(device); } } } } } }); } }; } else { getToast(&amp;quot;设备蓝牙版本过低&amp;quot;); return; }</code></pre> <p>那么如果在设备多的情况下我们讲搜出很多的设备。我们可以选择我们所需要的地址进行链接。但是这类要注意的是:搜索时,你只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索.</p> <p><code>5.进行链接设备</code></p> <pre><code> final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); if (device == null) { Log.w(TAG, &amp;quot;Device not found. Unable to connect.&amp;quot;); return false; } // We want to directly connect to the device, so we are setting the autoConnect // parameter to false. mBluetoothGatt = device.connectGatt(this, false, mGattCallback);</code></pre> <p>这里调用的是device的connectGatt方法</p> <pre><code>/** * Connect to GATT Server hosted by this device. Caller acts as GATT client. * The callback is used to deliver results to Caller, such as connection status as well * as any further GATT client operations. * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct * GATT client operations. * @param callback GATT callback handler that will receive asynchronous callbacks. * @param autoConnect Whether to directly connect to the remote device (false) * or to automatically connect as soon as the remote * device becomes available (true). * @throws IllegalArgumentException if callback is null */ public BluetoothGatt connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) { return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO)); }</code></pre> <p>api中阐述的是第一个参数是上下文对象Context,第二个参数是是否自动连接,第三个是蓝牙的GattCallback回调。</p> <pre><code>private BluetoothGattCallback GattCallback = new BluetoothGattCallback() { // 这里有9个要实现的方法,看情况要实现那些,用到那些就实现那些 //当连接状态发生改变的时候 @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState){ }; //回调响应特征写操作的结果。 @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){ }; //回调响应特征读操作的结果。 @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { } //当服务被发现的时候回调的结果 @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { } 当连接能被被读的操作 @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorRead(gatt, descriptor, status); } ...... };</code></pre> <p>连接的过程我们一个通过service来进行连接,也可以在activity中进行操作。 好,到此为止,一个BLE蓝牙连接设备的整个流程我们已经清楚完毕。</p> <p>Android4.x的蓝牙不太成熟性</p> <p> 但是在实际操作过程中难免会出现一些比较坑人的问题。比如我用一个地址进行蓝牙设备连接,偶尔会出现蓝牙连接不上或者是说连接上设备后不返回数据等问题。那么此时我们可能会重启一下蓝牙或手机就立马有成功了。此时我们千万不能蒙蔽,也不要怀疑自己的人生。这是因为Android4.x的蓝牙还是不太成熟。目前可以来说是个测试阶段。 </p> <ul> <li>手机可能会搜索不到蓝牙设备 </li> <li>有时候会在广播中接收不到数据 </li> <li>出现异常需要重新启动手机或者是重启才能恢复正常</li> </ul> <p>这个时候我们怎么办呢?</p> <p>此时不要抱怨什么,难到我们作为Android程序员就注定如此的苦逼吗?</p> <p>答案是否定的。</p> <p>如何去优化呢?那么我们就应该从UI界面,用户体验上进行操作来实现 </p> <ul> <li>做一个定时器,如果在在确定蓝牙设备一打开并且存在的情况系,可以在手机搜索5s内没有搜索到蓝牙设备时重启蓝牙,并且在广播中接收到蓝牙开启后再次搜索 </li> <li>可以在UI上进行对用户进行相对应的提示 </li> <li>当蓝牙为启动时,提示用户去开启器蓝牙 </li> <li>当蓝牙开启后,在处在开启状态后,提示用户蓝牙正在开启… </li> <li>蓝牙已开启,设备并没有连接上,提示用户去进行连接 </li> <li>设备正在连接上手机,提示用户,正在连接,请等待… </li> <li> <p>蓝牙设备连接上手机,正在读取,提示数据正在读取中…</p> <p>我们不能子在Android系统上来操作什么,我们在体验上做到了我们能做的就可以的。</p> <p>手机蓝牙连接BLE设备要求</p> </li> </ul> <p>手机Android 4.3以上的系统 SDK&gt;=18 蓝牙版本&gt;=4.0 学习参考道demo下载地址: <a href="https://github.com/androidstarjack/Bluetooth_4.3-master">https://github.com/androidstarjack/Bluetooth_4.3-master</a></p> <p>学到这里,关于AndroidBLE蓝牙连接我们已经基本上实现了蓝牙的搜索,连接,读取等。</p> <p>大家项目中如果经常涉及到硬件比如手环,温度计,汗液仪,心电图,血压计等这些ble的蓝牙设备,就一定会用到蓝相关方面的知识。这里笔者先给大家提前踩一下坑,进行了总结,为后面的小伙伴在研究蓝牙方面尽量的少踩一些坑。如多对蓝牙的历程还未有清楚的认识,请参考深入了解Android蓝牙Bluetooth4.0——《基础篇》。</p> <p>如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809  </p>

页面列表

ITEM_HTML