Untitled
unknown
typescript
a month ago
4.8 kB
5
Indexable
import { useEffect, useRef, useState, useCallback } from 'react'; import { BleManager, Device, State } from 'react-native-ble-plx'; import { PermissionsAndroid, Platform } from 'react-native'; import base64 from 'react-native-base64'; export const SAFE_DEVICE_NAME_PATTERNS: string[] = [ "airpods", "apple watch", "beats", "bose", "sony wh", "wf-1000xm", "galaxy buds", "galaxy watch", "pixel buds", "jabra", "jbl", "soundcore", "anker", "sennheiser", "skullcandy", "plantronics", "jaybird", "logitech headset", "astro a", "fitbit", "mi band", "mi watch", "huawei band", "garmin", "fossil", "ticwatch", "withings", "polar", "pebble", "casio watch", "dexcom", "freestyle libre", "omron", "accu-chek", "oticon", "phonak", "resound", "signia", "nintendo switch", "switch pro controller", "joy-con", "playstation", "dualshock", "dual sense", "xbox wireless controller", "tile", "chipolo", "cube tracker", "philips hue", "lifx", "wyze bulb", "smart plug", "echo", "amazon fire", "esp32", "hc-05", "my car", "handsfree", "headphones", "earphone", "earbuds", "wireless buds", "bud left", "bud right", "smartband", "smart watch" ]; export const SAFE_SERVICE_UUIDS: string[] = [ "1800", "1801", "1802", "1803", "1804", "1805", "1806", "1807", "1808", "1809", "180A", "180D", "180E", "180F", "1810", "1811", "1812", "1813", "1814", "1815", "1816", "1818", "1819", "181A", "181B", "181C", "181D", "181E", "181F", "1820", "1821", "1822", "1823", "1824", "1825", "1826", "1827", "1828", "1829", "183A" ]; export default function useCameraScanner() { const bleManagerRef = useRef(new BleManager()); const [scanning, setScanning] = useState(false); const [logs, setLogs] = useState<string[]>([]); const [potentialCameras, setPotentialCameras] = useState<Device[]>([]); useEffect(() => { return () => { bleManagerRef.current.destroy(); }; }, []); const normalizeUUID = useCallback((uuid: string) => { const upper = uuid.toUpperCase(); const match = upper.match(/^0000([0-9A-F]{4})-0000-1000-8000-00805F9B34FB$/); if (match) return match[1]; return upper; }, []); const isWellKnownSafeDevice = useCallback((device: Device) => { const lowerName = (device.name || device.localName || '').toLowerCase(); for (const pattern of SAFE_DEVICE_NAME_PATTERNS) { if (lowerName.includes(pattern)) { return true; } } if (device.serviceUUIDs) { for (const srv of device.serviceUUIDs) { if (SAFE_SERVICE_UUIDS.includes(normalizeUUID(srv))) { return true; } } } return false; }, [normalizeUUID]); const requestPermissions = useCallback(async () => { if (Platform.OS === 'android') { const scanPerm = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN ); const connectPerm = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT ); const locPerm = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION ); if ( scanPerm !== PermissionsAndroid.RESULTS.GRANTED || connectPerm !== PermissionsAndroid.RESULTS.GRANTED || locPerm !== PermissionsAndroid.RESULTS.GRANTED ) { setLogs((prev) => [...prev, "Permissions not granted."]); return false; } } return true; }, []); const startScan = useCallback(async () => { const hasPermissions = await requestPermissions(); if (!hasPermissions) return; const bleManager = bleManagerRef.current; const currentState = await bleManager.state(); if (currentState !== State.PoweredOn) { setLogs((prev) => [...prev, "Bluetooth not powered on."]); return; } setLogs([]); setPotentialCameras([]); setScanning(true); bleManager.startDeviceScan(null, null, (error, device) => { if (error) { setLogs((prev) => [...prev, `Scan error: ${error.message}`]); setScanning(false); bleManager.stopDeviceScan(); return; } if (!device) return; if (isWellKnownSafeDevice(device)) return; setPotentialCameras((prev) => { if (!prev.some((d) => d.id === device.id)) { return [...prev, device]; } return prev; }); }); }, [requestPermissions, isWellKnownSafeDevice]); const stopScan = useCallback(() => { bleManagerRef.current.stopDeviceScan(); setScanning(false); setLogs((prev) => [...prev, "Scan stopped."]); }, []); return { scanning, logs, potentialCameras, startScan, stopScan }; }
Editor is loading...
Leave a Comment