RN使用蓝牙扫描

我项目需要用到蓝牙模块,蓝牙扫描到设备并且获取到电量显示到页面上,因此我做了如下demo,使用了react-native-ble-plx这个插件 点击进入官方文档官方文档

1.安卓环境配置(ios暂定,还没做ios,不过下面的方法是兼容的,自行配置ios权限)
android/app/src/main/AndroidManifest.xml加入以下权限代码

  <uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /><uses-permission android:name="android.permission.BLUETOOTH_SCAN" />

2.封装蓝牙相关模块工具包

import {BleManager} from 'react-native-ble-plx'; // 引入蓝牙模块
import {PermissionsAndroid, Platform} from 'react-native';
import {Buffer} from 'buffer';
// 下面这两个常量为了获取设备的电量信息(每个人设备不一样,这里仅作参考)
const batteryServiceUUID = '0000180f-0000-1000-8000-00805f9b34fb'; // 电量服务的UUID
const batteryLevelCharacteristicUUID = '00002a19-0000-1000-8000-00805f9b34fb'; // 电量特征的UUID// 授权(位置,蓝牙扫描,蓝牙连接三个权限,但是我这目前有一个问题,蓝牙连接和蓝牙扫描权限会重复弹出两次框,这个bug后期再改)
const bleManager = new BleManager();
// 位置信息和蓝牙权限信息(请求权限)
export const requestPermissions = async callback => {if (Platform.OS === 'android') {try {let grantedLocation = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION,);let grantedBluetoothScan = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,{title: '请求蓝牙扫描权限',message: '我们需要您的蓝牙扫描权限来扫描设备。',buttonNeutral: '稍后询问',buttonNegative: '拒绝',buttonPositive: '同意',},);let grantedBluetoothConnect = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,{title: '请求蓝牙连接权限',message: '我们需要您的蓝牙连接权限来扫描设备。',buttonNeutral: '稍后询问',buttonNegative: '拒绝',buttonPositive: '同意',},);if (grantedLocation === PermissionsAndroid.RESULTS.GRANTED &&grantedBluetoothConnect === PermissionsAndroid.RESULTS.GRANTED) {console.log('已有权限');callback(true);} else {console.log('某些权限被拒绝');callback(false);}} catch (error) {console.error('权限请求错误:', error);callback(false);}} else {callback(false);}
};// 扫描蓝牙设备
export const scanDevice = callback => {// 参数1可以为null不做限制,也可以为服务的uuid,例如['180D']:心率服务的uuid,这样就只扫描过滤出关于心率服务的设备的uuid,如下// bleManager.startDeviceScan(['180D'], null, (error, scannedDevice)bleManager.startDeviceScan(null, null, (error, scannedDevice) => {if (error) {console.error('扫描错误:', error);callback(ture, error);return;}console.log('scannedDevice', scannedDevice);callback(false, scannedDevice);});
};// 返回信号强度(传入参数为上面的scannedDevice.rssi),每个数字都代表一个信号,我这就是0-5六个信号
export const BluetoothBatteryLevel = level => {let signal = 0;if (level < 0) {signal = Math.abs(level) / 10;} else {signal = 0;}if (signal > 0 && signal <= 3) {return 5;} else if (signal > 3 && signal <= 6) {return 4;} else if (signal > 6 && signal <= 9) {return 3;} else if (signal > 9 && signal <= 12) {return 2;} else if (signal > 12 && signal <= 15) {return 1;} else {return 0;}
};// 断开某个连接的设备,传入的是scannedDevice.id设备编码,如E6:13:27:12:BF:92
export const disconnectAllDevices = async a => {try {if (bleManager) {await bleManager.cancelDeviceConnection(a);}} catch (error) {console.log('断开连接时出错:', error);}
};// 获取蓝牙设备电量(传入的是整个scannedDevice)
export const connectAndDiscoverServices = async (device, callback) => {try {if (device) {bleManager.stopDeviceScan(); // 停止扫描device.connect() // 连接设备.then(device => {console.log('设备已连接:', device.id);return device.discoverAllServicesAndCharacteristics();}).then(device => {return device.services();}).then(services => {// 下面这堆逻辑是处理蓝牙设备电量的services.forEach(service => {if (service.uuid === batteryServiceUUID) {service.characteristics().then(characteristics => {characteristics.forEach(characteristic => {if (characteristic.uuid === batteryLevelCharacteristicUUID) {characteristic.read().then(readData => {console.log('电量:', readData.value);// Step 1: 使用 base64 解码// 这里的Buffer自行安装 yarn add buffer 导入方法如上所示const decodedBytes = Buffer.from(readData.value,'base64',);// Step 2: 将字节数组转换为十六进制字符串const hexString = decodedBytes.toString('hex');// Step 3: 将十六进制字符串解析为十进制数值const decimalValue = parseInt(hexString, 16);console.log('解析后的十进制数值:', decimalValue);callback(true, decimalValue, device); // 将电量信息返回// 这里的 readData.value 可能需要根据设备的具体协议进行解析// 断开连接disconnectAllDevices(device.id);}).catch(error => {console.error('读取电量信息出错:', error);// 断开连接disconnectAllDevices(device.id);callback(false, error);});}});});}});}).catch(error => {console.error('连接设备出错:', error);});}} catch (error) {console.error('连接设备时出错:', error);return null;}
};// 停止扫描
export const stopScan = () => {bleManager.stopDeviceScan();
};

使用demo

import {Button, View, TouchableOpacity, Text} from 'react-native';
import {requestPermissions, // 请求设备权限scanDevice, // 开始扫描设备BluetoothBatteryLevel, // 返回信号强度connectAndDiscoverServices, // 连接设备获取设备电量,然后断开连接(断开连接逻辑在工具包里面)stopScan, // 停止扫描
} from './uitls';
import {useState} from 'react';export default function App() {const [dataArr, setDataArr] = useState([]); // 设备列表const [dianliang, setDianLiang] = useState(0); // 电量// 更新设备数据(已经到扫描到的不会重复添加)function devicesArr(str) {let newData = str;let found = false;setDataArr(arr => {arr = arr.map(item => {if (item.name === newData.name) {found = true;return {...item, xinhao: newData.xinhao};}return item;});if (!found) {arr.push(newData);}return arr;});}// 扫描设备const scanDevices = async () => {// 请求权限await requestPermissions(res => {if (!res) {console.log('未获得必要权限');return;}console.log('开始扫描设备');scanDevice((error, scannedDevice) => {if (error) {console.error('扫描错误:', error);return;}devicesArr({name: scannedDevice.name,xinhao: BluetoothBatteryLevel(scannedDevice.rssi),devices: scannedDevice,});});});};// 连接设备获取电量,然后断开设备async function connectDevice(index, item) {await connectAndDiscoverServices(item.devices,(flag, dianliang, device) => {// dianliang 是设备电量 , flag代表扫描状态, device代表当前设备信息// 断开设备的逻辑在工具文件内if (flag) {console.log('flag,dianliang,device', flag, dianliang, device);setDianLiang(dianliang);}},);}return (<View><Buttontitle="点击获取蓝牙权限"onPress={() => {requestPermissions(res => {console.log('是否获取到了权限', res);});}}></Button><Button title="开始扫描" onPress={scanDevices}></Button><Button title="停止扫描" onPress={stopScan}></Button><Text>选中的设备电量为:{dianliang}</Text>{dataArr.map((item, index) => {return (<TouchableOpacity key={index}><Viewstyle={{flexDirection: 'row',justifyContent: 'space-around',alignItems: 'center',height: 50,}}><Text>信号强度为:{item.xinhao}</Text><Text>{item.name}</Text><TouchableOpacityonPress={() => {connectDevice(index, item);}}style={{flexDirection: 'row',flexDirection: 'row',width: 80,height: 35,borderRadius: 10,justifyContent: 'space-around',alignItems: 'center',borderWidth: 1,}}><Textstyle={{fontSize: 15,}}>获取当前电量完成后断开蓝牙</Text></TouchableOpacity></View><View style={{borderWidth: 0.2, borderColor: '#CCCCCC'}}></View></TouchableOpacity>);})}</View>);
}

效果图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/807411.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[C++][算法基础]走迷宫(BFS)

给定一个 nm 的二维整数数组&#xff0c;用来表示一个迷宫&#xff0c;数组中只包含 0 或 1&#xff0c;其中 0 表示可以走的路&#xff0c;1 表示不可通过的墙壁。 最初&#xff0c;有一个人位于左上角 (1,1)(1,1) 处&#xff0c;已知该人每次可以向上、下、左、右任意一个方…

oracle全量、增量备份

采用0221222增量备份策略,7天一个轮回 也就是周日0级备份&#xff0c;周1 2 4 5 6 采用2级增量备份&#xff0c;周3采用1级增量备份 打开控制文件自动备份 CONFIGURE CONTROLFILE AUTOBACKUP ON; 配置控制文件备份路径 CONFIGURE CONTROLFILE AUTOBACKUP FORMAT FOR DEVI…

ChatGPT使用小结

ChatGPT是openAI旗下的一款语言模型&#xff0c;说它是语言模型更不如说他是一个全能小助手&#xff0c;自从去年它爆火之后&#xff0c;国内也出现了许多同款语言模型&#xff0c;这些智能语言模型的出现&#xff0c;对于像我这样的低端程序员的效率提升是巨大的。 很多人可能…

(二十七)Flask之数据库连接池DBUtils库

目录&#xff1a; 每篇前言&#xff1a;DBUtils库模式一&#xff08;底层使用threading.local实现&#xff09;&#xff1a;模式二&#xff1a; Flask中使用方式一&#xff1a;直接将DBUtils初始化放到settings.py文件中方式二&#xff1a;从utils文件夹中导入 脚本使用DBUtils…

vue3+element+AntDesign(自动导入)+pina+vite+js+pnpm搭建项目框架

vue3elementAntDesign(自动导入)pinavitejspnpm搭建项目框架 文章目录 vue3elementAntDesign(自动导入)pinavitejspnpm搭建项目框架1. 安装pnpm&#xff1a;通过以下命令安装pnpm&#xff0c;它是一个快速、零配置的包管理工具。2. 初始化项目&#xff1a;在命令行中执行以下命…

python时间内存计算

记录python时间内存计算操作 时间计算采用time模块内存计算分别采用memory_profiler和psutil 1.占用时间计算&#xff1a;time import timedef funT(t):for i in range(t*10):passif __name____main__:t10begintime.time()funT(t)endtime.time()print(时间&#xff1a;{}s.for…

Qt plugin 开发UI界面插件

目录 1.创建接口 2.创建插件 3.创建插件界面 4.插件实现 5.创建应用工程 6.应用插件 1.创建接口 打开QtCreater&#xff0c;点击左上角“文件”->新建文件或项目&#xff0c;在弹窗中选择C/CHeader File。 输入文件名&#xff0c;选好路径&#xff08;可自行设置名称…

jsonpath在线解析器网址

jsonpath在线解析器网址&#xff1a;https://jsonpath.com/

手动实现简易版RPC(上)

手动实现简易版RPC(上) 前言 什么是RPC&#xff1f;它的原理是什么&#xff1f;它有什么特点&#xff1f;如果让你实现一个RPC框架&#xff0c;你会如何是实现&#xff1f;带着这些问题&#xff0c;开始今天的学习。 本文主要介绍RPC概述以及一些关于RPC的知识&#xff0c;为…

02-结构化程式与自定义函数

视频教程&#xff1a;b站视频【MATLAB教程_台大郭彦甫&#xff08;14课&#xff09;原视频补档】https://www.bilibili.com/video/BV1GJ41137UH/?share_sourcecopy_web&vd_sourc*ed6b9f96888e9c85118cb40c164875dfc 官网教程&#xff1a; MATLAB 快速入门 - MathWorks 中…

【动手学深度学习】15_汉诺塔问题

注&#xff1a; 本系列仅为个人学习笔记&#xff0c;学习内容为《算法小讲堂》&#xff08;视频传送门&#xff09;&#xff0c;通俗易懂适合编程入门小白&#xff0c;需要具备python语言基础&#xff0c;本人小白&#xff0c;如内容有误感谢您的批评指正 汉诺塔&#xff08;To…

基于springboot实现高校学科竞赛平台系统项目【项目源码+论文说明】

基于springboot实现高校学科竞赛平台系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了高校学科竞赛平台的开发全过程。通过分析高校学科竞赛平台管理的不足&#xff0c;创建了一个计算机管理高校学科竞…

day02 51单片机

51单片机学习 1闪烁LED 1.1 需求描述 这个案例,我们要让P00引脚对应的LED按照1秒闪烁1次。 1.2 硬件设计 1.1 软件设计 1)LED闪烁的代码 想让LED闪烁,就需要P00的值不断在0和1之间循环变化。实现这一功能的代码也很简单: #include <STC89C5xRC.H> //包含STC89…

超详细的 Python 文件操作知识!

python进行文件操作&#xff0c;在日常编程中是很常用的。为了方便大家&#xff0c;这里对各种文件操作的知识进行汇总。一文在手&#xff0c;无须它求&#xff01;来一起学习吧。 一、文件的打开和关闭 open()函数 f1 open(rd:\测试文件.txt, moder, encodingutf-8) conte…

nandgame中的Function(函数定义)传输传递、返回值

参考&#xff1a;https://zhuanlan.zhihu.com/p/613188641 函数函数宏定义了函数块的顶部。 它应该调整堆栈以为本地存储腾出空间。 本地存储的大小由占位符localsCount给出。名为占位符functionName的标签应该开始该块。 将LOCALS设置为当前SP。 通过将localsCount添加到当前…

《剑指 Offer》专项突破版 - 面试题 105 和 106 : 最大的岛屿和二分图(C++ 实现)

目录 面试题 105 : 最大的岛屿 面试题 106 : 二分图 面试题 105 : 最大的岛屿 题目&#xff1a; 海洋岛屿地图可以用由 0、1 组成的二维数组表示&#xff0c;水平或竖直方向相连的一组 1 表示一个岛屿&#xff0c;请计算最大的岛屿的面积&#xff08;即岛屿中 1 的数目&…

uniapp实现文件和图片选择上传功能实现

主要介绍了uni-file-picker文件选择上传,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下 上传一张: <template><view class="container example"><uni-forms ref="baseForm" …

数列求和 蓝桥杯 java

题目描述 给定 n 个数 Ai&#xff0c;问能满足 m! 为∑ni1(Ai!) 的因数的最大的 m 是多少。其中 m! 表示 m 的阶乘&#xff0c;即 1 2 3 m。 输入格式 输入的第一行包含一个整数 n 。 第二行包含 n 个整数&#xff0c;分别表示 Ai&#xff0c;相邻整数之间使用一个空…

【MATLAB】基于Wi-Fi指纹匹配的室内定位-仿真获取WiFi RSSI数据(附代码)

基于Wi-Fi指纹匹配的室内定位-仿真获取WiFi RSSI数据 WiFi指纹匹配是室内定位最为基础和常见的研究&#xff0c;但是WiFi指纹的采集可以称得上是labor-intensive和time-consuming。现在&#xff0c;给大家分享一下我们课题组之前在做WiFi指纹定位时的基于射线跟踪技术仿真WiFi…

chrome 浏览器 有自带的自动字幕功能,支持英文,控制您的音乐、视频等媒体内容

chrome 浏览器 有自带的自动字幕功能&#xff0c;支持英文&#xff0c;控制您的音乐、视频等媒体内容