蓝牙BLE设备连接与通信

Android 低功耗蓝牙开发(数据交互) 现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水!为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!Android架构师之路很漫长,一起共勉吧! 阅读详情

1、在建立BLE设备进行通信时注意3点


1.1、蓝牙位置权限必须动态申请(Android 6.0以上),如果没有动态申请会出现下面的问题
Need BLUETOOTH permission: Neither user 10063 nor current process has android.permission.BLUETOOTH.
1.2、尽管设置了BluetoothGatt中的setCharacteristicNotification(),但无法触发BluetoothGattCallback中的onCharacteristicChanged()方法
需要重新写setCharacteristicNotification()方法
1.3、读写和设置通知都是单步操作,必须执行完一个才能执行第二个,否则会操作失败

 

2、BLE通信基本流程


作者认为BLE连接与通信关键点是两个回调。
2.1、蓝牙扫描回调(BluetoothAdapter.LeScanCallback、ScanCallback(此方法使用不在赘述,参见作者的蓝牙扫描(简单)))
如果蓝牙扫描成功会执行onLeScan方法,可以获得设备的基本信息,例如:设备名字、设备地址

2.2、蓝牙连接回调(BluetoothGattCallback)
这个回调方法比较多需要细看。这个回调中常用的有以下几个方法:
onConnectionStateChange:当回调执行、状态发生变化时执行,在此方法中常用来搜索服务(BluetoothGatt#discoverServices())
onServicesDiscovered:当搜索服务执行时执行,在此方法中可以获得蓝牙设备服务的相关信息和特征的信息,例如:服务的UUID、特征的UUID、特征的属性等。
onCharacteristicWrite:当向蓝牙设备发送写命令(BluetoothGatt#writeCharacteristic())时执行,在此方法中可以获得蓝牙设备发送命令的执行状态。
onCharacteristicChanged:当向蓝牙设备发送写命令成功,并且提醒移动设备接收蓝牙设备返回的数据(BluetoothGatt#setCharacteristicNotification())时执行,此方法用来处理蓝牙返回的数据。
onCharacteristicRead:当向蓝牙设备发送读命令(BluetoothGatt#readCharacteristic())执行。

2.3、建立通信的过程
动态申请蓝牙位置权限;
获得蓝牙适配器、判断蓝牙是否支持、蓝牙是否打开;
扫描蓝牙(调用BluetoothAdapter.LeScanCallback、或者调用ScanCallback),在onLeScan(或者调用onScanResult)中处理蓝牙回调的蓝牙设备信息;
与蓝牙设备建立连接(调用BluetoothGattCallback),首先在onConnectionStateChange()方法中搜索服务,然后在onServicesDiscovered()方法中获得服务的UUID、特征的UUID和目标特征,根据服务的UUID、特征的UUID和目标特征与蓝牙设备建立连接,并向设备发送写命令,同时提醒移动设备接收蓝牙数据;
在onCharacteristicChanged方法中接收蓝牙返回的数据。

2.4、蓝牙通用唯一识别码(UUID,Universally Unique Identifier)的理解
一个设备中有多个服务(多个服务的UUID),一个服务中有多个特征(多个特征的UUID),多个设备的UUID可以都相同。
例如:
设备1:dev-01{server1(ser_UUID-01):{characteristic1_1(char1_UUID-01),characteristic1_2(char1_UUID-02),characteristic1_3(char1_UUID-03)},
server2(ser_UUID-02):{characteristic2_1(char2_UUID-01),characteristic2_2(char2_UUID-02),characteristic2_3,(char2_UUID-03)}}

设备2:dev-02{server1(ser_UUID-01):{characteristic1_1(char1_UUID-01),characteristic1_2(char1_UUID-02),characteristic1_3(char1_UUID-03)},
server2(ser_UUID-02):{characteristic2_1(char2_UUID-01),characteristic2_2(char2_UUID-02),characteristic2_3,(char2_UUID-03)}}

 

3、权限


    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-feature
        android:name="android.hardware.bluetooth_le"
        android:required="true" />

 

4、xml代码


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <Button
        android:id="@+id/search"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="搜索"/>

    <Button
        android:id="@+id/link"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="连接"/>

    <Button
        android:id="@+id/getData"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="接收数据"/>

    <TextView
        android:id="@+id/result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="数据字节长度"/>
    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </ListView>
</LinearLayout>

 

5、java代码

 

public class MainActivity extends AppCompatActivity {

    private ArrayList<String> data = null;
    private ListView listView = null;
    private BluetoothAdapter bta = null;
    private BluetoothManager btm = null;
    private Button button = null;
    private Button link = null;
    private Button getDataButton = null;
    private TextView result = null;

    ArrayAdapter<String> adapter = null;

    private  BluetoothGatt btg = null;
    private BluetoothDevice mDevice=null;
    private Handler handler = new Handler();

    private boolean isScanning = true;
    private boolean isLinking = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 获得数据
        this.data = new ArrayList<>();
        // 初始化控件
        this.initView();
        this.checkBlePermission();
    }


    // 初始化控件
    private void initView() {
        this.result = findViewById(R.id.result);

        // 获得button
        this.button = findViewById(R.id.search);
        this.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 扫描蓝牙
                scanBle();
            }
        });

        this.link = findViewById(R.id.link);
        this.link.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(!isScanning){
                    linkBlue();
                }else {
                    Toast.makeText(MainActivity.this, "没有扫描到蓝牙设备",Toast.LENGTH_SHORT).show();
                }
            }
        });

        this.getDataButton = findViewById(R.id.getData);
        this.getDataButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(isLinking){
                    getData();
                }else {
                    Toast.makeText(MainActivity.this, "蓝牙设备没建立连接",Toast.LENGTH_SHORT).show();
                }
            }
        });

        // 初始化ListView
        this.adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, this.data);
        this.listView = findViewById(R.id.lv);
        this.listView.setAdapter(adapter);
    }

    /*----- 搜索蓝牙设备 -----*/
    // 扫描蓝牙
    private void scanBle() {
        btm = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        // 初始化蓝牙适配器
        if(btm == null){
            return;
        }
        bta = btm.getAdapter();
        if(bta == null){
            this.result.setText("The bluetooth not support");
            this.result.setVisibility(View.VISIBLE);
            return;
        }

        // 打开蓝牙
        if (!bta.isEnabled()) {
            Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enable, 1);
        } else {
            bta.startLeScan(oldBtsc);
            // 设置扫描时间
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    bta.stopLeScan(oldBtsc);
                    Log.d("------------","停止扫描");
                }
            }, 8000);
        }
    }
    private BluetoothAdapter.LeScanCallback oldBtsc = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
            if(device.getName().equals("ECG-XA01")){
                mDevice=device;

                data.add(device.getAddress() + ""+ device.getName());
                Log.d("------------", device.getAddress());

                adapter.notifyDataSetChanged();
                bta.stopLeScan(oldBtsc);

                isScanning = false;
            }

        }
    };

    /*----- 搜索蓝牙服务和特征 -----*/
    // 连接蓝牙
    private void linkBlue(){
        btg = mDevice.connectGatt(MainActivity.this, true, btgcb);
    }

    // 获得数据
    private void getData(){
        BluetoothGattService service = btg.getService(UUID.fromString("0000180F-0000-1000-8000-00805F9B34FB"));
        BluetoothGattCharacteristic characteristic1= service.getCharacteristic(UUID.fromString("11111102-5544-7766-9988-AABBCCDDEEFF"));
        setCharacteristicNotification(characteristic1, true);
        if(btg.writeCharacteristic(characteristic1)){
            Log.d("------------","writeCharacteristic");
        }
    }
    private BluetoothGattCallback btgcb = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if(newState == BluetoothGatt.STATE_CONNECTED){
                Log.d("------------","ConnectionStateChange");
                // 搜索服务
                btg.discoverServices();
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            Log.d("------------","ServicesDiscovered");

            if (status == BluetoothGatt.GATT_SUCCESS) {
                List<BluetoothGattService> supportedGattServices = btg.getServices();
                for(int i=0;i<supportedGattServices.size();i++){
                    Log.d("------------","1:BluetoothGattService UUID=:"+supportedGattServices.get(i).getUuid());
                    List<BluetoothGattCharacteristic> listGattCharacteristic=supportedGattServices.get(i).getCharacteristics();
                    for(int j=0;j<listGattCharacteristic.size();j++){
                        Log.d("------------","2:BluetoothGattCharacteristic UUID=:"+listGattCharacteristic.get(j).getUuid());
                    }
                }

                BluetoothGattService service1 = btg.getService(UUID.fromString("0000300F-0000-1000-8000-00805F9B34FB"));
                final BluetoothGattCharacteristic characteristic1= service1.getCharacteristic(UUID.fromString("11111101-5544-7766-9988-AABBCCDDEEFF"));

                characteristic1.setValue(new byte[]{0x01, 0x01});
                btg.writeCharacteristic(characteristic1);
                btg.setCharacteristicNotification(characteristic1, true);
                Log.d("------------","write success ");
            } else {
                Log.d("------------", "onservicesdiscovered收到: " + status);
            }
        }
        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);

        }
        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            Log.d("------------", "CharacteristicWrite" + status);
            if(status == BluetoothGatt.GATT_SUCCESS){
                // 连接成功
                isLinking = true;
            }

        }
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            Log.d("------------", "CharacteristicChanged");
            // 查看字节长度
            Log.d("------------", characteristic.getValue().length+" ");
            result.setText("获得字节长度:"+characteristic.getValue().length);
        }
    };

    // 如果setCharacteristicNotification()不能触发onCharacteristicChanged()方法时,调用此方法
    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
        if (bta == null || btg == null) {
            Log.w("------------", "BluetoothAdapter not initialized");
            return;
        }
        btg.setCharacteristicNotification(characteristic, enabled);
        List<BluetoothGattDescriptor> descriptors = characteristic.getDescriptors();
        for (BluetoothGattDescriptor dp : descriptors) {
            dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            btg.writeDescriptor(dp);
        }
    }

    // 位置权限动态申请(ACCESS_COARSE_LOCATION)
    public void checkBlePermission() {
        if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
            // 调用系统的方法
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},1);
        } else {
            Log.i("tag", "已申请位置权限");
        }
    }
    // 位置权限动态申请(ACCESS_COARSE_LOCATION)
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            // 此处的1与上文的checkBlePermission()方法中ActivityCompat.requestPermissions的1(requestCode)对应
            case 1: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.i("tag", "同意位置申请");
                } else {
                    Log.i("tag", "拒绝位置申请");
                }
                return;
            }
        }
    }

}

