低功耗蓝牙初探

ESP32低功耗蓝牙快速入门 此文章包含两个部分。一是蓝牙理论部分,二是实践部分。实践部分用一个简单的例子帮助大家理解ESP32的低功耗蓝牙,例子实验用ESP32作为一个GATT_Server,当手机连接上蓝牙时,电亮LED灯,当蓝牙断开时熄灭LED灯。 阅读详情

低功耗蓝牙

蓝牙官网

谷歌BLE引文原文:Bluetooth Low Energy

【原创】Android 5.0BLE低功耗蓝牙从设备应用

获取BluetoothAdapter

   //Android 4.3引入BluetoothManager概念
   final BluetoothManager bluetoothManager =
           (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
   mBluetoothAdapter = bluetoothManager.getAdapter();

检查是否支持蓝牙开启了蓝牙

 //确保蓝牙在设备上启用,如果不是这样,显示一个对话框要求用户开启蓝牙
 if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
     Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
     startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
  }

检查是否支持外围设备

(5.0才开始支持,不保证所有大于5.0的设备都支持)

  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
      BluetoothLeAdvertiser mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
      if (mBluetoothLeAdvertiser != null) {
          Toast.makeText(this, "support peripheral", Toast.LENGTH_SHORT).show();
          break;
      }
  }
  Toast.makeText(this, "the device not support peripheral", Toast.LENGTH_SHORT).show();

扫描周围低功耗设备

  private static boolean mScanning;
     private static Handler mHandler = new Handler();
     // 10秒后停止扫描
     private static final long SCAN_PERIOD = 10000;

     @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
     public static void scanLeDevice(final boolean enable) {
         if (enable) {
             // Stops scanning after a pre-defined scan period.
             mHandler.postDelayed(new Runnable() {

                 @Override
                 public void run() {
                     mScanning = false;
                     mBluetoothAdapter.getBluetoothLeScanner().stopScan(mScanCallback);
                 }
             }, SCAN_PERIOD);

             mScanning = true;
             ScanSettings.Builder scanSettings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_BALANCED);
             mBluetoothAdapter.getBluetoothLeScanner().startScan(null, scanSettings.build(), mScanCallback);
         } else {
             mScanning = false;
             mBluetoothAdapter.getBluetoothLeScanner().stopScan(mScanCallback);
         }
     }


    // 设备扫描回调
    private static List<BluetoothDevice> devices = new ArrayList<>();

       @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
       private static ScanCallback mScanCallback = new ScanCallback() {

           @Override
           public void onScanResult(int callbackType, ScanResult result) {
               super.onScanResult(callbackType, result);
               BluetoothDevice device = result.getDevice();
               if (!devices.contains(device)) {  //判断是否已经添加
                   devices.add(device);
                   LogUtil.d(result.getDevice().toString() + "  rssi = " + result.getRssi());
               }
           }

           @Override
           public void onBatchScanResults(List<ScanResult> results) {
               super.onBatchScanResults(results);
               LogUtil.d("onBatchScanResults = " + results.size());
           }

           @Override
           public void onScanFailed(int errorCode) {
               super.onScanFailed(errorCode);
               LogUtil.d("onScanFailed = " + errorCode);
           }
       };

注意:只能扫描BLE设备或者扫描传统蓝牙设备,不能同时扫描BLE和传统蓝牙设备。

与设备连接

更确切的讲是与设备上的GATT服务连接

