expo-ble模块测试demo
This commit is contained in:
372
ble/example/BleExampleV2.tsx
Normal file
372
ble/example/BleExampleV2.tsx
Normal file
@@ -0,0 +1,372 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { View, Text, Button, Alert, ScrollView, StyleSheet } from 'react-native';
|
||||
import {
|
||||
BleManager,
|
||||
DeviceInfoManagerV2,
|
||||
FileTransferManager,
|
||||
CommandUtils,
|
||||
PROTOCOL_UUIDS,
|
||||
APP_COMMAND_TYPES,
|
||||
DEVICE_RESPONSE_TYPES,
|
||||
BleEventCallback,
|
||||
DeviceInfoListener,
|
||||
FileTransferListener,
|
||||
DeviceInfo,
|
||||
ActivationStatus,
|
||||
VersionInfo,
|
||||
BleDevice,
|
||||
} from '../index';
|
||||
|
||||
/**
|
||||
* Example component demonstrating BLE V2.1.1 protocol usage
|
||||
* This component shows how to use the new JSON-based BLE protocol
|
||||
*/
|
||||
const BleExampleV2: React.FC = () => {
|
||||
const [isScanning, setIsScanning] = useState(false);
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [connectedDevice, setConnectedDevice] = useState<BleDevice | null>(null);
|
||||
const [deviceInfo, setDeviceInfo] = useState<DeviceInfo | null>(null);
|
||||
const [version, setVersion] = useState<string>('');
|
||||
const [isActivated, setIsActivated] = useState<boolean>(false);
|
||||
const [transferProgress, setTransferProgress] = useState<number>(0);
|
||||
const [isTransferring, setIsTransferring] = useState<boolean>(false);
|
||||
const [logs, setLogs] = useState<string[]>([]);
|
||||
|
||||
// Managers
|
||||
const bleManager = BleManager.getInstance();
|
||||
const deviceInfoManager = DeviceInfoManagerV2.getInstance();
|
||||
const fileTransferManager = FileTransferManager.getInstance();
|
||||
|
||||
// Add log message
|
||||
const addLog = (message: string) => {
|
||||
const timestamp = new Date().toLocaleTimeString();
|
||||
setLogs(prev => [...prev, `[${timestamp}] ${message}`]);
|
||||
};
|
||||
|
||||
// Setup event listeners
|
||||
useEffect(() => {
|
||||
const bleCallback: BleEventCallback = {
|
||||
onDiscoveryStateChange: (scanning: boolean) => {
|
||||
setIsScanning(scanning);
|
||||
addLog(`Scanning: ${scanning ? 'Started' : 'Stopped'}`);
|
||||
},
|
||||
onDeviceDiscovered: (device) => {
|
||||
addLog(`Device discovered: ${device.name || 'Unknown'} (${device.id})`);
|
||||
},
|
||||
onConnectionStateChange: (deviceId, status) => {
|
||||
setIsConnected(status === 'Connected');
|
||||
addLog(`Connection ${status}: ${deviceId}`);
|
||||
if (status === 'Disconnected') {
|
||||
setConnectedDevice(null);
|
||||
}
|
||||
},
|
||||
onDataReceived: (deviceId, serviceUuid, characteristicUuid, data) => {
|
||||
console.log('onDataReceived', deviceId, serviceUuid, characteristicUuid, data);
|
||||
addLog(`Data received from ${deviceId} (${data.byteLength} bytes)`);
|
||||
},
|
||||
};
|
||||
|
||||
const deviceInfoCallback: DeviceInfoListener = {
|
||||
onDeviceInfoReceived: (info) => {
|
||||
setDeviceInfo(info);
|
||||
addLog(`Device info received: ${info.devname}`);
|
||||
},
|
||||
onVersionReceived: (version) => {
|
||||
setVersion(version);
|
||||
addLog(`Version: ${version}`);
|
||||
},
|
||||
onActivationStatusReceived: (activated) => {
|
||||
setIsActivated(activated);
|
||||
addLog(`Activation status: ${activated ? 'Activated' : 'Not activated'}`);
|
||||
},
|
||||
onIdentityCheckReceived: (isValid) => {
|
||||
addLog(`Identity check: ${isValid ? 'Valid' : 'Invalid'}`);
|
||||
},
|
||||
};
|
||||
|
||||
const fileTransferCallback: FileTransferListener = {
|
||||
onStart: () => {
|
||||
setIsTransferring(true);
|
||||
setTransferProgress(0);
|
||||
addLog('File transfer started');
|
||||
},
|
||||
onProgress: (progress) => {
|
||||
setTransferProgress(progress);
|
||||
addLog(`Transfer progress: ${progress}%`);
|
||||
},
|
||||
onComplete: () => {
|
||||
setIsTransferring(false);
|
||||
setTransferProgress(0);
|
||||
addLog('File transfer completed');
|
||||
},
|
||||
onFail: (code, message) => {
|
||||
setIsTransferring(false);
|
||||
setTransferProgress(0);
|
||||
addLog(`Transfer failed: ${message} (${code})`);
|
||||
},
|
||||
};
|
||||
|
||||
bleManager.registerCallback(bleCallback);
|
||||
deviceInfoManager.addListener(deviceInfoCallback);
|
||||
fileTransferManager.addListener(fileTransferCallback);
|
||||
|
||||
return () => {
|
||||
bleManager.unregisterCallback(bleCallback);
|
||||
deviceInfoManager.removeListener(deviceInfoCallback);
|
||||
fileTransferManager.removeListener(fileTransferCallback);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Start scanning for devices
|
||||
const startScan = async () => {
|
||||
try {
|
||||
addLog('Starting BLE scan...');
|
||||
await bleManager.startScan();
|
||||
} catch (error) {
|
||||
addLog(`Scan failed: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Stop scanning
|
||||
const stopScan = async () => {
|
||||
try {
|
||||
addLog('Stopping BLE scan...');
|
||||
await bleManager.stopScan();
|
||||
} catch (error) {
|
||||
addLog(`Stop scan failed: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Connect to device (for demo, connect to first discovered device)
|
||||
const connectToDevice = async () => {
|
||||
try {
|
||||
addLog('Connecting to device...');
|
||||
// In real app, you would select a specific device
|
||||
// For demo, we'll show the connection flow
|
||||
Alert.alert('Connect', 'Please select a device from the scan results first');
|
||||
} catch (error) {
|
||||
addLog(`Connection failed: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Disconnect from device
|
||||
const disconnectDevice = async () => {
|
||||
try {
|
||||
addLog('Disconnecting from device...');
|
||||
await bleManager.disconnectDevice();
|
||||
} catch (error) {
|
||||
addLog(`Disconnect failed: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Query activation status
|
||||
const queryActivationStatus = async () => {
|
||||
try {
|
||||
addLog('Querying activation status...');
|
||||
await deviceInfoManager.queryActivationStatus();
|
||||
} catch (error) {
|
||||
addLog(`Activation query failed: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Query version
|
||||
const queryVersion = async () => {
|
||||
try {
|
||||
addLog('Querying device version...');
|
||||
await deviceInfoManager.queryVersion();
|
||||
} catch (error) {
|
||||
addLog(`Version query failed: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Request device info
|
||||
const requestDeviceInfo = async () => {
|
||||
try {
|
||||
addLog('Requesting device info...');
|
||||
await deviceInfoManager.requestDeviceInfoReport();
|
||||
} catch (error) {
|
||||
addLog(`Device info request failed: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Update activation time to current time
|
||||
const updateActivationTime = async () => {
|
||||
try {
|
||||
addLog('Updating activation time...');
|
||||
await CommandUtils.sendCurrentTimeUpdate();
|
||||
} catch (error) {
|
||||
addLog(`Time update failed: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Send identity check response
|
||||
const sendIdentityCheck = (isValid: boolean) => {
|
||||
try {
|
||||
addLog(`Sending identity check response: ${isValid}`);
|
||||
deviceInfoManager.sendIdentityCheckResponse(isValid);
|
||||
} catch (error) {
|
||||
addLog(`Identity check failed: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Transfer sample file (demo)
|
||||
const transferSampleFile = async () => {
|
||||
try {
|
||||
addLog('Starting sample file transfer...');
|
||||
// In real app, you would provide actual file path
|
||||
Alert.alert('File Transfer', 'Please provide a valid file path for transfer');
|
||||
} catch (error) {
|
||||
addLog(`File transfer failed: ${error}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Clear logs
|
||||
const clearLogs = () => {
|
||||
setLogs([]);
|
||||
};
|
||||
|
||||
return (
|
||||
<ScrollView style={styles.container}>
|
||||
<Text style={styles.title}>BLE V2.1.1 Protocol Example</Text>
|
||||
|
||||
{/* Connection Status */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Connection Status</Text>
|
||||
<Text>Scanning: {isScanning ? 'Yes' : 'No'}</Text>
|
||||
<Text>Connected: {isConnected ? 'Yes' : 'No'}</Text>
|
||||
<Text>Device: {connectedDevice?.name || 'None'}</Text>
|
||||
</View>
|
||||
|
||||
{/* Device Info */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Device Information</Text>
|
||||
<Text>Activated: {isActivated ? 'Yes' : 'No'}</Text>
|
||||
<Text>Version: {version || 'Unknown'}</Text>
|
||||
{deviceInfo && (
|
||||
<>
|
||||
<Text>Name: {deviceInfo.devname}</Text>
|
||||
<Text>Total Space: {deviceInfo.allspace} KB</Text>
|
||||
<Text>Free Space: {deviceInfo.freespace} KB</Text>
|
||||
<Text>Brand: {deviceInfo.brand}</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Transfer Status */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>File Transfer</Text>
|
||||
<Text>Transferring: {isTransferring ? 'Yes' : 'No'}</Text>
|
||||
<Text>Progress: {transferProgress}%</Text>
|
||||
</View>
|
||||
|
||||
{/* Control Buttons */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Controls</Text>
|
||||
|
||||
<View style={styles.buttonRow}>
|
||||
<Button
|
||||
title={isScanning ? "Stop Scan" : "Start Scan"}
|
||||
onPress={isScanning ? stopScan : startScan}
|
||||
/>
|
||||
<Button
|
||||
title={isConnected ? "Disconnect" : "Connect"}
|
||||
onPress={isConnected ? disconnectDevice : connectToDevice}
|
||||
disabled={!isConnected && !isScanning}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.buttonRow}>
|
||||
<Button title="Query Activation" onPress={queryActivationStatus} disabled={!isConnected} />
|
||||
<Button title="Query Version" onPress={queryVersion} disabled={!isConnected} />
|
||||
</View>
|
||||
|
||||
<View style={styles.buttonRow}>
|
||||
<Button title="Device Info" onPress={requestDeviceInfo} disabled={!isConnected} />
|
||||
<Button title="Update Time" onPress={updateActivationTime} disabled={!isConnected} />
|
||||
</View>
|
||||
|
||||
<View style={styles.buttonRow}>
|
||||
<Button title="Identity Check (Valid)" onPress={() => sendIdentityCheck(true)} disabled={!isConnected} />
|
||||
<Button title="Identity Check (Invalid)" onPress={() => sendIdentityCheck(false)} disabled={!isConnected} />
|
||||
</View>
|
||||
|
||||
<View style={styles.buttonRow}>
|
||||
<Button title="Transfer File" onPress={transferSampleFile} disabled={!isConnected} />
|
||||
<Button title="Clear Logs" onPress={clearLogs} />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Protocol Info */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Protocol Information</Text>
|
||||
<Text>Version: 2.1.1</Text>
|
||||
<Text>Service UUID: {PROTOCOL_UUIDS.SERVICE}</Text>
|
||||
<Text>Write UUID: {PROTOCOL_UUIDS.WRITE_CHARACTERISTIC}</Text>
|
||||
<Text>Read UUID: {PROTOCOL_UUIDS.READ_CHARACTERISTIC}</Text>
|
||||
</View>
|
||||
|
||||
{/* Logs */}
|
||||
<View style={styles.section}>
|
||||
<View style={styles.logHeader}>
|
||||
<Text style={styles.sectionTitle}>Logs</Text>
|
||||
<Button title="Clear" onPress={clearLogs} />
|
||||
</View>
|
||||
<ScrollView style={styles.logContainer} nestedScrollEnabled={true}>
|
||||
{logs.map((log, index) => (
|
||||
<Text key={index} style={styles.logText}>{log}</Text>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: 16,
|
||||
backgroundColor: '#f5f5f5',
|
||||
},
|
||||
title: {
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'center',
|
||||
marginBottom: 20,
|
||||
},
|
||||
section: {
|
||||
backgroundColor: 'white',
|
||||
padding: 16,
|
||||
marginBottom: 16,
|
||||
borderRadius: 8,
|
||||
elevation: 2,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 8,
|
||||
},
|
||||
buttonRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 8,
|
||||
},
|
||||
logHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 8,
|
||||
},
|
||||
logContainer: {
|
||||
height: 200,
|
||||
backgroundColor: '#f8f8f8',
|
||||
padding: 8,
|
||||
borderRadius: 4,
|
||||
},
|
||||
logText: {
|
||||
fontSize: 12,
|
||||
fontFamily: 'monospace',
|
||||
marginBottom: 2,
|
||||
},
|
||||
});
|
||||
|
||||
export default BleExampleV2;
|
||||
Reference in New Issue
Block a user