Need BLUETOOTH_PRIVILEGED permission app能在5.0以前的系统上正常运行,但是在5.0以及更高的版本就不行了,每次去设置通知的时候,会报:Need BLUETOOTH_PRIVILEGED permission: Neither user 10157 nor current process has android.permission.BLUETOOTH_PRIVILEGED这种错误,我的清单文件里面已经添加了这个权限 阅读详情

相关推荐

【 ESP32双模蓝牙连接完整教程】BLE与经典蓝牙SPP实战 > 基于ESP32-DevKit-C的BLE和经典蓝牙SPP连接实现,包含RSSI读取、设备发现和数据通信

BLE连接:设备发现、GATT连接、RSSI读取经典蓝牙SPP连接:串口协议通信、设备配对AT命令控制:通过串口命令控制蓝牙功能实时RSSI监测:支持信号强度实时获取配置匹配最重要: 端口号、安全级别必须与目标设备匹配获取准确的设备信息: 咨询目标设备开发者获取正确配置完善的错误处理: 详细的日志和状态检查模块化设计: BLE和经典蓝牙功能独立,便于维护。

意愿三七 1536

android蓝牙write,java – Android蓝牙状态133在onCharacteristicwrite

我是Android的新手,现在正在做一个简单的应用程序,需要将一些数据写入外围设备.三星GT-S7272C设备其实没有什么问题.但是当我切换到Sony LT29i时,当我试图写入某个特性时,总是会有一个状态133.我会给出一些简短的代码.BluetoothGattService syncService = gatt.getService(SYNC_DATA_SERVICE);BluetoothGa...

