はじめに
React Nativeアプリケーションで、BLEペリフェラルデバイスのスキャンを行います。Androidでのみ動作確認していますが、Androidのみで動作可能なAPIは利用していないので、iOSでも動作可能かと思います。OSSはBLE Managerを利用します。
初期セットアップ
まず通常通りアプリケーションの雛形を作り、それからyarn addでBLE Managerをインストールします。
$ react-native init BLESample
$ cd BLESample
$ yarn add react-native-ble-manager
Androidのマニフェスト(android/app/src/main/AndroidManifest.xml)に以下の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" />
src/screens/MainScreen.jsを作成して、App.jsからはMainScreenを呼び出すようにしておきます。
// Appjs
import React from 'react';
import MainScreen from './src/screens/MainScreen'
const App: () => React$Node = () => {
return (
<MainScreen/>
);
};
export default App;
スマートフォンのBluetooth ON/OFFを取得する
BLE Managerは利用する前にまずstartを呼び出す必要があります。Componentの初期化時のcomponentDidMountで呼び出します。BLE Managerの初期化の後にBluetoothの状態(スマートフォンのBluetooth ON/OFF設定)を確認します。
Bluetoothの状態はBleManager.checkState()で取得できますが、その前にListenerの登録が必要です。Bluetoothの状態を以下のように単純にTextで表示します。スマートフォンのBluetoothの設定に応じてon/offが切り替わります。
class MainScreen extends React.Component {
state = {
bt_status: 'on',
}
componentDidMount() {
BleManager.start({showAlert: false})
.then(() => {
console.log('BleManager initialized')
bleManagerEmitter.addListener(
'BleManagerDidUpdateState',
(args) => {
this.setState({bt_status: args.state})
}
);
BleManager.checkState()
})
.catch((error) => {
console.log(error)
});
}
render() {
return (
<View style={styles.container}>
<Text style={styles.status_text}>Bluetooth: {this.state.bt_status}</Text>
</View>
);
}
}
ペリフェラルをスキャンする
ペリフェラルのスキャンはscan() APIを利用します。結果は、BleManagerDiscoverPeripheralリスナーで返却されます。事前にリスナーを登録します。
bleManagerEmitter.addListener(
'BleManagerDiscoverPeripheral',
(args) => {
}
);
ペリフェラルのスキャン結果は、以下のデータで返されます。
id - String - the id of the peripheral
name - String - the name of the peripheral
rssi - Number - the RSSI value
advertising - JSON - the advertising payload, here are some examples:
isConnectable - Boolean
serviceUUIDs - Array of String
manufacturerData - JSON - contains the raw bytes and data (Base64
encoded string)
serviceData - JSON - contains the raw bytes and data (Base64 encoded string)
txPowerLevel - Int
スキャンした結果をリストで表現するコードを以下のように実装します。ComponentのstateにperipheralListを設定します。BleManagerDiscoverPeripheralのリスナーでペリフェラルの情報が通知された時点で、リストに追加します。stateに設定しているので、ペリフェラルが見つかる毎にUIがリフレッシュされます。
class MainScreen extends React.Component {
state = {
bt_status: 'on',
peripheralList: [],
};
componentDidMount() {
BleManager.start({showAlert: false})
.then(() => {
console.log('BleManager initialized');
bleManagerEmitter.addListener(
'BleManagerDidUpdateState',
(args) => {
this.setState({bt_status: args.state});
}
);
bleManagerEmitter.addListener(
'BleManagerDiscoverPeripheral',
(args) => {
peripheral = { 'id': args.id, 'name': args.name };
this.state.peripheralList.push(peripheral);
this.setState(this.state.peripheralList);
}
);
BleManager.checkState();
})
.catch((error) => {
console.log(error);
});
}
scan() {
BleManager.scan([], 5, false)
.then(() => {
console.log('Scan started');
this.setState({peripheralList: []});
})
.catch((error) => {
console.log(error);
});
}
renderPeripheral({ item }) {
return (
<View style={styles.peripheralList}>
<Text style={styles.id_text}>{item.id}</Text>
<Text style={styles.id_text}>{item.name}</Text>
</View>
);
}
render() {
return (
<View style={styles.container}>
<Text style={styles.status_text}>Bluetooth: {this.state.bt_status}</Text>
<Button title="Scan" onPress={this.scan.bind(this)} />
<FlatList data={this.state.peripheralList} renderItem={this.renderPeripheral.bind(this)} />
</View>
);
}
}