精华内容
下载资源
问答
  • 低功耗蓝牙开发

    2021-03-15 14:13:07
    低功耗蓝牙开发权威指南》 链接:https://pan.baidu.com/s/1oQZN5exEd9Yj4nMclSIWXw 提取码:kwgj

    《低功耗蓝牙开发权威指南》


    链接:https://pan.baidu.com/s/1oQZN5exEd9Yj4nMclSIWXw 
    提取码:kwgj 
     

    展开全文
  • 低功耗蓝牙开发权威指南通过与经典蓝牙作对比,详尽介绍了将深入影响下一次无线技术革命的低功耗蓝牙技术的产生、设计、工作原理及其良好的节能、抗干扰特性和灵活、简单的开发特点。本书分为四个部分,分别阐述了低...
  • Android低功耗蓝牙开发官方示例Demo

    千次下载 热门讨论 2015-12-17 09:41:44
    谷歌官方提供的Android平台上的关于低功耗蓝牙开发的示例代码,该示例包含了Android低功耗蓝牙开发的完整过程:(低功耗蓝牙可简称“BLE”) 1、声明蓝牙权限 2、设置BLE 3、扫描BLE 4、连接到GATT服务器(即低...
  • 前面讲完了经典蓝牙的开发,本章开始详解低功耗蓝牙了,我在刚接触时傻傻的分不清经典蓝牙和低功耗蓝牙的区别,一直用开发经典蓝牙设备的方法去连接低功耗蓝牙,最后当然是一直连接不上了。然后一直吐槽低功耗蓝牙的...

    前言

    前面讲完了经典蓝牙的开发,本章开始详解低功耗蓝牙了,我在刚接触时傻傻的分不清经典蓝牙和低功耗蓝牙的区别,一直用开发经典蓝牙设备的方法去连接低功耗蓝牙,最后当然是一直连接不上了。然后一直吐槽低功耗蓝牙的不好用,这也是鉴于不会的基础上,后面会了后发现也还是挺简单的,就是感觉层次有点复杂了,下面首先详细介绍一下android蓝牙,也算是回顾前面的经典蓝牙概念。

    Android 蓝牙

    说到Android中的蓝牙,大家听到的可能有蓝牙1.0、蓝牙2.0、蓝牙3.0、蓝牙4.0之类的以数字结尾的蓝牙版本号,而实际上,在最新的标准中,已经不再使用数字版本号作为蓝牙版本的区分了,取而代之的是经典蓝牙与低功耗蓝牙(BLE)这两种区别。

    这里提到的低功耗蓝牙也会有很多人会误解为就是蓝牙4.0,但是完整的蓝牙4.0规范中实际上包括有经典蓝牙和低功耗蓝牙这两个部分,大家看看如下这张分类表就能够明白这其中的关系了。

    在这里插入图片描述
    如表中所述,现在的蓝牙实际上分为了三类:单模、双模和经典。那么,最官方的蓝牙版本称呼就是,单模蓝牙、双模蓝牙和经典蓝牙

    在这其中,最前沿的当属单模蓝牙了,也就是低功耗蓝牙(BLE)。这个蓝牙标准和经典蓝牙区别极大,在最初甚至考虑过加入WIFI阵营,但是因为蓝牙阵营这边条件较为优厚(比如授权费用极低)才并入了蓝牙标准。

    那么,低功耗蓝牙和经典蓝牙的区别究竟在哪里呢?

    要是仅仅从两者的通信方式上来说,可以说除了名字叫蓝牙外,完全可以当做两个东西。不过,两者在总体上的流程却也是相似的,那就是:

    发现设备->配对/绑定设备->建立连接->数据通信

    经典蓝牙和低功耗蓝牙除了配对/绑定这个环节是一样的之外,其它三个环节都是不同的。

    但是相较于传统蓝牙,BLE(低功耗蓝牙) 技术最重要的特点还有三个:低延迟、低功耗、低吞吐量

    蓝牙 4.0(BLE)工作在 2.4GHz ISM 频段,采用跳频技术与 GFSK 调制技术,广播频段均避开 Wi-Fi 频段,确保不受 Wi-Fi 信号影响。

    BLE 具有 40 个频段,其中有只有 3 个广播频段,37 个连接频段,大大缩短设备建立连接的时间,又能保证的数据的鲁棒性。

    BLE 低功耗蓝牙协议栈简介

    蓝牙 4.0(BLE)协议栈包含两部分:主机和控制器,如下图所示。协议定义的是一系列的通信标准,通信双方需要共同按照这一标准进行通信

    在这里插入图片描述

    控制器部分包括:物理层,链路层、主机控制接口层。

    物理层:从 2400MHz~2480MHz,间隔大小为 2MHz 的 40 个频段,其中 3 个广播频段,37 个连接频段。

    链路层:控制设备的状态。设备可以有五种状态:就绪、广播、搜索、初始化和连接。一个处于连接状态的设备会有一个角色:master(主)和 slave(从)。

    主机控制接口层:主机和控制器之间的一个标准接口。这一层可以是软件或者硬件接口,如 UART、SPI、USB 等。

    主机部分包括:逻辑链路控制及自适应协议层、安全管理层、属性协议层、通用属性配置层、通用访问配置层。

    逻辑链路控制及自适应协议层:为上层提供封装传输数据的服务,允许逻辑上的点对点数据通信。

    安全管理层:定义了配对和秘钥分配方式,为协议栈其他层与另一个设备之间的安全连接和数据交换提供服务。

    属性协议层:允许设备向另外一个设备展示一块特定的数据,称之为“属性”。展示“属性”的设备称为服务器,与之配对的设备称为客户端。

    通用属性配置层:定义了使用属性协议层的服务框架,用于已连接的蓝牙设备之间的数据通信。

    通用访问配置层:负责处理设备访问模式和程序,包括设备发现、建立连接、终止连接、初始化安全特性和设备配置。

    如果由工程师来开发蓝牙功能,就要先完成这些基本的协议栈上的工作,才能到应用层的开发。蓝牙 4.0(BLE)的出现带来低功耗的同时也进一步增加了蓝牙的开发难度。

    为了减小蓝牙设备的开发难度,云里物里基于 Nordic 的蓝牙 4.0(BLE)芯片 nrf51822 开发的一款低功耗、高性能的透传模块—MS49SF2C。

    BLE 蓝牙模块 MS49SF2C 不仅内置蓝牙 4.0(BLE)协议并支持用户简单接线就可以当 UART 口使用,开发 APP 还可实现 1 对 7 一主多从模式,实现多个设备间的信息交互。

    蓝牙的选用

    既然有经典蓝牙和低功耗蓝牙之分,我们在设计物联网产品和智能硬件产品的时候,如何选择呢?

    经典蓝牙: 蓝牙最初的设计意图,是打电话放音乐。3.0版本以下的蓝牙,都称为“经典蓝牙”。功耗高、传输数据量大、传输距离只有10米。

    低功耗蓝牙: 就是BLE,通常说的蓝牙4.0(及以上版本)。低功耗,数据量小,距离50米左右。

    传声音的,用经典蓝牙: 如蓝牙耳机、蓝牙音箱。蓝牙设计的时候就是为了传声音的,所以是近距离的音频传输的不二选择。

    电池供电、连手机APP的,用BLE: 如共享单车锁、蓝牙智能锁、蓝牙防丢器、蓝牙室内定位,是目前手机和智能硬件通信的性价比最高的手段。直线距离约50米,一节5号电池能用一年,传输模组成本10块钱,远比WIFI、4G等大数据量的通信协议更实用。

    又要声音又要数据的,用双模蓝牙: 双模蓝牙,就是同时支持经典蓝牙音频和低功耗蓝牙。

    如智能电视遥控器、降噪耳机等。很多智能电视配的遥控器带 有语音识别,需要用经典蓝牙 才能传输声音

    传大数据量的,用经典蓝牙: 如某些工控场景,使用Android或Linux主控,外挂蓝牙遥控设备的,可以使用经典蓝牙里的SPP协议,当作一个无线串口使用。速度比BLE传输快多了。

    远距离的,不用蓝牙: 固定供电的、不考虑功耗的、要传超过几十米距离的、要传高速数据的,这些都不适合蓝牙。远距离的可以用2G、4G、NB-IOT,大数据量的可以用WIFI。

    BLE 低功耗蓝牙模块具体应用场景

    下面单独列出低功耗蓝牙具体应用场景

    蓝牙灯控方案

    蓝牙灯控解决方案主要蓝牙模块为基础,实现智能蓝牙 LED 灯的色彩控制等功能。

    蓝牙灯控方案说明:手机蓝牙和彩灯上的蓝牙模块 MS102SF6 进行配对,实现 APP 命令控制彩灯蓝牙,实现不同的功能,比如可以通过色板、声音调节喜欢的颜色、亮度等。

    BLE 蓝牙智能锁方案

    智能门禁锁是在原有门禁系统的基础上,增加低功耗蓝牙透传模块,实现手机蓝牙协议对接。智能手机通过 APP 调用蓝牙服务,发送指令,智能门禁锁接收蓝牙指令,继而控制智能门禁锁的开关。

    蓝牙智能锁方案说明:智能锁中内置 BLE 蓝牙模块 MS48SF1C,手机通过 APP 读取智能锁蓝牙信息,尝试配对,并发送开锁请求到服务器端,服务器端向手机发送开锁指令,手机接受到指令,通过蓝牙再把指令发送给智能锁进行解锁。

    蓝牙 MAC 地址扫描打印解决方案

    蓝牙 MAC 地址扫描打印解决方案,例如包含蓝牙 MAC 地址读取设备、MAC 地址读取软件、MAC 地址管理软件、二维码生成软件、二维码打印驱动。

    蓝牙 MAC 地址扫描打印解决方案说明:把低功耗蓝牙模块充当主机角色,扫描周边设备,根据广播名称过滤,筛选出周边信号最强的设备,获取 MAC 地址;获取 MAC 地址后,通过串口将数据发送给标签打印机,标签打印机打印出符合要求的二维码。

    以二维码的形式将蓝牙 MAC 地址打印出来,方便蓝牙产品对蓝牙 MAC 地址进行读取,能够有效提高工作效率。

    蓝牙 Mesh 组网方案

    蓝牙 Mesh 网络是用于建立多对多(many:many)设备通信的低能耗蓝牙(Bluetooth Low Energy,也称为 Bluetooth LE)新的网络拓扑。

    它允许您创建基于多个设备的大型网络,网络可以包含数十台,数百甚至数千台蓝牙 Mesh 设备,这些设备之间可以相互进行信息的传递,无疑这样一种应用形态为楼宇自动化,无线传感器网络,资产跟踪和其他解决方案提供了理想的选择。有了蓝牙 Mesh,智能家居便涌现出很多新的应用可能性。

    蓝牙 Mesh 组网方案说明:有了蓝牙 Mesh 之后,只需用一台控制设备,就可以同时、轻松、高效地控制智能家居系统内的所有功能。蓝牙 Mesh 的强大架构还可以进行扩展,满足办公室、工厂、工业环境甚至城市的需求,将数以百万计的节点连接起来,而不会产生故障。

    蓝牙 Beacon 室内定位方案

    Beacon 是建立在低功耗蓝牙协议基础上的一种广播协议,同时它也是拥有这个协议的一款低功耗蓝牙从机设备。Beacon 设备,通常放在室内的某个固定位置,每隔一定时间广播一个数据包到周围。

    或者通过当前接收发送信号强度指示值(RSSI)、和 MAC 地址解析等来进行复杂的数据运算,进而对顾客进行室内定位。

    蓝牙 Beacon 室内定位方案说明:室内定位配合 Beacon 这一技术,将 Beacon 节点布在适当的位置,在配合丰富的 APP 应用,可以很方便地为用户提供室内位置服务。

    展开全文
  • 由Nordic工程师撰写,特别适合低功耗蓝牙开发入门。由蓝牙协议讲到蓝牙软硬件开发。包括TI及NORDIC常用蓝牙开发板使用。并且介绍了BLE安卓及ios开发。由浅入深,内容详细。相信仔细研读该教程后,对于BLE会有更全面...
  • 低功耗蓝牙开发权威指南》通过与经典蓝牙作对比,详尽介绍了将深入影响下一次无线技术革命的低功耗蓝牙技术的产生、设计、工作原理及其良好的节能、抗干扰特性和灵活、简单的开发特点。本书分为四个部分,分别阐述...
  • Android 低功耗蓝牙开发(扫描、连接)前言正文一、项目配置二、权限请求三、扫描低功耗蓝牙四、显示扫描设备五、连接设备六、源码 前言   之间我写过蓝牙开发的文章,只不过是针对于经典蓝牙,可以理解为普通蓝牙...

    前言

      之前我写过蓝牙开发的文章,只不过是针对于经典蓝牙,可以理解为普通蓝牙,连接的对象是经典蓝牙,列如手机蓝牙、蓝牙耳机等设备。而也有读者说在学习低功耗蓝牙,因此就有了这篇文章,一方面是为了丰富蓝牙的使用,一方面也是为了帮助看我文章的读者,我会讲的很细,很多人也说我在记流水账,不过这不重要,重要的是你从流水账里学到了什么。

    正文

      首先明白低功耗蓝牙是什么?

      蓝牙低能耗(Bluetooth Low Energy,或称Bluetooth LE、BLE,旧商标Bluetooth Smart)也称低功耗蓝牙,是蓝牙技术联盟设计和销售的一种个人局域网技术,旨在用于医疗保健、运动健身、信标、安防、家庭娱乐等领域的新兴应用。相较经典蓝牙,低功耗蓝牙旨在保持同等通信范围的同时显著降低功耗和成本。

      概念已经了解了,下面创建一个名为BleDemo的项目来写这篇文章。
    在这里插入图片描述

    一、项目配置

      首先进行项目的配置,一个是build.gradle配置,一个是AndroidManifest.xml配置。
    先进行项目的build.gradle的配置,添加jitpack仓库。

    maven { url "https://jitpack.io"}
    

    在这里插入图片描述

    再进行app的build.gradle的配置,这里需要添加几个依赖库,

    //蓝牙扫描库
    implementation 'no.nordicsemi.android.support.v18:scanner:1.5.0'
    //权限请求 支持Androidx
    implementation 'pub.devrel:easypermissions:3.0.0'
    //让你的适配器一目了然,告别代码冗余
    implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4'
    

    在这里插入图片描述
    改完了build.gradle记得要Sync Now。

    这个库是Nordic公司开发的,在蓝牙领域很出名的公司。这个版本是适配androidx的,一般现在创建新项目都是默认支持androidx的,不支持的话就说明你的AS该更新了。如果要支持support请到GitHub上去适配。其他的库或多或少都有接触过就不介绍了。

    下面配置AndroidManifest.xml。

    	<!-- 蓝牙权限 -->
        <uses-permission android:name="android.permission.BLUETOOTH" />
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> 
        <!-- 支持ble的设备 -->
        <uses-feature
            android:name="android.hardware.bluetooth_le"
            android:required="true" /> 
        <!-- 定位权限 -->
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    

    添加位置如下图所示
    在这里插入图片描述
      在Android 6.0以后的系统BLE scan需要申请location的相关权限才能支持BLE的一些功能,比如发现附近的beacons设备。

      这是开发的时候必须用到的权限,并非权限滥用。而在Android6.0以后则有了动态权限的申请,这里就说明一下等下为是什么要请求定位权限,后面就不要问我为什么扫描一个蓝牙还要打开定位权限这样的问题了。

    二、权限请求

      这里主要是定位权限的请求,还有就是获得定位之后,蓝牙是否有打开也需要进行处理,下面进行具体的编码。
    在MainActivity中新增一个方法,代码如下:

    	/**
         * 检查Android版本
         */
        private void checkAndroidVersion() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                //Android 6.0及以上动态请求权限
                
            } else {
                //检查蓝牙是否打开
                
            }
        }
    

    这里进行Android版本的判断,6.0及以上则请求权限,6.0一下则判断蓝牙是否打开。

    下面先写这个蓝牙是否打开的判断

    	/**
         * 请求打开蓝牙
         */
        private static final int REQUEST_ENABLE_BLUETOOTH = 100;
        /**
         * 蓝牙适配器
         */
        private BluetoothAdapter bluetoothAdapter;
    
    	/**
         * 是否打开蓝牙
         */
        public void openBluetooth() {
            //获取蓝牙适配器
            bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            if (bluetoothAdapter != null) {//是否支持蓝牙
                if (bluetoothAdapter.isEnabled()) {//打开
                    showMsg("蓝牙已打开");
                } else {//未打开
                    startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), REQUEST_ENABLE_BLUETOOTH);
                }
            } else {
                showMsg("你的设备不支持蓝牙");
            }
        }
    
        /**
         * Toast提示
         *
         * @param msg 内容
         */
        private void showMsg(String msg) {
            Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
        }
    

    这里会有一个页面的返回结果,代码如下:

    	@Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (resultCode == Activity.RESULT_OK) {
                if (requestCode == REQUEST_ENABLE_BLUETOOTH) {
                    if (bluetoothAdapter.isEnabled()) {
                        //蓝牙已打开
                        showMsg("蓝牙已打开");
                    } else {
                        showMsg("请打开蓝牙");
                    }
                }
            }
        }
    

    那么现在对于蓝牙是否打开的结果进行了处理,下面进行动态权限的请求。

    	/**
         * 权限请求码
         */
        public static final int REQUEST_PERMISSION_CODE = 9527;
    	
    	/**
         * 请求权限
         */
        @AfterPermissionGranted(REQUEST_PERMISSION_CODE)
        private void requestPermission() {
            String[] perms = {Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.ACCESS_COARSE_LOCATION,};
            if (EasyPermissions.hasPermissions(this, perms)) {
                //权限通过之后检查有没有打开蓝牙
                openBluetooth();
            } else {
                // 没有权限
                EasyPermissions.requestPermissions(this, "App需要定位权限", REQUEST_PERMISSION_CODE, perms);
            }
        }
    

    这里会检查权限,有权限检查有没有打开蓝牙,没有权限则请求权限,请求权限的结果代码如下:

    	/**
         * 权限请求结果
         */
        @Override
        public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            // 将结果转发给 EasyPermissions
    		EasyPermissions.onRequestPermissionsResult(REQUEST_PERMISSION_CODE, permissions, grantResults, this);
        }
    

    这个结果会通过@AfterPermissionGranted注解将结果返回给这个requestPermission方法,然后重新检查权限结果。下面只要在checkAndroidVersion中调用这个requestPermission()方法和openBluetooth()方法即可,如下图所示:
    在这里插入图片描述
    现在就形成了一个逻辑链,不过还需要一个地方去调用这个checkAndroidVersion()方法,就直接在onCreate中调用吧。
    在这里插入图片描述
    继续下一步。

    三、扫描低功耗蓝牙

      扫描低功耗蓝牙,首先要有触发的地方,其次要有显示结果的地方,这些都需要进行UI的处理,那么下面进行布局的修改和增加,修改activity_main.xml,代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <!--设备列表-->
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv_device"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@+id/btn_start_scan"
            android:overScrollMode="never" />
    
        <!--开始扫描-->
        <com.google.android.material.button.MaterialButton
            android:id="@+id/btn_start_scan"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_above="@+id/btn_stop_scan"
            android:layout_margin="6dp"
            android:insetTop="0dp"
            android:insetBottom="0dp"
            android:text="开始扫描" />
        <!--停止扫描-->
        <com.google.android.material.button.MaterialButton
            android:id="@+id/btn_stop_scan"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_alignParentBottom="true"
            android:layout_margin="6dp"
            android:insetTop="0dp"
            android:insetBottom="0dp"
            android:text="停止扫描" />
    </RelativeLayout>
    

    下面进行列表item的布局编写,在layout下新建一个item_device_rv.xml文件,文件代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:foreground="?attr/selectableItemBackground"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:padding="16dp">
    
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/ic_bluetooth_blue" />
    
            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:orientation="vertical"
                android:paddingStart="12dp">
    
                <TextView
                    android:id="@+id/tv_device_name"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:ellipsize="end"
                    android:singleLine="true"
                    android:text="设备名称"
                    android:textColor="@color/black"
                    android:textSize="16sp" />
    
                <TextView
                    android:id="@+id/tv_mac_address"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="8dp"
                    android:ellipsize="end"
                    android:singleLine="true"
                    android:text="Mac地址" />
            </LinearLayout>
    
            <TextView
                android:id="@+id/tv_rssi"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="信号强度" />
        </LinearLayout>
    
        <View
            android:layout_width="match_parent"
            android:layout_height="0.5dp"
            android:background="#EEE" />
    </LinearLayout>
    

    这里面有一个图标,使用路径绘制的ic_bluetooth_blue.xml,放在drawable文件夹下,代码如下:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="36dp"
        android:height="36dp"
        android:autoMirrored="true"
        android:tint="#42A5F5"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    
        <path
            android:fillColor="@android:color/white"
            android:pathData="M14.58,12.36l1.38,1.38c0.28,0.28 0.75,0.14 0.84,-0.24c0.12,-0.48 0.18,-0.99 0.18,-1.5c0,-0.51 -0.06,-1.01 -0.18,-1.48c-0.09,-0.38 -0.56,-0.52 -0.84,-0.24l-1.39,1.38C14.39,11.85 14.39,12.17 14.58,12.36zM18.72,7.51l-0.05,0.05c-0.25,0.25 -0.3,0.62 -0.16,0.94c0.47,1.07 0.73,2.25 0.73,3.49c0,1.24 -0.26,2.42 -0.73,3.49c-0.14,0.32 -0.09,0.69 0.16,0.94l0,0c0.41,0.41 1.1,0.29 1.35,-0.23c0.63,-1.3 0.98,-2.76 0.98,-4.3c-0.01,-1.48 -0.34,-2.89 -0.93,-4.16C19.83,7.22 19.13,7.1 18.72,7.51zM15,7l-4.79,-4.79C10.07,2.07 9.89,2 9.71,2h0C9.32,2 9,2.32 9,2.71v6.88L5.12,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L8.59,12l-4.89,4.89c-0.39,0.39 -0.39,1.02 0,1.41h0c0.39,0.39 1.02,0.39 1.41,0L9,14.41v6.88C9,21.68 9.32,22 9.71,22h0c0.19,0 0.37,-0.07 0.5,-0.21L15,17c0.39,-0.39 0.39,-1.02 0,-1.42L11.41,12L15,8.42C15.39,8.03 15.39,7.39 15,7zM11,5.83l1.88,1.88L11,9.59V5.83zM12.88,16.29L11,18.17v-3.76L12.88,16.29z" />
    
    </vector>
    
    

    好了,现在针对于这个布局方面的内容告一段落,下面先运行一下了:在这里插入图片描述
    进行下一步操作。

    先进行页面的初始化。新增一个initView的方法。

    	private static final String TAG = MainActivity.class.getSimpleName();
    	/**
         * nordic扫描回调
         */
        private ScanCallback scanCallback;
    	
    	/**
         * 初始化
         */
        private void initView() {
            RecyclerView rvDevice = findViewById(R.id.rv_device);
            findViewById(R.id.btn_start_scan).setOnClickListener(v -> startScanDevice());
            findViewById(R.id.btn_stop_scan).setOnClickListener(v -> stopScanDevice());
            //扫描结果回调
            scanCallback = new ScanCallback() {
                @Override
                public void onScanResult(int callbackType, @NonNull ScanResult result) {
    
                    Log.d(TAG, "name:" + result.getDevice().getName() + ",rssi:" + result.getRssi());
                }
    
                @Override
                public void onScanFailed(int errorCode) {
                    throw new RuntimeException("Scan error");
                }
            };
        }
    

    这个initView主要是页面的初始化,列表在后面进行配置,根据扫描结果来定,然后就是配置扫描回调,这里注意导包的问题,不要到错了包。
    在这里插入图片描述
    然后还有一个开始扫描和停止扫描的方法。

    	/**
         * 开始扫描设备
         */
        public void startScanDevice() {
            BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
            scanner.startScan(scanCallback);
        }
    
        /**
         * 停止扫描设备
         */
        public void stopScanDevice() {
            BluetoothLeScannerCompat scanner = BluetoothLeScannerCompat.getScanner();
            scanner.stopScan(scanCallback);
        }
    

    下面在onCreate方法中调用initView()方法。
    在这里插入图片描述
    下面就可以开始运行了。运行之后点击开始扫描按钮,就会扫描附近的低功耗蓝牙设备,(请在附近有已打开低功耗蓝牙时进行扫描)可以在日志栏处进行打印。
    在这里插入图片描述
    这里很明显,扫描到了一些蓝牙设备,并且很多设备没有设备名称。既然有了结果,那么下面就是将扫描到的结果显示在列表上,这样才更直观。

    四、显示扫描设备

      下面将扫描结果渲染到列表上,首先明确列表要显示扫描设备的那些信息,从item来看有设备名、Mac地址、信号强度。那么可以根据这一个扫描的信息构建一个设备类,新建一个BleDevice类,代码如下:

    package com.llw.bledemo.bean;
    
    import android.bluetooth.BluetoothDevice;
    
    /**
     * @author llw
     * @description BleDevice
     * @date 2021/7/21 19:20
     */
    public class BleDevice {
        private BluetoothDevice device;
        private int rssi;
        private String realName;//真实名称
    
        /**
         * 构造Device
         * @param device 蓝牙设备
         * @param rssi 信号强度
         * @param realName 真实名称
         */
        public BleDevice(BluetoothDevice device, int rssi, String realName) {
            this.device = device;
            this.rssi = rssi;
            this.realName = realName;
        }
    
        public BluetoothDevice getDevice(){
            return device;
        }
    
        public int getRssi(){
            return rssi;
        }
    
        public void setRssi(int rssi) {
            this.rssi = rssi;
        }
    
        public String getRealName(){
            return realName;
        }
    
        public void setRealName(String realName) {
            this.realName = realName;
        }
    
        @Override
        public boolean equals(Object object) {
            if(object instanceof BleDevice){
                final BleDevice that =(BleDevice) object;
                return device.getAddress().equals(that.device.getAddress());
            }
            return super.equals(object);
        }
    }
    
    

    下面来写这个适配器,新建一个BleDeviceAdapter类,代码如下:

    package com.llw.bledemo.adapter;
    
    import com.chad.library.adapter.base.BaseQuickAdapter;
    import com.chad.library.adapter.base.viewholder.BaseViewHolder;
    import com.llw.bledemo.R;
    import com.llw.bledemo.bean.BleDevice;
    
    import java.util.List;
    
    /**
     * @author llw
     * @description BleDeviceAdapter
     * @date 2021/7/21 19:34
     */
    public class BleDeviceAdapter extends BaseQuickAdapter<BleDevice, BaseViewHolder> {
    
        public BleDeviceAdapter(int layoutResId, List<BleDevice> data) {
            super(layoutResId, data);
        }
    
        @Override
        protected void convert(BaseViewHolder holder, BleDevice bleDevice) {
            holder.setText(R.id.tv_device_name, bleDevice.getRealName())
                    .setText(R.id.tv_mac_address, bleDevice.getDevice().getAddress())
                    .setText(R.id.tv_rssi, bleDevice.getRssi() + " dBm");
        }
    }
    
    

    下面回到MainActivity中对列表进行适配,先定义变量

    	/**
         * 设备列表
         */
        private List<BleDevice> mList = new ArrayList<>();
    
        /**
         * 列表适配器
         */
        private BleDeviceAdapter deviceAdapter;
    

    然后在initView方法中进行列表配置,代码如下:

    	//列表配置
        deviceAdapter = new BleDeviceAdapter(R.layout.item_device_rv, mList);
        rvDevice.setLayoutManager(new LinearLayoutManager(this));
        //启用动画
        deviceAdapter.setAnimationEnable(true);
        //设置动画方式
        deviceAdapter.setAnimationWithDefault(BaseQuickAdapter.AnimationType.SlideInRight);
        rvDevice.setAdapter(deviceAdapter);
    

    添加位置如下:
    在这里插入图片描述
    下面就是将扫描结果添加到列表中了,可以写一个方法addDeviceList(),代码如下:

    	/**
         * 添加到设备列表
         *
         * @param bleDevice 蓝牙设备
         */
        private void addDeviceList(BleDevice bleDevice) {
            if (!mList.contains(bleDevice)) {
                bleDevice.setRealName(bleDevice.getRealName() == null ? "UNKNOWN" : bleDevice.getRealName());
                mList.add(bleDevice);
            } else {
                //更新设备信号强度值
                for (BleDevice device : mList) {
                    device.setRssi(bleDevice.getRssi());
                }
            }
            //刷新列表适配器
            deviceAdapter.notifyDataSetChanged();
        }
    

    然后在扫描的回调中进行调用即可。
    在这里插入图片描述
    点击开始的时候清理一下列表。
    在这里插入图片描述

    下面运行一下:
    在这里插入图片描述
    增加一个表示搜索的效果,在activity_main.xml中增加

    	<androidx.core.widget.ContentLoadingProgressBar
            android:id="@+id/loading_progress_bar"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:indeterminate="true"
            android:indeterminateTint="@color/purple_200"
            android:visibility="invisible"
            tools:ignore="UnusedAttribute"/>
    

    然后这个进度条设置在列表的上面。

    在这里插入图片描述
    回到MainActivity,创建变量:

    	/**
         * 加载进度条
         */
        private ContentLoadingProgressBar loadingProgressBar;
    

    绑定视图
    在这里插入图片描述
    控制视图
    在这里插入图片描述
    运行一下:
    在这里插入图片描述

    五、连接设备

      连接Ble设备其实也很简单,难的是连接之外的东西,先来构想一下连接功能的业务逻辑,点击设备列表中的设备,进行连接,先显示一个加载布局,表示现在正在连接,然后停止扫描,在根据设备的mac地址去连接这个设备,然后在连接设备的回调中处理连接设备的结果。嗯,就是这样。下面来编码,首先是加载布局的问题。在activity_main.xml中增加如下布局代码:

    	<!--加载布局-->
        <LinearLayout
            android:id="@+id/lay_connecting_loading"
            android:layout_centerInParent="true"
            android:layout_width="160dp"
            android:layout_height="160dp"
            android:orientation="vertical"
            android:visibility="invisible"
            android:background="@color/white"
            android:gravity="center">
    
            <ProgressBar
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:indeterminate="true"
                android:indeterminateTint="@color/purple_200" />
    
            <TextView
                android:layout_marginTop="12dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="连接中..."
                android:textColor="@color/black"
                android:textSize="@dimen/sp_14" />
        </LinearLayout>
    

    添加位置如下图
    在这里插入图片描述
    然后在MainActivity中创建变量

    	/**
         * 等待连接
         */
        private LinearLayout layConnectingLoading;
    

    绑定视图
    在这里插入图片描述
    下面新增一个方法,用来连接设备。在点击设备列表Item的时候调用。

    	/**
         * 连接设备
         *
         * @param bleDevice 蓝牙设备
         */
        private void connectDevice(BleDevice bleDevice) {
            //显示连接等待布局
            layConnectingLoading.setVisibility(View.VISIBLE);
    
            //停止扫描
            stopScanDevice();
    
            //获取远程设备
            BluetoothDevice device = bleDevice.getDevice();
    		//连接gatt
            device.connectGatt(this, false, new BluetoothGattCallback() {
                @Override
                public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                    switch (newState) {
                        case BluetoothProfile.STATE_CONNECTED://连接成功
                            Log.d(TAG,"连接成功");
                            runOnUiThread(() -> {
                                layConnectingLoading.setVisibility(View.GONE);
                                showMsg("连接成功");
                            });
                            break;
                        case BluetoothProfile.STATE_DISCONNECTED://断开连接
                            Log.d(TAG,"断开连接");
                            runOnUiThread(() -> {
                                layConnectingLoading.setVisibility(View.GONE);
                                showMsg("断开连接");
                            });
                            break;
                        default:
                            break;
                    }
                }
            });
        }
    

    在initView()中设置列表点击。

    	//item点击事件
        deviceAdapter.setOnItemClickListener((adapter, view, position) -> {
            //连接设备
            connectDevice(mList.get(position));
        });
    

    在这里插入图片描述
    OK,下面运行一下:

    在这里插入图片描述
    这个布局背景是白色的不是很明显,改一下好了。在drawable文件夹下新建一个shape_loading_bg.xml,里面的代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="@color/white" />
        <corners android:radius="20dp" />
        <stroke
            android:width="1dp"
            android:color="@color/purple_500" />
    </shape>
    

    然后设置到这个布局中
    在这里插入图片描述
    运行看看
    在这里插入图片描述
    嗯,还可以,就这样了。

    有连接设备就自然有断开连接设备。再增加两个变量

    	/**
         * Gatt
         */
        private BluetoothGatt bluetoothGatt;
    
        /**
         * 设备是否连接
         */
        private boolean isConnected = false;
    

    修改connectDevice()中的代码,如下图所示
    在这里插入图片描述
    再新建一个断开连接的方法,代码如下:

    	/**
         * 断开设备连接
         */
        private void disconnectDevice() {
            if (isConnected && bluetoothGatt != null) {
                bluetoothGatt.disconnect();
            }
        }
    

    六、源码

    源码地址Github:BleDemo

    源码地址CSDN:BleDemo.rar

    这篇文章就到这里了,有问题的可以评论区留言或者私信我都行,山高水长,后会有期~

    展开全文
  • 低功耗蓝牙开发权威指南中文带标签版,可以熟悉一下蓝牙开发的过程和应当注意的问题。
  • 本节书摘来自华章社区《低功耗蓝牙开发权威指南》一书中的第1章什么是低功耗蓝牙技术,作者 (英)Robin Heydon,更多章节内容可以访问云栖社区“华章社区”公众号查看 第1章什么是低功耗蓝牙技术如果我能看得更远的...

    本节书摘来自华章社区《低功耗蓝牙开发权威指南》一书中的第1章什么是低功耗蓝牙技术,作者 (英)Robin Heydon,更多章节内容可以访问云栖社区“华章社区”公众号查看

    第1章
    什么是低功耗蓝牙技术
    如果我能看得更远的话,那是因为我站在巨人的肩膀上。
    —艾萨克·牛顿(Isaac Newton)
    低功耗蓝牙是一种全新的技术,是当前可以用来设计和使用的功耗最低的无线技术。作为经典蓝牙的扩展,低功耗蓝牙沿用了蓝牙商标,并且借鉴了很多父辈的技术,然而,由于针对的设计目标和市场领域均与经典蓝牙有所不同,低功耗蓝牙应被视为一种不同的技术。
    经典蓝牙的设计目的在于统一全球各地的计算和通信设备,让手机与笔记本电脑互相连接。不过事实证明,蓝牙最为广泛的应用还是音频传输,比如将音频从手机传到蓝牙耳机。随着技术的成熟,越来越多的蓝牙应用进入人们的视线,包括立体声音频流、汽车从手机下载电子书、无线打印和文件传输。由于每一个新的应用都要求更多带宽,因此,随着时间的推移,越来越快的无线电技术不断地加入蓝牙系统中。1.0版蓝牙为基本码率(Basic Rate,BR),最大物理层数据速率为1 Mbps(兆比特每秒);2.0版本为增强码率(Enhanced Data Rate,EDR),其物理层数据传输率增至3Mbps;3.0版本引入Alternative MAC PHY (AMP,交替射频技术),利用IEEE 802.11实现了高达数百Mbps的物理层数据速率。
    低功耗蓝牙选择了完全不同的方向:并非只是增加可达的数据传输速率,而是从尽可能降低功耗方面进行优化。这意味着,也许你无法获得很高的传输速率,但是可以将连接保持数小时或数天的时间。这一选择非常有趣,显然,大部分有线和无线通信技术还在马不停蹄地提升速率,如表1-1所示。
    对于那些由纽扣电池供电的设备,经典蓝牙并不能真正达到它们的低功耗要求。理解了这一点,就不难明白选择新方向的原因。然而,在充分考虑低功耗的相关要求时,还有一点必须考虑到,即低功耗蓝牙应被设计成满足极大规模部署的要求,以便用于迄今尚未装备无线技术的装置。要实现极大的规模,就必须要有极低的成本。就好像射频识别(Radio Frequency Identification,RFID)通过一个价格较高的扫描装置获得能量,然而其标签本身的成本极低,从而获得了大量的部署。


    8cf264e208977a52a6791dc1c0a77e13a295973e

    因此,从低成本的需求方面审视低功耗蓝牙的系统设计尤为重要。实现低成本的设计有三个关键因素:

    1. ISM频段
      无论从设计的角度还是从使用的角度出发,2.4GHz ISM频段对无线技术而言都是个糟糕的频段。该频段无线电传播特性差,能量极容易被各类物体吸收,尤其是水,而人体主要是由水构成的。尽管有许多显著的不利因素,但不可否认,该无线电频谱的优势是在全世界可以免许可、自由地使用。当然,“免交租金”的标志意味着其他技术一样能够使用该频段,包括绝大部分的Wi-Fi信号。不过,免许可并非等同于毫无约束,使用该频段仍然要遵守相当多的规则,主要是限制设备的输出能量和范围。当然,与许可频谱的高昂费用相比,这些限制就显得微不足道了。因此,选择使用ISM频段能够降低成本。
    2. IP许可
      当Wibree(超低功耗蓝牙)技术发展成熟,考虑将其并入已有的无线标准工作组时,诺基亚原本有多种选择方案。比如加入Wi-Fi联盟,该联盟也在2.4GHz ISM频段制定标准化技术。然而,鉴于蓝牙组织拥有较高的声誉和优厚的专利许可政策,他们最终选择了蓝牙技术联盟(Bluetooth Special Interest Group,BT SIG)。与其他采取FRAND政策的兴趣小组或联盟相比,蓝牙技术联盟的政策使得蓝牙设备的专利许可成本大为降低。而许可成本的降低使得每件设备的成本也显著降低。
    3. 低功耗
      设计一款低成本设备的最好方法就是减少制作这个设备所需的原料,比如电池。电池越大,电池盒就越大,这样又会增加成本。替换一节电池的花费,不仅指消费者需要购买新的电池,而且替换本身也包含了因设备暂时无法使用带来的机会成本。如果设备由第三方维护,比如作为家庭警备管理系统的一部分,换电池还需额外的劳动力成本。因此,设计有关低功耗的技术也是在降低各种成本。这里不妨做个脑力实验,如果只花一毛钱就能买一个兆瓦特级的电池,那事情会变得多么不同?

    很多设备能容纳更大的电池,例如键盘或者鼠标内部很容易装下几节AA电池。然而生产商们却倾向于使用AAA电池,并不是因为它们更小,而是因为它们的原料成本更低,降低了设备的总成本。
    因此,低功耗的基础设计就是以纽扣电池—这种最小、最便宜并且最容易购买的电池类型作为能量来源。这意味着我们无法令低功耗蓝牙实现很高的数据传输速率,或是将其用于大量数据的传输或者数据流传输。这一点或许是经典蓝牙与低功耗蓝牙的最大区别。下一节将就该问题进行详细讨论。

    展开全文
  • 代码中包含的是一个完整的低功耗蓝牙设备从判断、连接、断开、传输数据、接收数据的一个完整的模板。由于每个设备的硬件方面不同,此代码可能不适用与所有低功耗蓝牙设备,但是其中的逻辑关系都是差不多的,大家需要...
  • 本节书摘来自华章社区《低功耗蓝牙开发权威指南》一书中的第3章低功耗蓝牙的体系结构,作者 (英)Robin Heydon,更多章节内容可以访问云栖社区“华章社区”公众号查看 第3章低功耗蓝牙的体系结构专注简单是我一直...
  • 低功耗蓝牙开发套件-LaunchIOT-CC2640R2F,适合初学者学习
  • Android BLE低功耗蓝牙开发

    千次阅读 2017-01-24 19:08:01
    啦啦啦在上一个项目中有用到BLE低功耗蓝牙开发,当时baidu google了很多资料,但大多数都是千篇一律,英文文档我这种渣渣又看不懂。。。总之刚开始查的很痛苦。所以要把自己的踩坑之路写下来记录下,,,或许能帮到...
  • 这篇,我们来学习蓝牙开发的最后一章,低功耗蓝牙 BLE,也就是我们常说的蓝牙 4.0 。 今天要完成的效果如下: 中心设备 外围设备 一. 简介 与传统蓝牙不同,低功耗蓝主要为了降低设备功耗,支持更低...
  • 有关低功耗蓝牙开发

    2018-08-30 10:20:33
    这是有关低功耗蓝牙通信的代码,可以下载看看。其中资源是一个项目的压缩包。
  • Android 低功耗蓝牙开发

    千次阅读 2019-07-04 14:12:26
    初识低功耗蓝牙 Android 4.3(API Level 18)开始引入Bluetooth Low Energy(BLE,低功耗蓝牙)的核心功能并提供了相应的 API, 应用程序通过这些 API 扫描蓝牙设备、查询 services、读写设备的 characteristics...
  • 官方出品,低功耗蓝牙入门开发教程和源码,包含IOS/Android/Raspberry和Zephyr
  • 低功耗蓝牙开发权威指南》通过与经典蓝牙作对比,详尽介绍了将深入影响下一次无线技术革命的低功耗蓝牙技术的产生、设计、工作原理及其良好的节能、抗干扰特性和灵活、简单的开发特点。本书分为四个部分,分别阐述...
  • 低功耗蓝牙开发权威指南 之 安全
  • 学习低功耗蓝牙协议的入门必读经典书籍,作者参与BLE协议的起草,告诉读者BLE协议为什么这么设计,一切都是为实际的低功耗应用场景服务。非常适合入门。
  • 我集成了API21前后蓝牙版本,做成了一个BLE蓝牙调用库,方便快捷。希望能够帮助有需要的朋友们,内付demo仅供参考!
  • 低功耗蓝牙概述 Android 4.3(API级别18)引入了内置平台支持蓝牙低功耗(BLE)的核心角色,并提供应用程序可用于发现设备,查询服务和传输信息的API。 常见用例包括以下内容: 在附近设备之间传输少量数据。 ...
  • Android 8.0 BLE 低功耗蓝牙开发记录

    千次阅读 2018-09-29 16:15:34
    Android 8.0 BLE 低功耗蓝牙开发记录(1-3)--------------(权限申请篇) 目的:开源博客,希望大家一起修改博客错误地方,共同完善并会鸣谢提供意见的朋友。为大家提供一个开发支持的字典,谢谢各位朋友帮助。如有错误...
  • Bluetooth Low Energy The Developer-'s Handbook(低功耗蓝牙开发权威指南英文版) 蓝牙开发的经典英文书籍原版
  • 转载请注明出处,本文出自 BLE低功耗蓝牙开发相关概念问题记录 ble对于数据的传输有一个字节上的限制,默认情况下是20个字节,但并不是不可修改的。默认情况下mtu是23个字节(除去3个字节的标志位剩余为20个字节)...
  • 相较经典蓝牙,低功耗蓝牙旨在保持同等通信范围的同时显著降低功耗和成本。 低功耗蓝牙芯片有传输远、功耗低、延迟低等优势。传输距离方面,经典蓝牙只有10-100米,而BLE最远能传输300米;连接方式上,经典蓝牙只能...
  • 本节书摘来自华章社区《低功耗蓝牙开发权威指南》一书中的目录,作者 (英)Robin Heydon,更多章节内容可以访问云栖社区“华章社区”公众号查看 目 录 前言第一部分 综 述第1章 什么是低功耗蓝牙技术 1.1 ...
  • 细分为传统蓝牙、高速蓝牙和低功耗蓝牙模块, 传统蓝牙 泛指支持蓝牙协议在4.0以下的模块,细分为传统蓝牙和高速蓝牙。 低功耗蓝牙 BLE即蓝牙低功耗,是指蓝牙协议在4.0及以上的蓝牙模块,是一种新型的超低...
  • 本节书摘来自华章社区《低功耗蓝牙开发权威指南》一书中的第1章,第1.1节设备类型,作者 (英)Robin Heydon,更多章节内容可以访问云栖社区“华章社区”公众号查看 1.1 设备类型低功耗蓝牙技术可以构建两种类型的...
  • 低功耗蓝牙开发权威指南 中文版

    千次下载 热门讨论 2015-04-13 09:18:54
    是中文版,感觉很好的一本书,对蓝牙的协议进行了描述

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,869
精华内容 3,947
关键字:

低功耗蓝牙开发