weixin_34748612的博客 1120

Unity+Arduino蓝牙通信避坑指南:5分钟搞定BLE设备连接(含完整代码示例)

本文详细介绍了Unity与Arduino通过BLE(低功耗蓝牙)实现高效通信的完整方案,包括环境配置、设备连接核心流程、数据交换优化策略及实战案例。重点解析BLE与经典蓝牙协议的差异,提供可直接复用的代码示例,帮助开发者快速解决智能硬件交互中的通信问题。

c2d3e4f的博客 1029

【转】android 4.3 BLE onCharacteristicWrite没有回调

原文网址:http://bbs.youkuaiyun.com/topics/390882717?page=1 问题1.我在自己程序有开一个Timer定时去readCharacteristic, 每次read可以成功,但是在此过程中再调用writeCharacteristic之后发现BLE设备没有接收到设置的数据,没有执行onCharacteristicWrite这个回调,把Timer关闭掉不执行readCh...

weixin_34018169的博客 980

Windows双模蓝牙开发:基于EDR连接自动发现并通信Ble设备

本文详细解析了在Windows平台上实现双模蓝牙通信的完整方案。针对已通过经典蓝牙(EDR)连接的设备,如何自动发现并与其低功耗蓝牙(Ble)部分建立通信。文章核心在于利用经典蓝牙MAC地址,通过UWP API的DeviceWatcher精准定位对应的Ble设备,并提供了从设备枚举、地址匹配到GATT连接与数据收发的完整C++/WinRT代码实现与实战避坑指南。

