React Native BLE蓝牙通信 App开发

Posted 拼了命的珍惜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React Native BLE蓝牙通信 App开发相关的知识,希望对你有一定的参考价值。

由于公司项目需要,开发一个基于rn的app与公司蓝牙模块下位机进行通讯。用来扫描并连接可用的外设,然后读取和写入数据。

项目选用的蓝牙库是:react-native-ble-manager,详细安装教程和api文档查看官方文档即可。

app采用react-native+react-native-navigation+typescript+hook状态管理技术栈。

如有疑问可联系我或在下方评论区留言。

项目地址:https://github.com/HY88883/Bluetooth_central
友情提示:如果能帮到你的话,给个star哦,感激不尽~

react-native-ble-manager只适用于BLE蓝牙通信,不适用于经典蓝牙通信,接入前请确保你的设备是BLE(低功耗)蓝牙,以免前功尽弃。

app部分截图如下:
进入首页,扫描附近ble设备,默认扫描5s,可停止扫描。点击下方设备列表中的某一项进行连接。点击上方按钮中的选项可以清空。

可以查看已连接的设备,点击跳转到服务和特征详情页。

可以看到该设备的服务uuid和特征uuid,点击某一个特征,进入对应页面。

这里可以对特征进行操作,显示了当前该特征具备哪些属性,可进行读取、写入操作。

下面展示主要文件:

import React, {FunctionComponent, useContext, useEffect, useLayoutEffect, useRef, useState} from 'react';
import {
    View,
    Text,
    StyleSheet,
    Platform,
    Permissionsandroid,
    Alert,
    NativeModules,
    NativeEventEmitter, FlatList, TouchableHighlight, Linking, SafeAreaView, TouchableOpacity, ScrollView
} from "react-native";
// import HeaderButtons from "./components/HeaderButtons";
import BleManager from "react-native-ble-manager";
import {Button} from "react-native-paper";
import AntDesign from "react-native-vector-icons/AntDesign";
import {px2dp} from "../utils";
import Ionicons from "react-native-vector-icons/Ionicons";
import Toast from 'teaset/components/Toast/Toast'
import IconFont from "../assets/iconfont";
import {navigate} from "../utils/RootNavigation";
import Overlay from './components/OverlayLoading'
import { Dialog, Portal, Text as PText,List  } from 'react-native-paper';
import usePageHeaderTitle from "./components/usePageHeaderTitle";
import HeaderButtons, { Item } from 'react-navigation-header-buttons'
import {DispatchContext, GlobalDataContext} from "../context";
import {ADD_DEVICE, MINUS_DEVICE} from "../reducer";
const BleManagerModule = NativeModules.BleManager;
const bleManagerEmitter = new NativeEventEmitter(BleManagerModule);
interface OwnProps {}

type Props = OwnProps;

