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,一经查实,立即删除!

相关文章

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…

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…

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

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

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

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

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

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

【机器学习算法】决策树和随机森林在计算机视觉中的应用

前言 决策树和随机森林在计算机视觉中有着广泛的应用。决策树作为一种简单而强大的分类模型&#xff0c;可以用于图像分类、目标检测、特征提取等任务。它能够根据图像的特征逐层进行判断和分类&#xff0c;从而实现对图像数据的智能分析和理解。随机森林作为一种集成学习方法&…

[dvwa] CSRF

CSRF 0x01 low 跨站&#xff0c;输入密码和确认密码直接写在url中&#xff0c;将连接分享给目标&#xff0c;点击后修改密码 社工方式让目标点击短链接 伪造404页&#xff0c;在图片中写路径为payload&#xff0c;目标载入网页自动请求构造链接&#xff0c;目标被攻击 http…

【STL】栈(stack)

笔者在做下面这道题的时候想到用栈&#xff0c;但写的很麻烦 代码&#xff1a; #include<bits/stdc.h> using namespace std; #define MAXC 255 typedef int SElemType; typedef struct StackNode {SElemType data;struct StackNode *next; }StackNode,*LinkStack; bool…

MathJax的基本使用

一、引言 MathJax引擎是一个开源的JavaScript库&#xff0c;它允许Web开发者在网页中嵌入高质量的数学公式。通过利用Web的最新技术&#xff0c;MathJax引擎可以解析LaTeX、MathML和AsciiMath等数学标记语言&#xff0c;并将其渲染为可视化的数学公式&#xff0c;这些公式可以…

NPU float(“inf“) mask_fill 出现NAN

使用NPU时&#xff0c;采用mask_fill函数&#xff0c;会出错&#xff1a; tensors.masked_fill(mask.unsqueeze(-1), float(inf)) 无法直接使用表达式,会报错 NAN&#xff1a; 取一个较大的值替换即可&#xff1b; tensors.masked_fill(mask.unsqueeze(-1), float(1e10))

LeetCode算法——双指针篇

宫侑的发球最终进化为三刀流&#xff0c;那么我的题解也未必要循规蹈矩! 1、验证回文串 题目描述&#xff1a; 解法&#xff1a; 这题官方给的关于双指针的题解都用到了多个库函数&#xff0c;如 tolower(大写字母转小写)、isalnum(判断一个字符是否是 字母 或者 十进制数字 )…

LeetCode——622设计循环队列

. - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/design-circular-queue/ 1.题目 设计你的循环队列实现。 循环队列是一…