weixin_29214335的博客 598

Android 低功耗蓝牙BLE连接通信

简介 蓝牙(Bluetooth®):是一种无线技术标准,可实现固定设备、移动设备和楼宇个人域网之间的短距离数据交换(使用2.4—2.485GHz的ISM波段的UHF无线电波)。蓝牙技术最初由电信巨头爱立信公司于1994年创制,当时是作为RS232数据线的替代方案。蓝牙可连接多个设备,克服了数据同步的难题。 蓝牙 4.0 蓝牙技术联盟于2010年6月30日正式推出蓝牙核心规格4.0 。它包...

hwx865的专栏 3160

Android蓝牙开发终极指南:BLE通信与设备连接的完整教程

想要掌握Android蓝牙开发的核心技术吗?🤔 这篇**Android蓝牙开发终极指南**将带你从零开始,深入了解BLE通信和设备连接的完整流程。无论你是初学者还是有经验的开发者,这份教程都能为你提供实用的开发指南和最佳实践。 在今天的移动应用开发中,**蓝牙低功耗(BLE)技术**已成为连接智能设备的重要桥梁。从健康监测设备到智能家居,BLE为Android应用提供了高效、低功耗的通信解决方

gitblog_00367的博客 760

Unity与Arduino蓝牙通信实战:5分钟搞定BLE设备连接

蓝牙低功耗(BLE)技术是物联网设备实现低功耗、短距离无线通信的核心协议。其基于GATT(通用属性配置文件)的通信模型,通过定义服务(Service)和特征值(Characteristic)来标准化数据交换,开发者无需深入射频底层即可实现设备间的高效交互。这一技术为虚拟与现实世界的连接提供了关键桥梁,在体感游戏、智能家居中控、实时数据监控等交互场景中价值显著。本文聚焦于利用ESP32开发板构建BLE服务器,并结合Unity引擎的新Input System,详细解析了从环境配置、代码编写到联调测试的全流程,旨

weixin_29183637的博客 302

基于BLE低功耗蓝牙实现与蓝牙设备的连接和数据通信

基于BLE低功耗蓝牙实现与蓝牙设备的连接和数据通信

qq_42500408的博客 3495

AndroidStudio低能耗蓝牙协议BLE通信

SPP是蓝牙2.0版本时主要采用的通信协议,需要通过设备MAC地址建立socket连接,然后通过inputStream和outputStream进行通信。BLE是蓝牙4.0版本开始使用的通信协议,是基于Gatt(通用属性配置文件)的通信方式。BLE支持扫描周边设备并建立连接,而SPP需要提前建立蓝牙连接。BLE扫描周边设备并获取想要的设备,建立gatt连接,通过双方设备定义好的服务特性获取BluetoothGattService并进行相关定义;

pumbkin的博客 2071