const Blutooth: FunctionComponent<Props> = (props) => {

    const [isScanning, setIsScanning] = useState(false);
    const peripherals = useRef(new Map()).current;
    const [list, setList] = useState([]);
    const [visible,setVisible]=useState(false)
    const {_dispatch}=useContext(DispatchContext)
    const {list:deviceList}=useContext(GlobalDataContext)
    useEffect(()=>{

        const initfn=async ()=>{
            try {
                const result = await BleManager.start({showAlert: true});
                console.log('result====', JSON.stringify(result))
                if (!result) {
                    BleManager.checkState();
                    bleManagerEmitter.addListener('BleManagerDiscoverPeripheral', handleDiscoverPeripheral);
                    bleManagerEmitter.addListener('BleManagerStopScan', handleStopScan);
                    bleManagerEmitter.addListener('BleManagerConnectPeripheral',handleConnectPeripheral);
                    bleManagerEmitter.addListener('BleManagerDisconnectPeripheral', handleDisconnectedPeripheral);
                    bleManagerEmitter.addListener('BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic);
                    bleManagerEmitter.addListener("BleManagerDidUpdateState",handleDidUpdateState )

                    return (() => {
                        console.log('unmount');
                        bleManagerEmitter.removeListener('BleManagerDiscoverPeripheral', handleDiscoverPeripheral);
                        bleManagerEmitter.removeListener('BleManagerStopScan', handleStopScan);
                        bleManagerEmitter.removeListener('BleManagerDisconnectPeripheral', handleDisconnectedPeripheral);
                        bleManagerEmitter.removeListener('BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic);
                        bleManagerEmitter.removeListener("BleManagerDidUpdateState",handleDidUpdateState )
                    })
                } else {
                    Toast.fail('蓝牙初始化失败,请检查相关设置再重试')
                }
            }catch (e) {
                console.log('e',e)
            }
        }

        initfn()

    },[])

    const handleDiscoverPeripheral = (peripheral) => {
        if (!peripheral.name) {
            peripheral.name = '未知设备';
        }
        peripherals.set(peripheral.id, peripheral);
        setList(Array.from(peripherals.values()));
    }

    const startScan = () => {
        console.log('startScan')
        if (!isScanning) {
            BleManager.scan([], 5, false).then((results) => {
                console.log('Scanning...',JSON.stringify(results));
                setIsScanning(true);
            }).catch(err => {
                Toast.fail('扫描出错了')
                console.error('err',err);
            });
        }
    }

    const stopScan=()=>{
        BleManager.stopScan().then(() => {
            // Success code
            console.log("Scan stopped");
        }).catch(err=>{
            console.log('err',err)
        })
    }

    const handleStopScan = () => {
        console.log('Scan is stopped=============xx====');
        setIsScanning(false);
    }
    const handleDisconnectedPeripheral = (data) => {
        console.log('data=========',JSON.stringify(data))
        Overlay.removeLoading()
        Toast.fail('已断开与 BLE 蓝牙设备的连接')
        let peripheral = peripherals.get(data.peripheral);
        if (peripheral) {
            peripheral.connected = false;
            peripherals.set(peripheral.id, peripheral);
            setList(Array.from(peripherals.values()));
        }
        _dispatch({
            type:MINUS_DEVICE,
            payload:{id:data.peripheral}
        })
        console.log('Disconnected from ' + data.peripheral);
    }
    const handleUpdateValueForCharacteristic = (data) => {
        console.log('Received data from ' + data.peripheral + ' characteristic ' + data.characteristic, data.value);
    }

    const onOpenBluetooth = () => {
        if (Platform.OS === 'ios') {
            Linking.openURL('App-Prefs:root=Bluetooth')
        } else {
            BleManager.enableBluetooth().catch(() =>{})
        }
    }

    const handleDidUpdateState=args=>{
        console.log('handleDidUpdateState',args)
        if(args.state==='off'){
            Alert.alert(
                '蓝牙未开启',
                '需要您开启蓝牙才能使用后续功能',
                [
                    { text: '取消' },
                    { text: '开启蓝牙', onPress: onOpenBluetooth }
                ]
            )
            // Toast.fail('需要您开启蓝牙才能使用后续功能')
        }else if(args.state==='on'){
            Toast.success('蓝牙已开启')
        }
    }

    const handleConnectPeripheral=args=>{
        Toast.success('已连接到 BLE 蓝牙设备')
        console.log('handleConnectPeripheral',args)
    }

    const testPeripheral = (peripheral) => {
        console.log(peripheral)
        if (peripheral){
            if (peripheral.connected){
                BleManager.disconnect(peripheral.id)
            }else{
                stopScan() // 连接时停止扫描
                setTimeout(()=>{
                    Overlay.displayLoading('正在连接设备...')
                    BleManager.connect(peripheral.id).then(() => {
                        let p = peripherals.get(peripheral.id);
                        console.log('p===',p)
                        if (p) {
                            p.connected = true;
                            peripherals.set(peripheral.id, p);
                            setList(Array.from(peripherals.values()));
                        }
                        Overlay.removeLoading()
                        setTimeout(()=>{
                            BleManager.retrieveServices(peripheral.id).then(peripheralData=>{
                                _dispatch({
                                    type: ADD_DEVICE,
                                    payload: peripheralData
                                })
                                Alert.alert('成功连接设备', '需要立即查看该设备详情吗', [
                                    { text: '下次' },
                                    { text: '去看看', onPress: () => navigate('Device') }
                                ])
                            })
                        },500)
                        console.log('Connected to ' + peripheral.id);
                    }).catch((error) => {
                        console.log('Connection error', error);
                    });
                },500)
            }
        }

    }

    const renderItem = (item) => {
        const color = item.connected ? 'green' : '#fff';
        return (
            <TouchableOpacity onPress={() => testPeripheral(item) } activeOpacity={0.7}>
                <View style={[styles.row, {backgroundColor: color}]}>
                   <View>
                       <Text style={styles.name}>{item.localName||item.name}</Text>
                       <View style={styles.bView}>
                           <Text style={styles.btext}>RSSI: {item.rssi}</Text>
                           <Text style={styles.btext}>{item.id}</Text>
                       </View>
                   </View>
                    <IconFont name={'arrow'} size={px2dp(20)}/>
                </View>
            </TouchableOpacity>
        );
    }

    const hideDialog=()=>{
setVisible(false)
    }

    const cleanAllDevices=async()=>{
        for(let i=0;i<deviceList.length;i++){
            try {
                await BleManager.disconnect(deviceList[i].id)
            }catch (e) {
            }
        }
        _dispatch({
            type:'connectedDevice/cleanAll'
        })
        setList([])
        peripherals.clear()
    }

  return (<SafeAreaView style={{flex:1}}>
      <Portal>
          <Dialog visible={visible} onDismiss={hideDialog} style={{marginHorizontal:px2dp(50)}}>
              <Dialog.ScrollArea >
                  <ScrollView contentContainerStyle={{paddingHorizontal: px2dp(50),height :px2dp(200)}}>
                      <List.Section>
                      {['清空'].map((item,index)=>{
                          return <List.Item
                              key={item}
                              title={item}
                              left={_ => <IconFont name={'clean'}  size={px2dp(20)} style={{top:px2dp(5),marginRight:px2dp(20)}}/>}
                              onPress={cleanAllDevices}
                          />
                      })}
                      </List.Section>
                  </ScrollView>
              </Dialog.ScrollArea>
          </Dialog>
      </Portal>
      <View style={styles.header}>
          <Button
              icon={()=><AntDesign
                  name={'search1'}
                  size={18}
                  color={"#fff"}
              />}
              mode="contained"
              onPress={startScan}
              loading={isScanning}
              style={{back

以上是关于React Native BLE蓝牙通信 App开发的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 react-native-ble-manager 通过蓝牙连接到设备

React Native 中的蓝牙打印

react-native 中蓝牙连接、下发数据、监听数据

低功耗蓝牙是不是支持网络?

android怎么来判断蓝牙开、关的状态?求代码

React Native:BLE,发现和广播(广告数据)