“`
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public static void connectBle(String address) {
BluetoothDevice remoteDevice = mBluetoothAdapter.getRemoteDevice(address);
remoteDevice.connectGatt(mContext, false, bluetoothGattCallback);
}

 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
 private static BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
     @Override
     public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
         super.onConnectionStateChange(gatt, status, newState);
         LogUtil.d(" onConnectionStateChange()  called with: gatt = [" + gatt + "], status = [" + status + "], newState = [" + newState + "]");
         if (newState == BluetoothProfile.STATE_CONNECTED) {
             gatt.discoverServices();//连接成功,开始搜索服务,一定要调用此方法,否则获取不到服务
         }
     }

     @Override
     public void onServicesDiscovered(BluetoothGatt gatt, int status) {
         super.onServicesDiscovered(gatt, status);
         LogUtil.d(" onServicesDiscovered() called with: gatt = [" + gatt + "], status = [" + status + "]");
         List<BluetoothGattService> services = gatt.getServices();
         for (BluetoothGattService service : services) {
             LogUtil.d("service = " + service.getUuid());
             List<BluetoothGattService> includedServices = service.getIncludedServices();
             for (BluetoothGattService includedService : includedServices) {
                 LogUtil.d("       includedService = " + includedService.getUuid());
             }

             List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
             for (BluetoothGattCharacteristic characteristic : characteristics) {
                 LogUtil.d("       -characteristic = " + characteristic.getUuid() + "  Value()" + characteristic.getValue() + "  writhType = " + characteristic.getWriteType());
             }
         }
     }

     @Override
     public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
         super.onCharacteristicRead(gatt, characteristic, status);
         LogUtil.d(" onCharacteristicRead");
     }

     @Override
     public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
         super.onCharacteristicWrite(gatt, characteristic, status);
         LogUtil.d(" onCharacteristicWrite");
     }

     @Override
     public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
         super.onCharacteristicChanged(gatt, characteristic);
         LogUtil.d("onCharacteristicChanged");
     }

     @Override
     public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
         super.onDescriptorRead(gatt, descriptor, status);
         LogUtil.d("onDescriptorRead");
     }

     @Override
     public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
         super.onDescriptorWrite(gatt, descriptor, status);
         LogUtil.d("onDescriptorWrite");
     }

     @Override
     public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
         super.onReliableWriteCompleted(gatt, status);
         LogUtil.d("onReliableWriteCompleted");
     }

     @Override
     public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
         super.onReadRemoteRssi(gatt, rssi, status);
         LogUtil.d("onReadRemoteRssi");
     }

     @Override
     public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
         super.onMtuChanged(gatt, mtu, status);
         LogUtil.d("onMtuChanged");
     }
 };

“`

//字符串转byte
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }



 // 转化字符串为十六进制编码
    public static String toHexString(String s) {
        String str = "";
        for (int i = 0; i < s.length(); i++) {
            int ch = (int) s.charAt(i);
            String s4 = Integer.toHexString(ch);
            str = str + s4;
        }
        return str;
    }