Android WriteCharacteristic流程 & Bluedroid源码刨析

通过BluetoothGatt向BLE设备写入数据,涉及获取BluetoothGatt与Characteristic对象、设置数据并调用writeCharacteristic方法。源码刨析显示,此操作需确保权限、连接状态及设备支持,并异步执行,通过回调返回结果。该流程涉及多层交互,包括应用层API调用、JNI层native方法调用及HAL层接口实现,确保数据准确传输至BLE设备。

byte轻骑兵的技术小窝 3933

Kotlin/Native蓝牙开发:BLE设备连接与通信

在物联网(IoT)和移动设备开发中,蓝牙低功耗(Bluetooth Low Energy,BLE)技术已成为设备间通信的重要标准。Kotlin/Native作为Kotlin的多平台解决方案,为开发者提供了在原生环境中使用Kotlin进行BLE开发的强大能力。本文将深入探讨如何使用Kotlin/Native实现BLE设备的连接与通信。 ## Kotlin/Native BLE开发架构 ### 技...

gitblog_00664的博客 993

Android蓝牙开发:BLE设备连接与通信实战

BLE与传统蓝牙的区别Android BLE开发的核心APIBLE设备连接与通信的完整流程实际开发中的最佳实践和常见陷阱文章将从BLE基础概念开始,逐步深入到Android API的具体实现,最后通过一个完整的实战项目展示BLE开发的完整流程。每个技术点都将配有详细的代码示例和原理说明。:蓝牙低功耗技术,专为低功耗设备设计:定义BLE设备间数据传输的标准方式:用于标识服务、特征和描述符的唯一ID:GATT服务中的数据字段,包含值和描述符Descriptor:描述特征属性的元数据。

移动开发前沿的博客 1410

Android BLE蓝牙通信终极指南:5步快速集成智能设备连接

想要在Android应用中实现智能设备的BLE蓝牙通信?Android-BluetoothKit是您的最佳选择!这个强大的Android BLE蓝牙通信库能够帮助开发者快速集成智能设备连接功能,无论是健康手环、智能家居还是物联网设备,都能轻松搞定。🚀 ## 为什么选择Android-BluetoothKit? Android-BluetoothKit是一个专为Android平台设计的BLE蓝

gitblog_00836的博客 746

随机截距交叉滞后模型RI-CLPM:原理、Mplus实现与结果解读

纵向面板数据分析中,传统交叉滞后模型(CLPM)常被用于探索变量间的时序关系,但其估计结果可能混淆了个体间稳定差异与个体内短期波动,导致交叉滞后路径出现偏差。随机截距交叉滞后模型(RI-CLPM)通过引入随机截距因子,将个体特质层面的差异与个体内动态过程分离,从而提供更纯净的个体内效应估计。该模型在组织心理学、发展心理学、成瘾行为等研究领域迅速普及,并成为顶级期刊审稿时常见的稳健性检验要求。本文从原理出发,系统讲解RI-CLPM的模型构建、识别条件、Mplus实操代码、输出解读及常见陷阱,并结合协变量处理、

weixin_33525298的博客 275

S4-FPGA-K7板级原理图硬件实战

xilinx K7板级硬件实战

weixin_66510961的博客 6152

Flutter Reactive BLE多设备连接优化:提升蓝牙通信稳定性的7个方法

