📱Mobile/React Native

[React Native] iOS BLE Advertising

뉴발자 2023. 11. 21.
728x90

 

 

 

 

 

 

 

 

 

 

 

 

 

 

그림 1-1. BLE Advertising

 

 

BLE의 정의 및 참고 사이트

https://tlseoqja.tistory.com/38

 

[React Native] Android BLE Advertising

BLE 란? Bluetooth Low Energy의 줄임말로, 저전력 블루투스 라고 한다. Bluetooth는 크게 Bluetooth Classic과 BLE로 구분된다. Bluetooth 3.0 까지는 Bluetooth Classic, Bluetooth 4.0 부터는 BLE로 불린다. Bluetooth Classic은 다

tlseoqja.tistory.com

 

 

코드

Swift가 아닌 Object-C를 사용해서 코드를 작성하였다.

 

 

1. BLE 권한 추가

ios 폴더의 프로젝트 폴더의 Info.plist 파일을 열어서 블루투스 사용 권한을 넣어준다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  ...
  <key>NSBluetoothAlwaysUsageDescription</key>
  <string>use BLE Advertising</string>
  <key>NSBluetoothPeripheralUsageDescription</key>
  <string>use BLE Advertising</string>
  ...
</dict>
</plist>

 

 

2. 모듈 파일 생성

x-Code에서 프로젝트의 ios 폴더를 열고, Header 파일과 Metal 파일을 생성해준다.

 

※ x-Code가 아닌 VS에서 파일을 생성할 경우 파일이 정상적으로 실행되지 않는다.

그림 2-1. 새로운 파일 생성 - x-code

 

그림2-2. Header File 선택

 

그림 2-3. Header 파일명 입력 및 프로젝트 선택

 

그림 2-4. Metal File 선택

 

그림 2-5. Metal 파일명 및 프로젝트 선택

 

위의 과정을 거치면 확장자 .h 파일과 확장자 .m 파일이 생성된다.

728x90

 

 

3. Header File ( RCTBLEModule.h )

#import <React/RCTBridgeModule.h>

@interface RCTBLEModule : NSObject <RCTBridgeModule>

@end

 

 

3-2. Metal File ( RCTBLEModule.m )

uuid를 packet에 따라 변동해서 사용하기 위해 React Native 코드에서 data를 전달받은 후 startAdvertising 하는 코드이다.

 

※ CoreBluetooth 모듈에서 LocalNameKey와 ServiceUUIDsKey를 제외한 데이터의 변경은 허용하지 않는다.

#import <React/RCTBridgeModule.h>
#import <CoreBluetooth/CoreBluetooth.h>

@interface RCTBLEModule : NSObject <RCTBridgeModule, CBPeripheralManagerDelegate>

@property (nonatomic, strong) CBPeripheralManager *peripheralManager;
@property (nonatomic, strong) NSDictionary *advertisementData;

@end

@implementation RCTBLEModule

RCT_EXPORT_MODULE(IOSBLEModule);

RCT_EXPORT_METHOD(IOSstartAdvertising:(NSString *) data) {
  self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];

  self.advertisementData = @{
    // CBAdvertisementDataLocalNameKey: data,
    CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:data]]
  };

  [self.peripheralManager startAdvertising: self.advertisementData];

  NSLog(@"BLE Advertising Success");
}

RCT_EXPORT_METHOD(IOSstopAdvertising) {
    [self.peripheralManager stopAdvertising];
}

@end

 

 

3-3. React Native에서 iOS 코드 사용하기

src/module/nativeModule.ts

import { NativeModules } from "react-native";

...

export interface IIOSBLEModule {
  IOSstartAdvertising: (data: string) => void;
  IOSstopAdvertising: () => void;
}

export default {
  ...
  ...NativeModules.IOSBLEModule as IIOSBLEModule,
};

 

 

src/hooks/useBluetooth.ts

import { useState, useEffect, useCallback } from "react";
import nativeModules from "../module/nativeModules";
import BackgroundTimer from "react-native-background-timer";

const {
  startAdvertising,
  stopAdvertising,
  IOSstartAdvertising,
  IOSstopAdvertising,
} = nativeModules;

const useBluetooth = () => {
  const [isTransmitter, setIsTransmitter] = useState(false);
  const transmitterMs = 5000;

  // 광고 데이터 송신 시작 함수
  const onStartAdvertising = useCallback((hexString: string, uuid: string) => {
    setIsTransmitter(true);

    try {
      if( Platform.OS === "android" ) {
        startAdvertising(hexString);
      } else {
        // iOS Advertising 시작
        IOSstartAdvertising(uuid);
      }
    } catch (error) {
      console.log(error);
    }
    
  }, []);

  // 지정한 시간 후에 BLE 광고를 종료한다.
  useEffect(() => {
    if (isTransmitter) {
      const timer = BackgroundTimer.setTimeout(() => {
        setIsTransmitter(false);

        // 광고 데이터 송신 종료 함수
        if ( Platform.OS === "android" ) {
          stopAdvertising();
        } else {
          // iOS Advertising 종료
          IOSstopAdvertising();
        }
      }, transmitterMs);

      return () => BackgroundTimer.clearTimeout(timer);
    }
  }, [isTransmitter, transmitterMs]);

  return {
    onStartAdvertising,
  };
};

export default useBluetooth;

 

 

App.tsx

import { TouchableOpacity, View, Text } from "react-native";
import useBluetooth from "./src/hooks/useBluetooth";

const ViewStyle = {
  flex: 1,
  justifyContent: "center",
  alignItems: "center",
};

const ButtonStyle = {
  backgroundColor: "red",
  padding: 10,
  border: "1px solid black",
  borderRadius: 5
};

const TextStyle = {
  color: "white",
};

const App = () => {
  const { onStartAdvertising } = useBluetooth();
  
  const bleAdvertising = () => {
    const manufacturerData = "1111111111";
    const uuid = "11111111-1111-1111-1111-111111111111";

    onStartAdvertising(manufacturerData, uuid);
  };

  return (
    <View
      style={ViewStyle}
    >
      <TouchableOpacity
        onPress={bleAdvertising}
        style={ButtonStyle}
      >
        <Text style={TextStyle}>BLE 광고</Text>
      </TouchableOpacity>
    </View>
  );
};

export default App;

 

 

 

 

 

 

 

 

 

 

728x90

댓글