diff options
-rw-r--r-- | App.tsx | 118 | ||||
-rw-r--r-- | __tests__/App.test.tsx | 2 | ||||
-rw-r--r-- | android/app/src/debug/AndroidManifest.xml | 42 | ||||
-rw-r--r-- | android/app/src/main/AndroidManifest.xml | 53 | ||||
-rwxr-xr-x | dev-env | 10 | ||||
-rw-r--r-- | index.js | 2 | ||||
-rw-r--r-- | package-lock.json | 21 | ||||
-rw-r--r-- | package.json | 4 | ||||
-rw-r--r-- | src/App.tsx | 107 | ||||
-rw-r--r-- | src/ble-service.ts | 186 |
10 files changed, 412 insertions, 133 deletions
diff --git a/App.tsx b/App.tsx deleted file mode 100644 index 125fe1b..0000000 --- a/App.tsx +++ /dev/null | |||
@@ -1,118 +0,0 @@ | |||
1 | /** | ||
2 | * Sample React Native App | ||
3 | * https://github.com/facebook/react-native | ||
4 | * | ||
5 | * @format | ||
6 | */ | ||
7 | |||
8 | import React from 'react'; | ||
9 | import type {PropsWithChildren} from 'react'; | ||
10 | import { | ||
11 | SafeAreaView, | ||
12 | ScrollView, | ||
13 | StatusBar, | ||
14 | StyleSheet, | ||
15 | Text, | ||
16 | useColorScheme, | ||
17 | View, | ||
18 | } from 'react-native'; | ||
19 | |||
20 | import { | ||
21 | Colors, | ||
22 | DebugInstructions, | ||
23 | Header, | ||
24 | LearnMoreLinks, | ||
25 | ReloadInstructions, | ||
26 | } from 'react-native/Libraries/NewAppScreen'; | ||
27 | |||
28 | type SectionProps = PropsWithChildren<{ | ||
29 | title: string; | ||
30 | }>; | ||
31 | |||
32 | function Section({children, title}: SectionProps): React.JSX.Element { | ||
33 | const isDarkMode = useColorScheme() === 'dark'; | ||
34 | return ( | ||
35 | <View style={styles.sectionContainer}> | ||
36 | <Text | ||
37 | style={[ | ||
38 | styles.sectionTitle, | ||
39 | { | ||
40 | color: isDarkMode ? Colors.white : Colors.black, | ||
41 | }, | ||
42 | ]}> | ||
43 | {title} | ||
44 | </Text> | ||
45 | <Text | ||
46 | style={[ | ||
47 | styles.sectionDescription, | ||
48 | { | ||
49 | color: isDarkMode ? Colors.light : Colors.dark, | ||
50 | }, | ||
51 | ]}> | ||
52 | {children} | ||
53 | </Text> | ||
54 | </View> | ||
55 | ); | ||
56 | } | ||
57 | |||
58 | function App(): React.JSX.Element { | ||
59 | const isDarkMode = useColorScheme() === 'dark'; | ||
60 | |||
61 | const backgroundStyle = { | ||
62 | backgroundColor: isDarkMode ? Colors.darker : Colors.lighter, | ||
63 | }; | ||
64 | |||
65 | return ( | ||
66 | <SafeAreaView style={backgroundStyle}> | ||
67 | <StatusBar | ||
68 | barStyle={isDarkMode ? 'light-content' : 'dark-content'} | ||
69 | backgroundColor={backgroundStyle.backgroundColor} | ||
70 | /> | ||
71 | <ScrollView | ||
72 | contentInsetAdjustmentBehavior="automatic" | ||
73 | style={backgroundStyle}> | ||
74 | <Header /> | ||
75 | <View | ||
76 | style={{ | ||
77 | backgroundColor: isDarkMode ? Colors.black : Colors.white, | ||
78 | }}> | ||
79 | <Section title="Step One"> | ||
80 | Edit <Text style={styles.highlight}>App.tsx</Text> to change this | ||
81 | screen and then come back to see your edits. | ||
82 | </Section> | ||
83 | <Section title="See Your Changes"> | ||
84 | <ReloadInstructions /> | ||
85 | </Section> | ||
86 | <Section title="Debug"> | ||
87 | <DebugInstructions /> | ||
88 | </Section> | ||
89 | <Section title="Learn More"> | ||
90 | Read the docs to discover what to do next: | ||
91 | </Section> | ||
92 | <LearnMoreLinks /> | ||
93 | </View> | ||
94 | </ScrollView> | ||
95 | </SafeAreaView> | ||
96 | ); | ||
97 | } | ||
98 | |||
99 | const styles = StyleSheet.create({ | ||
100 | sectionContainer: { | ||
101 | marginTop: 32, | ||
102 | paddingHorizontal: 24, | ||
103 | }, | ||
104 | sectionTitle: { | ||
105 | fontSize: 24, | ||
106 | fontWeight: '600', | ||
107 | }, | ||
108 | sectionDescription: { | ||
109 | marginTop: 8, | ||
110 | fontSize: 18, | ||
111 | fontWeight: '400', | ||
112 | }, | ||
113 | highlight: { | ||
114 | fontWeight: '700', | ||
115 | }, | ||
116 | }); | ||
117 | |||
118 | export default App; | ||
diff --git a/__tests__/App.test.tsx b/__tests__/App.test.tsx index 9eac6fb..d5d3244 100644 --- a/__tests__/App.test.tsx +++ b/__tests__/App.test.tsx | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | import 'react-native'; | 5 | import 'react-native'; |
6 | import React from 'react'; | 6 | import React from 'react'; |
7 | import App from '../App'; | 7 | import App from '../src/App.tsx'; |
8 | 8 | ||
9 | // Note: import explicitly to use the types shipped with jest. | 9 | // Note: import explicitly to use the types shipped with jest. |
10 | import {it} from '@jest/globals'; | 10 | import {it} from '@jest/globals'; |
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index eb98c01..b7c3a3c 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml | |||
@@ -1,6 +1,46 @@ | |||
1 | <?xml version="1.0" encoding="utf-8"?> | 1 | <?xml version="1.0" encoding="utf-8"?> |
2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | 2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
3 | xmlns:tools="http://schemas.android.com/tools"> | 3 | xmlns:tools="http://schemas.android.com/tools"> |
4 | |||
5 | <uses-permission android:name="android.permission.INTERNET" /> | ||
6 | |||
7 | <!-- | ||
8 | HACK: this permission should not be needed on android 12+ devices anymore, | ||
9 | but in fact some manufacturers still need it for BLE to properly work : | ||
10 | https://stackoverflow.com/a/72370969 | ||
11 | --> | ||
12 | <uses-permission android:name="android.permission.BLUETOOTH" tools:remove="android:maxSdkVersion" /> | ||
13 | <!-- | ||
14 | should normally only be needed on android < 12 if you want to: | ||
15 | - activate bluetooth programmatically | ||
16 | - discover local BLE devices | ||
17 | see: https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#discover-local-devices. | ||
18 | Same as above, may still be wrongly needed by some manufacturers on android 12+. | ||
19 | --> | ||
20 | <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" tools:remove="android:maxSdkVersion" /> | ||
21 | |||
22 | <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28"/> | ||
23 | <uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/> | ||
24 | |||
25 | <!-- Only when targeting Android 12 or higher --> | ||
26 | <!-- | ||
27 | Please make sure you read the following documentation | ||
28 | to have a better understanding of the new permissions. | ||
29 | https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#assert-never-for-location | ||
30 | --> | ||
31 | |||
32 | <!-- Needed if your app search for Bluetooth devices. --> | ||
33 | <!-- | ||
34 | If your app doesn't use Bluetooth scan results to derive physical location information, | ||
35 | you can strongly assert that your app doesn't derive physical location. | ||
36 | --> | ||
37 | <uses-permission android:name="android.permission.BLUETOOTH_SCAN" | ||
38 | android:usesPermissionFlags="neverForLocation" /> | ||
39 | <!-- Needed if you want to interact with a BLE device. --> | ||
40 | <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> | ||
41 | <!-- Needed if your app makes the current device discoverable to other Bluetooth devices. --> | ||
42 | <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> | ||
43 | |||
4 | 44 | ||
5 | <application | 45 | <application |
6 | android:usesCleartextTraffic="true" | 46 | android:usesCleartextTraffic="true" |
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4122f36..e1c8b57 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml | |||
@@ -1,25 +1,58 @@ | |||
1 | <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | 1 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
2 | xmlns:tools="http://schemas.android.com/tools"> | ||
2 | 3 | ||
3 | <uses-permission android:name="android.permission.INTERNET" /> | 4 | <uses-permission android:name="android.permission.INTERNET" /> |
4 | 5 | ||
5 | <application | 6 | <uses-permission android:name="android.permission.BLUETOOTH" tools:remove="android:maxSdkVersion" /> |
7 | <!-- | ||
8 | should normally only be needed on android < 12 if you want to: | ||
9 | - activate bluetooth programmatically | ||
10 | - discover local BLE devices | ||
11 | see: https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#discover-local-devices. | ||
12 | Same as above, may still be wrongly needed by some manufacturers on android 12+. | ||
13 | --> | ||
14 | <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" tools:remove="android:maxSdkVersion" /> | ||
15 | |||
16 | <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28"/> | ||
17 | <uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/> | ||
18 | |||
19 | <!-- Only when targeting Android 12 or higher --> | ||
20 | <!-- | ||
21 | Please make sure you read the following documentation | ||
22 | to have a better understanding of the new permissions. | ||
23 | https://developer.android.com/guide/topics/connectivity/bluetooth/permissions#assert-never-for-location | ||
24 | --> | ||
25 | |||
26 | <!-- Needed if your app search for Bluetooth devices. --> | ||
27 | <!-- | ||
28 | If your app doesn't use Bluetooth scan results to derive physical location information, | ||
29 | you can strongly assert that your app doesn't derive physical location. | ||
30 | --> | ||
31 | <uses-permission android:name="android.permission.BLUETOOTH_SCAN" | ||
32 | android:usesPermissionFlags="neverForLocation" /> | ||
33 | <!-- Needed if you want to interact with a BLE device. --> | ||
34 | <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> | ||
35 | <!-- Needed if your app makes the current device discoverable to other Bluetooth devices. --> | ||
36 | <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> | ||
37 | |||
38 | <application | ||
6 | android:name=".MainApplication" | 39 | android:name=".MainApplication" |
7 | android:label="@string/app_name" | 40 | android:label="@string/app_name" |
8 | android:icon="@mipmap/ic_launcher" | 41 | android:icon="@mipmap/ic_launcher" |
9 | android:roundIcon="@mipmap/ic_launcher_round" | 42 | android:roundIcon="@mipmap/ic_launcher_round" |
10 | android:allowBackup="false" | 43 | android:allowBackup="false" |
11 | android:theme="@style/AppTheme"> | 44 | android:theme="@style/AppTheme"> |
12 | <activity | 45 | <activity |
13 | android:name=".MainActivity" | 46 | android:name=".MainActivity" |
14 | android:label="@string/app_name" | 47 | android:label="@string/app_name" |
15 | android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" | 48 | android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" |
16 | android:launchMode="singleTask" | 49 | android:launchMode="singleTask" |
17 | android:windowSoftInputMode="adjustResize" | 50 | android:windowSoftInputMode="adjustResize" |
18 | android:exported="true"> | 51 | android:exported="true"> |
19 | <intent-filter> | 52 | <intent-filter> |
20 | <action android:name="android.intent.action.MAIN" /> | 53 | <action android:name="android.intent.action.MAIN" /> |
21 | <category android:name="android.intent.category.LAUNCHER" /> | 54 | <category android:name="android.intent.category.LAUNCHER" /> |
22 | </intent-filter> | 55 | </intent-filter> |
23 | </activity> | 56 | </activity> |
24 | </application> | 57 | </application> |
25 | </manifest> | 58 | </manifest> |
@@ -0,0 +1,10 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | docker run -it \ | ||
4 | --rm \ | ||
5 | -v "$(pwd)":/app -w /app \ | ||
6 | -v react-native-android-data:/root \ | ||
7 | --privileged \ | ||
8 | reactnativecommunity/react-native-android \ | ||
9 | $@ | ||
10 | |||
@@ -3,7 +3,7 @@ | |||
3 | */ | 3 | */ |
4 | 4 | ||
5 | import {AppRegistry} from 'react-native'; | 5 | import {AppRegistry} from 'react-native'; |
6 | import App from './App'; | 6 | import App from './src/App.tsx'; |
7 | import {name as appName} from './app.json'; | 7 | import {name as appName} from './app.json'; |
8 | 8 | ||
9 | AppRegistry.registerComponent(appName, () => App); | 9 | AppRegistry.registerComponent(appName, () => App); |
diff --git a/package-lock.json b/package-lock.json index 930ef30..f52af31 100644 --- a/package-lock.json +++ b/package-lock.json | |||
@@ -9,7 +9,9 @@ | |||
9 | "version": "0.0.1", | 9 | "version": "0.0.1", |
10 | "dependencies": { | 10 | "dependencies": { |
11 | "react": "18.2.0", | 11 | "react": "18.2.0", |
12 | "react-native": "0.73.0" | 12 | "react-native": "0.73.0", |
13 | "react-native-ble-manager": "^11.0.5", | ||
14 | "react-native-toast-message": "^2.1.8" | ||
13 | }, | 15 | }, |
14 | "devDependencies": { | 16 | "devDependencies": { |
15 | "@babel/core": "^7.20.0", | 17 | "@babel/core": "^7.20.0", |
@@ -11769,6 +11771,23 @@ | |||
11769 | "react": "18.2.0" | 11771 | "react": "18.2.0" |
11770 | } | 11772 | } |
11771 | }, | 11773 | }, |
11774 | "node_modules/react-native-ble-manager": { | ||
11775 | "version": "11.0.5", | ||
11776 | "resolved": "https://registry.npmjs.org/react-native-ble-manager/-/react-native-ble-manager-11.0.5.tgz", | ||
11777 | "integrity": "sha512-d8q6YEKyNkiygCy+qHa+N139UHRSWtbz7S+29mL0ZVjCSdzA6PRPsnSVDeRQJEVrWzP8ut2O6py57b6mPnBBFA==", | ||
11778 | "peerDependencies": { | ||
11779 | "react-native": ">=0.60.0" | ||
11780 | } | ||
11781 | }, | ||
11782 | "node_modules/react-native-toast-message": { | ||
11783 | "version": "2.1.8", | ||
11784 | "resolved": "https://registry.npmjs.org/react-native-toast-message/-/react-native-toast-message-2.1.8.tgz", | ||
11785 | "integrity": "sha512-vlDQVkvpSq9L3/GRfoKaxVQyenj/A7yHToC9M0nrSCTR9XPXzoc2AOgRQnM6GVvDhetDld9ZfGtFcucyWcGQNA==", | ||
11786 | "peerDependencies": { | ||
11787 | "react": "*", | ||
11788 | "react-native": "*" | ||
11789 | } | ||
11790 | }, | ||
11772 | "node_modules/react-native/node_modules/@jest/types": { | 11791 | "node_modules/react-native/node_modules/@jest/types": { |
11773 | "version": "26.6.2", | 11792 | "version": "26.6.2", |
11774 | "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", | 11793 | "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", |
diff --git a/package.json b/package.json index c51391e..7455929 100644 --- a/package.json +++ b/package.json | |||
@@ -11,7 +11,9 @@ | |||
11 | }, | 11 | }, |
12 | "dependencies": { | 12 | "dependencies": { |
13 | "react": "18.2.0", | 13 | "react": "18.2.0", |
14 | "react-native": "0.73.0" | 14 | "react-native": "0.73.0", |
15 | "react-native-ble-manager": "^11.0.5", | ||
16 | "react-native-toast-message": "^2.1.8" | ||
15 | }, | 17 | }, |
16 | "devDependencies": { | 18 | "devDependencies": { |
17 | "@babel/core": "^7.20.0", | 19 | "@babel/core": "^7.20.0", |
diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..7972da9 --- /dev/null +++ b/src/App.tsx | |||
@@ -0,0 +1,107 @@ | |||
1 | import React, {useEffect, useState} from 'react'; | ||
2 | import type {PropsWithChildren} from 'react'; | ||
3 | import { | ||
4 | Button, | ||
5 | FlatList, | ||
6 | SafeAreaView, | ||
7 | ScrollView, | ||
8 | StatusBar, | ||
9 | StyleSheet, | ||
10 | Text, | ||
11 | useColorScheme, | ||
12 | View, | ||
13 | } from 'react-native'; | ||
14 | |||
15 | import Toast from 'react-native-toast-message'; | ||
16 | import BleService, {Peripheral} from './ble-service'; | ||
17 | |||
18 | const bleService = new BleService(); | ||
19 | |||
20 | function App(): React.JSX.Element { | ||
21 | bleService: BleService; | ||
22 | |||
23 | const [isScanning, setIsScanning] = useState<boolean>(false); | ||
24 | const [peripherals, setPeripherals] = useState< | ||
25 | Map<Peripheral['id'], Peripheral> | ||
26 | >([]); | ||
27 | |||
28 | useEffect(() => { | ||
29 | bleService.setEvents({ | ||
30 | bleManagerConnectPeripheral: e => console.log(e.peripheral), | ||
31 | bleManagerStartSuccess: () => { | ||
32 | Toast.show({ | ||
33 | type: 'info', | ||
34 | text1: 'BleManager started..', | ||
35 | }); | ||
36 | }, | ||
37 | bleManagerDiscoverPeripheral: p => { | ||
38 | console.log(p.advertising.localName); | ||
39 | }, | ||
40 | bleManagerStopScan: () => { | ||
41 | setIsScanning(false); | ||
42 | setPeripherals(bleService.getPeripherals()); | ||
43 | |||
44 | console.log('scan: stop;'); | ||
45 | Toast.show({ | ||
46 | type: 'success', | ||
47 | text1: 'Scan stop..', | ||
48 | position: 'bottom', | ||
49 | }); | ||
50 | }, | ||
51 | bleManagerStartScan: () => { | ||
52 | setIsScanning(true); | ||
53 | console.log('scan: start;'); | ||
54 | Toast.show({ | ||
55 | type: 'info', | ||
56 | text1: 'Scan start..', | ||
57 | position: 'bottom', | ||
58 | }); | ||
59 | }, | ||
60 | bleManagerDidUpdateValueForCharacteristic: a => { | ||
61 | console.log(a.value); | ||
62 | }, | ||
63 | }); | ||
64 | |||
65 | return () => bleService.destroy(); | ||
66 | }); | ||
67 | |||
68 | return ( | ||
69 | <> | ||
70 | <Toast /> | ||
71 | <View> | ||
72 | <Text>Hello, World!!!!</Text> | ||
73 | {isScanning ? <Text>SKANUJE!</Text> : <Text>Juz nie</Text>} | ||
74 | <Button | ||
75 | onPress={() => { | ||
76 | bleService.scan(); | ||
77 | }} | ||
78 | title="Scan!" | ||
79 | /> | ||
80 | <FlatList | ||
81 | data={[...peripherals.values()]} | ||
82 | renderItem={({item}) => ( | ||
83 | <> | ||
84 | <Text>id: {item.id}</Text> | ||
85 | <Text>name: {item.name}</Text> | ||
86 | <Button | ||
87 | onPress={() => { | ||
88 | bleService.connect(item); | ||
89 | }} | ||
90 | title="Connect!" | ||
91 | /> | ||
92 | <Button | ||
93 | onPress={() => { | ||
94 | console.log(bleService.read(item)); | ||
95 | }} | ||
96 | title="Read!" | ||
97 | /> | ||
98 | <Text>-------</Text> | ||
99 | </> | ||
100 | )} | ||
101 | /> | ||
102 | </View> | ||
103 | </> | ||
104 | ); | ||
105 | } | ||
106 | |||
107 | export default App; | ||
diff --git a/src/ble-service.ts b/src/ble-service.ts new file mode 100644 index 0000000..f2a08a3 --- /dev/null +++ b/src/ble-service.ts | |||
@@ -0,0 +1,186 @@ | |||
1 | import BleManager, { | ||
2 | BleConnectPeripheralEvent, | ||
3 | BleDisconnectPeripheralEvent, | ||
4 | BleManagerDidUpdateValueForCharacteristicEvent, | ||
5 | BleScanCallbackType, | ||
6 | BleScanMatchMode, | ||
7 | BleScanMode, | ||
8 | Peripheral as PeripheralWithoutConnectInfo, | ||
9 | } from 'react-native-ble-manager'; | ||
10 | import { | ||
11 | EmitterSubscription, | ||
12 | NativeEventEmitter, | ||
13 | NativeModules, | ||
14 | PermissionsAndroid, | ||
15 | Platform, | ||
16 | } from 'react-native'; | ||
17 | |||
18 | import Buffer from 'buffer'; | ||
19 | |||
20 | export type Peripheral = PeripheralWithoutConnectInfo & { | ||
21 | connected?: boolean; | ||
22 | connecting?: boolean; | ||
23 | }; | ||
24 | |||
25 | type Events = { | ||
26 | bleManagerStartSuccess: () => void | undefined; | ||
27 | bleManagerStartError: () => void | undefined; | ||
28 | bleManagerStopScan: () => void | undefined; | ||
29 | bleManagerStartScan: () => void | undefined; | ||
30 | bleManagerDiscoverPeripheral: (peripheral: Peripheral) => void | undefined; | ||
31 | bleManagerDisconnectPeripheral: ( | ||
32 | event: BleDisconnectPeripheralEvent, | ||
33 | ) => void | undefined; | ||
34 | bleManagerDidUpdateValueForCharacteristic: ( | ||
35 | event: BleManagerDidUpdateValueForCharacteristicEvent, | ||
36 | ) => void | undefined; | ||
37 | bleManagerConnectPeripheral: ( | ||
38 | event: BleConnectPeripheralEvent, | ||
39 | ) => void | undefined; | ||
40 | }; | ||
41 | |||
42 | export default class BleService { | ||
43 | private _bleManagerModule = NativeModules.BleManager; | ||
44 | private _bleManagerEmitter = new NativeEventEmitter(this._bleManagerModule); | ||
45 | private _events: Events; | ||
46 | private _listeners: EmitterSubscription[]; | ||
47 | private _peripherals: Map<Peripheral['id'], Peripheral>; | ||
48 | |||
49 | constructor() { | ||
50 | this._listeners = []; | ||
51 | this._events = {}; | ||
52 | this._peripherals = new Map(); | ||
53 | BleManager.start({showAlert: false}) | ||
54 | .then(() => { | ||
55 | this.runEvent(this._events.bleManagerStartSuccess); | ||
56 | console.debug('[BleService]: BleManager started.'); | ||
57 | }) | ||
58 | .catch((err: any) => { | ||
59 | this.runEvent(this._events.bleManagerStartError); | ||
60 | console.debug('[BleService]: BeManager could not be started.', err); | ||
61 | }); | ||
62 | this.handle_permissions(); | ||
63 | } | ||
64 | |||
65 | setEvents(events: Events) { | ||
66 | this._events = events; | ||
67 | this.setupListiners(events); | ||
68 | } | ||
69 | |||
70 | handle_permissions() { | ||
71 | // po requestach, jak sie zrobi .then() nastepnie gdy (resoult) cos zwroci to oznacza, że ma perma jak nie to nie ma. | ||
72 | if (Platform.OS === 'android') { | ||
73 | if (Platform.Version >= 31) | ||
74 | PermissionsAndroid.requestMultiple([ | ||
75 | PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN, | ||
76 | PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT, | ||
77 | ]); | ||
78 | else if (Platform.Version >= 23) | ||
79 | PermissionsAndroid.request( | ||
80 | PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, | ||
81 | ); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | scan() { | ||
86 | this.runEvent(this._events.bleManagerStartScan); | ||
87 | this.clearPeripherals(); | ||
88 | BleManager.scan([], 3, false, { | ||
89 | matchMode: BleScanMatchMode.Sticky, | ||
90 | scanMode: BleScanMode.LowLatency, | ||
91 | callbackType: BleScanCallbackType.AllMatches, | ||
92 | }) | ||
93 | .then(() => { | ||
94 | console.debug('[startScan] scan promise returned successfully.'); | ||
95 | }) | ||
96 | .catch((err: any) => { | ||
97 | console.error('[startScan] ble scan returned in error', err); | ||
98 | }); | ||
99 | } | ||
100 | |||
101 | destroy() { | ||
102 | this.destroyListiners(); | ||
103 | } | ||
104 | |||
105 | getPeripherals() { | ||
106 | return this._peripherals; | ||
107 | } | ||
108 | |||
109 | connect(p: Peripheral) { | ||
110 | return BleManager.connect(p.id); | ||
111 | } | ||
112 | |||
113 | async read(peripheral: Peripheral) { | ||
114 | await BleManager.requestMTU(peripheral.id, 512); | ||
115 | BleManager.startNotification( | ||
116 | peripheral.id, | ||
117 | '6e400001-b5a3-f393-e0a9-e50e24dcca9e', | ||
118 | '6e400003-b5a3-f393-e0a9-e50e24dcca9e', | ||
119 | ) | ||
120 | .then(a => { | ||
121 | // Success code | ||
122 | console.log('--------'); | ||
123 | console.log(a); | ||
124 | console.log('--------'); | ||
125 | }) | ||
126 | .catch(error => { | ||
127 | // Failure code | ||
128 | console.log(error); | ||
129 | }); | ||
130 | } | ||
131 | |||
132 | private addPeripheral(p: Peripheral) { | ||
133 | this._peripherals.set(p.id, p); | ||
134 | } | ||
135 | |||
136 | private clearPeripherals() { | ||
137 | this._peripherals = new Map(); | ||
138 | } | ||
139 | |||
140 | private destroyListiners() { | ||
141 | for (const listener of this._listeners) { | ||
142 | if (listener) listener.remove(); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | private setupListiners(events: Events) { | ||
147 | this.destroyListiners(); | ||
148 | this._listeners = [ | ||
149 | this._bleManagerEmitter.addListener( | ||
150 | 'BleManagerDiscoverPeripheral', | ||
151 | peripheral => { | ||
152 | this.addPeripheral(peripheral); | ||
153 | this.runEvent(events.bleManagerDiscoverPeripheral, peripheral); | ||
154 | }, | ||
155 | ), | ||
156 | this._bleManagerEmitter.addListener('BleManagerStopScan', () => | ||
157 | this.runEvent(events.bleManagerStopScan), | ||
158 | ), | ||
159 | this._bleManagerEmitter.addListener( | ||
160 | 'BleManagerDisconnectPeripheral', | ||
161 | event => this.runEvent(events.bleManagerDisconnectPeripheral, event), | ||
162 | ), | ||
163 | this._bleManagerEmitter.addListener( | ||
164 | 'BleManagerDidUpdateValueForCharacteristic', | ||
165 | event => | ||
166 | this.runEvent( | ||
167 | events.bleManagerDidUpdateValueForCharacteristic, | ||
168 | event, | ||
169 | ), | ||
170 | ), | ||
171 | this._bleManagerEmitter.addListener( | ||
172 | 'BleManagerConnectPeripheral', | ||
173 | event => this.runEvent(events.bleManagerConnectPeripheral, event), | ||
174 | ), | ||
175 | ]; | ||
176 | } | ||
177 | |||
178 | private runEvent( | ||
179 | event: CallableFunction | undefined, | ||
180 | ...optionalParams: any[] | ||
181 | ): void { | ||
182 | if (event) { | ||
183 | event(...optionalParams); | ||
184 | } | ||
185 | } | ||
186 | } | ||