Flutter Reactive BLE是一个强大的Flutter库,专为处理多设备的蓝牙低功耗(BLE)操作而设计。它支持BLE设备发现、主机设备BLE状态观察、建立BLE连接以及维护多个BLE设备的连接状态,是开发蓝牙应用的理想选择。 [![Flutter Reactive BLE logo](https://raw.gitcode.com/gh_mirrors/fl/flutter_rea

gitblog_00132的博客 1043

Type-C转DP1.4转C双向互传转接线方案

Type-C转DP双向互转方案的核心在于利用Type-C接口中的Alt Mode(交替模式)功能。通过利用Type-C接口的Alt Mode功能,该方案实现了Type-C接口与DP接口之间的双向互传,极大地丰富了用户的视觉体验。在选择Type-C转DP双向互转方案时,用户需要关注兼容性、性能需求、线缆长度和品牌等因素,以确保获得最佳的传输质量和使用体验。因此,Type-C转DP双向互转方案应运而生,旨在实现Type-C接口与DP接口之间的无缝连接,满足用户对高效能和高清晰度视频传输的需求。

m0_70875024的博客 4976

Android BLE蓝牙通信开发终极指南:5个步骤轻松搞定低功耗设备连接

Android BLE蓝牙通信开发是连接智能手表、健康监测设备、智能家居等低功耗物联网设备的关键技术。Android-BluetoothKit框架提供了简单易用的接口,屏蔽了蓝牙通信中的复杂技术细节,让开发者能够快速实现设备扫描、连接、读写和通知等核心功能。🚀 ## 📱 为什么选择Android-BluetoothKit? 这个开源框架解决了Android蓝牙开发中的多个痛点: - **

gitblog_00161的博客 1004

2.4G/4G天线共存方案:Air8101多频段隔离设计实战(附波长计算表)

本文深入探讨了物联网设备中Wi-Fi 2.4GHz与4G LTE天线共存设计的实战方案。针对B40与2.4G频段紧邻带来的干扰挑战,文章系统性地提出了空间隔离、PCB布局优化、结构设计三重防线,并提供了关键的波长计算工具与系统级验证Checklist,旨在帮助工程师将多频段隔离设计从“玄学”变为可执行的工程规范。

weixin_29197051的博客 389

【OpenStack】OpenStack原理(一)——OpenStack发展及架构

OpenStack目前的七个核心组件,分别是计算(Compute)、对象存储(Object Storage)、认证(Identity)、用户界面(Dashboard)、块存储(Block Storage)、网络(Network)和镜像服务(Image Service)。

大数据分析BDA 2万+

蓝牙低功耗(BLE)通信的中心设备/外围设备(连接角色)、主机/从机(时序角色)、客户端/服务器(数据交互角色)的理解

在蓝牙低功耗(BLE)通信中,中心设备/外围设备(连接角色)、主机/从机(时序角色)、客户端/服务器(数据交互角色)是三组不同维度的概念,分别从“连接建立→通信控制→数据交互”的全流程理解它们的关系:

L1643319918的博客 1234

oscp备考,oscp系列——Djinn3靶场:ssti漏洞,pkexec提权

oscp备考,oscp系列——Djinn3靶场:ssti漏洞,pkexec提权难度简单偏上对于低权限shell获取涉及:ssti漏洞对于提权:pkexec提权。

2202_75361164的博客 633

Android BLE 蓝牙通信库

Android-BluetoothKit 项目地址:dingjikerbo/Android-BluetoothKit 简介: Android BLE 蓝牙通信库 更多:作者提 Bug 标签: 这个库用于 Android 蓝牙 BLE 设备通信,支持设备扫描,连接,读写,通知。 这套框架存在的意义 一、统一解决 Android 蓝牙通信过程中的兼容性问题 二、提供...

未来很长,但我会努力的走下去。 1398

基于Flink的流式数据降维实现方案

理解为何实时场景需要降维(解决维度灾难)掌握Flink流处理与降维算法的结合方式学会用Flink实现一个可落地的流式降维系统覆盖内容包括:Flink流处理基础、降维算法选择(侧重在线算法)、Flink与降维的集成方案、实战代码示例,以及工业级场景的应用经验。本文从“为什么需要流式降维”出发,用“快递分拣”的生活案例引出核心概念;接着拆解Flink流处理、数据降维的底层逻辑;然后重点讲解“在线PCA”这一适合流式场景的降维算法,并用Flink实现一个完整的流式降维管道;

AI 领航者的博客 567

YOLOv12改进策略【注意力机制篇】| 添加SE、CBAM、ECA、CA、Swin Transformer等注意力和多头注意力机制

这篇文章带来一个经典注意力模块的汇总,虽然有些模块已经发布很久了,但后续的注意力模块也都是在此基础之上进行改进的,对于初学者来说还是有必要去学习了解一下,以加深对模块,模型的理解。

Limiiiing的博客 1509
上一篇: SurfaceView绘制动态直线
下一篇: Android中自定义蓝牙的MTU
MasonYyp
博客等级 码龄9年 301粉丝 297原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值