// 转化十六进制编码为字符串
    public static String hexToString(String s) {
        byte[] baKeyword = new byte[s.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {
                baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(
                        i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            s = new String(baKeyword, "utf-8");// UTF-16le:Not
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return s;
    }

低功耗蓝牙Android 4.3版本以上支持 Api》18

  • Service : 服务
  • Characteristic : 特征

1 Profile,可以理解为一种规范,一种通信协议,profile存在于从机中。SIG规定了一些profile,如心率计,防丢器,HID OVER GATT等等。每个Profile中都包含多个Service。每个Service代表从机的一个能力。

2、Service可以理解为一个服务,在BLE从机中,可以有多个服务,譬如系统电量信息服务,系统信息服务,每个Service又包含多个Characteristic。每个具体的Characteristic值才是BLE通信的主体。比如当前电量是80%,会通过电量的Characteristic特征值存在从机的Profile里面,这样,主机就可以通过这个Characteristic值获得从机的80%电量值。

3、Characteristic BLE主从机通信均通过Characteristic实现。 可以理解为一个标签,通过这个标签可以获取或写入想要的内容。

4、UUID 唯一识别码。上述Service 和 Characteristic 均需要通过一个UUID来识别。UUID为128,但是在BLE中,UUID通常用16位,也就是两个字节来替代。16位UUID和128位UUID可以相互转换,具体如何实现需参考SIG文档。

综上,每个从机均由一个或若干个profile构成,不管是simpleprofile还是防丢器Profile等,而每个profile又由一些列Service组成,每个Service包含若干个Characteristic。 主机和从机之间的通信均是由 Characteristic实现。

蓝牙低能耗技术采用可变连接时间间隔,这个间隔根据具体应用可以设置为几毫秒到几秒不等。另外,因为BLE技术采用非常快速的连接方式,因此平时可以处于“非连接”状态(节省能源),此时链路两端相互间只是知晓对方,只有在必要时才开启链路,然后在尽可能短的时间内关闭链路。

每个蓝牙4.0的设备都是通过服务和特征来展示自己的,一个设备必然包含一个或多个服务,每个服务下面又包含若干个特征。特征是与外界交互的最小单位。比如说,一台蓝牙4.0设备,用特征A来描述自己的出厂信息,用特征B来与收发数据等。

服务和特征都是用UUID来唯一标识的,UUID的概念如果不清楚请自行google,国际蓝牙组织为一些很典型的设备(比如测量心跳和血压的设备)规定了标准的service UUID(特征的UUID比较多,这里就不列举了),如下:

 蓝牙4.0分为标准蓝牙和低功耗蓝牙(BLE),标准蓝牙就是手机上用的那种,低功能耗蓝牙由于其具有最大化的待机时间、快速连接和低峰值的发送和接收特性,被广泛用于智能手表、智能手环等可穿戴设备上。在安卓4.3之前,安卓平台上的BLE开发相当难搞,好在谷歌在4.3之后发布了官方的API。在安卓5.0之后又引入了新的API,原来的API已经被废弃。在新的系统里采用旧API开发的APP仍可使用,但采用新API开发的APP只能在LOLLIPOP即安卓5.0及其以后的版本使用。

坑

  • Android从4.3(API 18)才支持BLE,只支持作为中心设备 (Central) 模式,这就意味着 Android 设备只能主动扫描和链接其他外围设备 (Peripheral)(两个同是中心设备或者两个同是外围设备是无法连接的)。从Android 5.0(API Level 21)开始两种模式都支持(绝大部分)
  • 官方的Demo在6.0设备上会有动态权限问题 java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results
    动态申请或者把target降到23以内
经典蓝牙与低功耗蓝牙的区别(4) 文章所有资料全部已经打包整理好,另外小编手头上整理了大量Android架构师全套学习资料,Android核心高级技术PDF文档+全套高级学习资料+视频+2021 BAT 大厂面试真题解析资料展示:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取![外链图片转存中…(img-SEsPuU4S-1715355730334)]《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取! 阅读详情

相关推荐

低功耗蓝牙通讯 C# WinForm

因为项目需要上位机软件与下位机的蓝牙模块进行通讯,所以上网查阅了很多关于蓝牙通讯的资料。刚开始以为使用现成的库就可以了,像InTheHand,发现无法搜索到蓝牙设备。后来查询资料知道,由于我们的下位机使用的是低功耗蓝牙,很多蓝牙通讯的库不适用低功耗蓝牙。再后来发现,我们的上位机软件是使用WinForm开发的,网上关于WinForm开发低功耗蓝牙的资料很少。整个开发过程挺不容易的,也踩了很多坑,终于可以正常与蓝牙模块进行通讯了。一、添加引用。.........

m0_59535491的博客 6012

ActivityCompat使用

今天在查看资料的时候看到了ActivityCompat这个类来启动Activity,ActivityCompat是v4包里新加的一个类,打开了看了看代码:&lt;span style="font-family:SimSun;font-size:14px;"&gt;public static void startActivity(Activity activity, Intent intent, @...

专栏 2万+

低功耗蓝牙抓包

低功耗蓝牙数据包嗅探 工具: 蓝牙嗅探工具:nrf51822-Dongle一个 Wireshark 安卓手机一台 这里使用nrf51822结合Wireshark来捕获低功耗蓝牙数据包; nrf51822的外观: 操作步骤 1.到nrf官网(https://www.nordicsemi.com)下载对应的Segger-jlink工具、Dongle工具包、Sniffer...

samli的博客 4497

【Java】Android动态权限相关问题梳理

Android 6.0开始,对敏感权限需要动态申请,首先我们需要引入android.support.v4的兼容包,然后使用ActivityCompat这个类来处理权限。 其实Activity自身也可以处理动态权限,不需要额外引入ActivityCompat。

devnn的专栏 5104

Android v4和v7包 appcompat-v7:23.1.1 支持AppCompatActivity

2015年末最新的v7库,源码中找出来的,赚点辛苦费,在eclipse上使用的依赖包,其中包括最新的V4和V7包,这个风格是要这2个包支持的,确切的说是V7需要V4的支持

eclipse ActivityCompat.shouldShowRequestPermissionRationale没有

eclipse旧的v4不能引入部分资源,和部分方法缺失。eclipse中contextcompat.checkselfpermission没有 ActivityCompat.shouldShowRequestPermissionRationale没有,没分的可以滴滴我,有的就送点

Android开发学习日记--运行时动态申请应用权限

方法,即可命令系统自动弹出权限申请窗口,该方法的第一个参数为活动实例,第二个参数为待申请的权限名称数组,第三个参数为本次操作的请求代码。第三步,判断用户的权限选择结果。如果是Android6.0以上才用动态申请权限,也就是下面要讲的。方法,该方法的第一个参数为活动实例,第二个参数为待检查的权限名称。,如果当前页面请求弹出权限申请窗口,那么该页面的Java。这种情况大多出现在刚安装完软件,进入软件的时候。方法,并在该方法内部处理用户的权限选择结果。先写个工具类PermissionUtil。...

m0_52238102的博客 3231

欢乐熊大话蓝牙知识16:蓝牙是怎么找设备的?扫描与广播的“对话内幕”

蓝牙是怎么找设备的?扫描与广播的对话技术介绍

hoony123的博客 1382

Android: 动态运行时权限(危险权限)源码分析、封装、及9.0权限改动

简介: 动态运行时权限的检测流程分析:(Android 6.0开始就有了危险权限) ActivityCompat.requestPermissions() ActivityCompat.shouldShowRequestPermissionRationale() ActivityCompat.checkSelfPermission(value) Android 9.0 对于权限处理和6.0...

手写我对你的温柔 4553

Claude Code VSCode集成开发指南:AI编程助手完整配置

Claude Code与Visual Studio Code的深度集成为开发者提供了强大的AI编程支持。本文详细介绍Claude Code VSCode扩展的安装配置、功能特性和实际应用方法。通过完整的配置流程和代码示例,帮助开发者充分利用Claude AI的智能编程能力。文章涵盖从环境搭建到高级功能应用的完整指南,包括代码自动补全、智能重构、实时代码分析等核心功能的使用技巧,以及与现有开发工作流的整合方案。

2501_93058131的博客 5984

解决[WARN] : Controller Spawner couldn‘t find the expected controller_manager ROS interface.思路

rrbot例程ros_control配置问题的解决思路 本人刚入门ROS机器人开发,在学习rrbot例程出现了control_manager无法启动的bug。 在启动rrbot_control.launch的时候,出现下列warning: [WARN] [1594362016.372059]: Controller Spawner couldn't find the expected controller_manager ROS interface. 之后再按教程的步骤 rosservice call /

qq_40299650的博客 1万+

Android开发学习之路-Android6.0运行时权限

在Android6.0以后开始,对于部分敏感的“危险”权限,需要在应用运行时向用户申请,只有用户允许的情况下这个权限才会被授予给应用。这对于用户来说,无疑是一个提升安全性的做法。那么对于开发者,应该怎么做呢? Android6.0规定的危险权限有下面这些: Permission GroupPermissions CALENDAR READ_CALENDA...

weixin_30242907的博客 405

计算pi小数点后10000位

数据结构课上,老师让我们计算一下pi的10000位,复习一下面向对象。 First Try:定义一个高精度类hp(high precision),实现加减乘除,输入输出,然后随便找一个公式,比如Wallis公式,全都用hp进行计算。 现实是:大数乘大数或者大数除大数,实在是太慢了。而且Wallis公式收敛太慢。 Second Try先找到一个收敛较快的公司:BBP公式,观察公式发现,...

我的技术人生 7395

网络靶场实战-低功耗蓝牙初探

这一小节,我们学习蓝牙无线通信的基础知识,以及对蓝牙智能手环的简单抓包分析和攻击,初步理解了低功耗蓝牙的内容。

蛇矛实验室 2170

Unity中5分钟实现3D高斯泼溅渲染:从原理到实战部署

3D高斯泼溅(3D Gaussian Splatting)是一种新兴的神经渲染技术,它通过显式地使用大量3D高斯椭球来表示场景,革新了传统的体渲染和神经辐射场(NeRF)方法。其核心原理是将这些3D高斯投影到2D屏幕并进行快速光栅化与Alpha混合,从而绕过了耗时的光线步进,实现了极高的渲染效率。这项技术的价值在于,它能够在消费级GPU上达到实时甚至超实时的帧率,同时保持紧凑的数据表达和惊人的视觉细节,极大地降低了高质量3D重建与渲染的门槛。在应用场景上,它正快速渗透到数字孪生、虚拟现实、文化遗产数字化以及

weixin_29474431的博客 275

【2024年华为秋招-12月25日-第三题(300分)- PCB印刷电路板布线】(题目+思路+Java&C++&Python解析+在线测试)

在PCB印刷电路板设计中,器件之间的连线需要避免线路的阻抗值增大、而且赛件之间还有别的器件和别的干扰源,在布线时我们希望受到的干扰尽量小。现将电路板简化成一个M×N的矩阵,每个位置(单元格)的值表示其源干扰度。如果单元格的值为0,表示此位置没有干扰源;如果单元格的值为非0,则表示此位置是干扰源,其值为源干扰度。连线经过干扰源或干扰源附近会增加连线的总干扰度。位置Axy的干扰源的源干扰度为dd01、若连线经过位置Axy,则其总干扰度会增加d;2、若连线经过离位置A。

m0_73659489的博客 344

android 蓝牙5.0初探之低功耗扫描

今天闲着没啥事,然后我旁边的IOS同事要学安卓,因为公司是做蓝牙的,我就把我的一个简单的蓝牙demo给了他,然后他在看的时候问我为啥代码中间会有跟横线,于是我也去看了下发现如下: 很明显是有新方法了,于是乎来兴趣了,二话不说直接看谷老大API https://developer.android.google.cn/about/versions/marshmallow/android-6.0.

noheartheflower的博客 8619

从零构建Fama-French多因子模型:量化投资系统开发实战

本文详细介绍了如何从零构建Fama-French多因子模型,并将其应用于量化投资系统的开发。首先,文章概述了Fama-French多因子模型的背景、核心原理和架构,解释了其如何通过引入市场风险、规模、价值、盈利和投资等因子来解释股票收益率的变化。接着,文章详细阐述了构建该模型的具体步骤,包括因子的计算、因子暴露的确定以及模型的估计。通过数学模型和公式,文章对模型进行了理论推导,并举例说明了其应用。此外,文章还提供了项目实战的代码案例,从开发环境搭建到源代码实现,逐步指导读者完成量化投资系统的开发。最后,文章

2501_92132293的博客 1226

2、低功耗蓝牙(BLE)协议栈 初探

BLE协议栈为什么要分层?怎么理解BLE“连接”?如果BLE协议只有ATT层没有GATT层会发生什么? 协议栈框架 一般而言,我们把某个协议的实现代码称为协议栈(protocol stack),BLE协议栈就是实现低功耗蓝牙协议的代码,理解和掌握BLE协议是实现BLE协议栈的前提。在深入BLE协议栈各个组成部分之前,我们先看一下BLE协议栈整体架构。 如上图所述,要实现一个BLE应用,首先需要一个支持BLE射频的芯片,然后还需要提供一个与此芯片配套的BLE协议栈,最后在协议栈上开发自己的应用。...

雪飞_海 492

QGis二次开发 —— 5、基于qgis开发多种在线地图预览,并加入经纬度坐标显示等(附:源码)

QGis二次开发 —— 5、基于qgis开发多种在线地图预览,并加入经纬度坐标显示等(附:源码

369

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

物联网安全拔“牙”实战——低功耗蓝牙(BLE)初探

物联网安全拔“牙”实战——低功耗蓝牙(BLE)初探 唐朝实验室·2015/10/30 10:22 Author: FengGou 0x00 目录 0x00 目录 0x01 前言 0x02 BLE概述 BLE 协议栈总览 GAP-通用访问规范 GATT-通用属性协议 0x03 BLE嗅探 0x04 伪造BLE通信 0x05 分析BLE私...

1335

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

低功耗蓝牙协议(BLE)初探:了解BLE协议的运作原理

Bluetooth Low Energy (BLE) 是从蓝牙 4.0 开始引入的技术,又被称为 Bluetooth Smart。与经典的蓝牙相比,BLE 主要的特点是能够在维持相对低的功耗的同时实现通信。BLE因为其低功耗特性成为了物联网领域的一项重要技术,为大量的设备提供了长时间的运行期。现代智能手机中的蓝牙芯片一般被设计为“双模”(Dual-mode),这意味着它可以同时支持经典蓝牙和BLE。

Reveone的博客 8935

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Android BLE与终端通信(五)——Google API BLE4.0低功耗蓝牙文档解读之案例初探

Android BLE与终端通信(五)——Google API BLE4.0低功耗蓝牙文档解读之案例初探 算下来很久没有写BLE的博文了,上家的技术都快忘记了,所以赶紧读了一遍Google的API顺便写下这篇博客心得 Google API:http://developer.android.com/guide/topics...

weixin_34168880的博客 369

积跬步至千里系列之四--低功耗蓝牙通信(一)

最近空闲时间研究了下低功耗蓝牙通信方面的知识,蓝牙这块在平时的开发过程中并不常见,借着刚刚看过的知识点,记录在此。

sdjzyuxinburen的专栏 632
上一篇: 汉字转拼音小型类库推荐
下一篇: Splash页面优化
Ksee
博客等级 码龄12年 1粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值