native_device_kit 0.0.3
native_device_kit: ^0.0.3 copied to clipboard
High-performance Flutter plugin for deep native access to hardware, system resources, and connectivity. Features advanced camera diagnostics, BLE scanning, NFC, USB monitoring, and security checks.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:native_device_kit/native_device_kit.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _status = 'Initializing...';
final Map<String, Map<String, dynamic>> _devicesMap = {};
bool _isScanning = false;
Map<String, dynamic>? _deviceInfo;
Map<String, dynamic>? _batteryInfo;
List<Map<String, dynamic>> _cameraDetails = [];
Map<String, dynamic>? _storageInfo;
bool _isRooted = false;
bool _isEmulator = false;
bool _flashOn = false;
bool _cameraPermission = false;
String _connectivity = 'unknown';
Map<String, dynamic>? _sensorData;
bool _isSensorActive = false;
String? _connectedDeviceId;
final _kit = NativeDeviceKit.instance;
@override
void initState() {
super.initState();
_initKit();
_setupListeners();
}
Future<void> _initKit() async {
try {
final pingResp = await _kit.ping();
final info = await _kit.bridge.getDeviceInfo();
final battery = await _kit.system.getBatteryInfo();
final conn = await _kit.system.getConnectivityInfo();
final storage = await _kit.system.getStorageInfo();
final rooted = await _kit.security.isRooted();
final emulator = await _kit.security.isEmulator();
final hasPerm = await _kit.camera.hasPermission();
List<Map<String, dynamic>> cams = [];
if (hasPerm) {
cams = await _kit.camera.getLensDiagnostics();
}
setState(() {
_status = 'Kit Active: $pingResp';
_deviceInfo = info;
_batteryInfo = battery;
_connectivity = conn['type'] ?? 'none';
_storageInfo = storage;
_isRooted = rooted;
_isEmulator = emulator;
_cameraPermission = hasPerm;
_cameraDetails = cams;
});
} catch (e) {
setState(() => _status = 'Init Error: $e');
}
}
void _setupListeners() {
_kit.bluetooth.eventStream.listen((event) {
if (event['type'] == 'scanResult') {
final id = event['id'] as String;
setState(() {
_devicesMap[id] = Map<String, dynamic>.from(event);
});
} else if (event['type'] == 'connectionState') {
setState(() {
_status = 'BLE ${event['deviceId']}: ${event['state']}';
_connectedDeviceId = event['state'] == 'connected' ? event['deviceId'] : null;
});
}
});
_kit.sensors.accelerometerStream.listen((event) {
setState(() => _sensorData = event);
});
_kit.nfc.eventStream.listen((event) {
if (!mounted) return;
_showDialog('NFC Detected', 'ID: ${event['id']}');
});
_kit.usb.eventStream.listen((event) {
setState(() => _status = 'USB ${event['event']}: ${event['name']}');
});
}
Future<void> _toggleAccelerometer() async {
try {
if (_isSensorActive) {
await _kit.sensors.stopAccelerometer();
} else {
await _kit.sensors.startAccelerometer();
}
setState(() => _isSensorActive = !_isSensorActive);
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Sensor Error: $e')));
}
}
Future<void> _requestCamera() async {
final granted = await _kit.camera.requestPermission();
if (granted) {
final cams = await _kit.camera.getLensDiagnostics();
setState(() {
_cameraPermission = true;
_cameraDetails = cams;
});
}
}
Future<void> _toggleFlash() async {
try {
final target = !_flashOn;
await _kit.camera.toggleFlash(target);
setState(() => _flashOn = target);
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Flash Error: $e')));
}
}
void _showDialog(String title, String content) {
showDialog(context: context, builder: (ctx) => AlertDialog(
title: Text(title), content: Text(content),
actions: [TextButton(onPressed: () => Navigator.pop(ctx), child: const Text('OK'))],
));
}
String _formatSize(int bytes) {
if (bytes <= 0) return "0 GB";
double size = bytes / (1024.0 * 1024.0 * 1024.0);
return "${size.toStringAsFixed(1)} GB";
}
@override
Widget build(BuildContext context) {
final sortedDevices = _devicesMap.values.toList()..sort((a,b) => (b['rssi'] as int).compareTo(a['rssi'] as int));
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.deepPurple),
home: Scaffold(
appBar: AppBar(
title: const Text('Native Device Kit', style: TextStyle(fontWeight: FontWeight.bold)),
centerTitle: true,
actions: [
IconButton(icon: const Icon(Icons.refresh), onPressed: _initKit),
],
),
body: SingleChildScrollView(
child: Column(
children: [
_buildControlCard(),
_buildSecurityBanner(),
_buildHardwareGrid(),
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: () async {
if (_isScanning) {
await _kit.bluetooth.stopScan();
} else {
_devicesMap.clear();
await _kit.bluetooth.requestPermissions();
await _kit.bluetooth.scan();
}
setState(() => _isScanning = !_isScanning);
},
icon: Icon(_isScanning ? Icons.stop : Icons.bluetooth_searching),
label: Text(_isScanning ? 'Stop Scan' : 'Scan BLE'),
),
),
const SizedBox(width: 8),
Expanded(
child: OutlinedButton.icon(
onPressed: () => _kit.nfc.readTag(),
icon: const Icon(Icons.nfc),
label: const Text('Read NFC'),
),
),
],
),
),
const Divider(),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: sortedDevices.length,
itemBuilder: (context, index) {
final device = sortedDevices[index];
final isConnected = _connectedDeviceId == device['id'];
final deviceName = device['name'] ?? 'Unknown Device';
return ListTile(
leading: Icon(Icons.bluetooth, color: isConnected ? Colors.deepPurple : Colors.grey),
title: Text(deviceName),
subtitle: Text(device['id']),
trailing: Text('${device['rssi']} dBm'),
onTap: () => isConnected ? _kit.bluetooth.disconnect() : _kit.bluetooth.connect(device['id']),
);
},
),
],
),
),
),
);
}
Widget _buildControlCard() {
return Container(
width: double.infinity,
margin: const EdgeInsets.all(16),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.deepPurple.shade50,
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.deepPurple.shade100),
),
child: Column(
children: [
Text(_status, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
if (_deviceInfo != null) ...[
const SizedBox(height: 8),
Text('${_deviceInfo!['manufacturer']} ${_deviceInfo!['model']} | ${_deviceInfo!['androidVersion'] ?? 'iOS'}',
style: const TextStyle(fontSize: 12, color: Colors.deepPurple)),
],
if (_storageInfo != null) ...[
const SizedBox(height: 4),
Text('Storage: ${_formatSize(_storageInfo!['availableBytes'])} Free / ${_formatSize(_storageInfo!['totalBytes'])}',
style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w500)),
],
const SizedBox(height: 12),
Wrap(
spacing: 12,
alignment: WrapAlignment.center,
children: [
if (_batteryInfo != null)
_buildSimpleInfo(
_batteryInfo!['isCharging'] ? Icons.battery_charging_full : Icons.battery_std,
'${_batteryInfo!['level']}%'
),
_buildSimpleInfo(
_connectivity == 'wifi' ? Icons.wifi : (_connectivity == 'cellular' ? Icons.signal_cellular_4_bar : Icons.wifi_off),
_connectivity.toUpperCase()
),
],
)
],
),
);
}
Widget _buildSecurityBanner() {
if (!_isRooted && !_isEmulator) return const SizedBox.shrink();
return Container(
width: double.infinity,
margin: const EdgeInsets.symmetric(horizontal: 16),
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.red.shade50,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.red.shade100),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.warning_amber_rounded, size: 16, color: Colors.red.shade700),
const SizedBox(width: 8),
Text(
'Insecure Environment: ${_isRooted ? "ROOTED" : ""} ${_isEmulator ? "EMULATOR" : ""}',
style: TextStyle(color: Colors.red.shade700, fontWeight: FontWeight.bold, fontSize: 12),
),
],
),
);
}
Widget _buildSimpleInfo(IconData icon, String text) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 16, color: Colors.deepPurple.shade700),
const SizedBox(width: 4),
Text(text, style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 13)),
],
);
}
Widget _buildHardwareGrid() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
_buildSensorCard(),
const SizedBox(height: 8),
_buildCameraCard(),
],
),
);
}
Widget _buildCameraCard() {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.blue.shade100),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('Camera Hardware', style: TextStyle(fontWeight: FontWeight.bold)),
Row(
children: [
if (!_cameraPermission)
TextButton(onPressed: _requestCamera, child: const Text('Grant Access', style: TextStyle(fontSize: 12))),
IconButton(
onPressed: _toggleFlash,
icon: Icon(_flashOn ? Icons.flash_on : Icons.flash_off, color: _flashOn ? Colors.orange : Colors.grey),
tooltip: 'Toggle Flashlight',
),
],
),
],
),
if (_cameraPermission && _cameraDetails.isNotEmpty) ...[
const SizedBox(height: 8),
..._cameraDetails.map((cam) => Theme(
data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
child: ExpansionTile(
tilePadding: EdgeInsets.zero,
iconColor: Colors.blue,
leading: Icon(cam['position'] == 'front' ? Icons.camera_front : Icons.camera_rear, size: 18, color: Colors.blue),
title: Text('Lens ${cam['id']}: ${cam['position']?.toString().toUpperCase() ?? 'UNKNOWN'}', style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold)),
subtitle: Text('f/${cam['aperture']} | Zoom ${cam['maxZoom']}x', style: const TextStyle(fontSize: 10, color: Colors.blueGrey)),
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.only(left: 40, bottom: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildCamSpec('ISO Sensitivity', '${cam['minISO']} – ${cam['maxISO']}'),
const SizedBox(height: 4),
_buildCamSpec('Auto Focus', cam['hasAutoFocus'] ? 'Supported' : 'Manual Only'),
const SizedBox(height: 4),
_buildCamSpec('Supported Res', (cam['resolutions'] as List).take(5).join(', ') + '...'),
],
),
)
],
),
)).toList(),
] else if (!_cameraPermission) ...[
const Center(child: Padding(
padding: EdgeInsets.all(8.0),
child: Text('Permission required for hardware report', style: TextStyle(fontSize: 10, fontStyle: FontStyle.italic)),
)),
]
],
),
);
}
Widget _buildCamSpec(String label, String value) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: const TextStyle(fontSize: 9, color: Colors.blueGrey, fontWeight: FontWeight.bold)),
Text(value, style: const TextStyle(fontSize: 10, fontFamily: 'monospace')),
],
);
}
Widget _buildSensorCard() {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.grey.shade200),
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('Accelerometer', style: TextStyle(fontWeight: FontWeight.bold)),
Switch(value: _isSensorActive, onChanged: (_) => _toggleAccelerometer()),
],
),
if (_sensorData != null && _isSensorActive) ...[
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildAxis('X', _sensorData!['x']),
_buildAxis('Y', _sensorData!['y']),
_buildAxis('Z', _sensorData!['z']),
],
),
]
],
),
);
}
Widget _buildAxis(String label, dynamic value) {
return Column(
children: [
Text(label, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 12)),
Text(value.toStringAsFixed(2), style: const TextStyle(fontFamily: 'monospace')),
],
);
}
}