rf88_plugin 0.3.2 copy "rf88_plugin: ^0.3.2" to clipboard
rf88_plugin: ^0.3.2 copied to clipboard

PlatformAndroid

A Flutter plugin for the PointMobile RF88 RFID pistol-grip scanner module. Supports single-shot and trigger-based RFID tag reading via UART on Android. Works with PointMobile PM84 and other RF88-compa [...]

example/lib/main.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:rf88_plugin/rf88_plugin.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'RF88 Scanner Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
        useMaterial3: true,
      ),
      home: const ScannerPage(),
    );
  }
}

class ScannerPage extends StatefulWidget {
  const ScannerPage({super.key});

  @override
  State<ScannerPage> createState() => _ScannerPageState();
}

class _ScannerPageState extends State<ScannerPage> {
  final _rf88 = Rf88Plugin();
  StreamSubscription<String>? _tagSubscription;

  final List<String> _tags = [];
  bool _initialized = false;
  bool _connected = false;
  bool _isScanning = false;
  String _statusMessage = 'Not initialized';

  // ──────────────────────────────────────────────
  // Lifecycle
  // ──────────────────────────────────────────────

  @override
  void initState() {
    super.initState();
    _initialize();
  }

  @override
  void dispose() {
    _tagSubscription?.cancel();
    _rf88.stopSearch();
    _rf88.close();
    _rf88.deinitScanner();
    super.dispose();
  }

  // ──────────────────────────────────────────────
  // Plugin control
  // ──────────────────────────────────────────────

  Future<void> _initialize() async {
    try {
      final ok = await _rf88.initScanner();
      setState(() {
        _initialized = ok;
        _statusMessage = ok ? 'Initialized — tap Connect' : 'Init failed (PointMobile device required)';
      });

      // Subscribe to the tag stream once
      _tagSubscription = _rf88.onTagsRead.listen(_onTagRead);
    } catch (e) {
      setState(() => _statusMessage = 'Error: $e');
    }
  }

  Future<void> _connect() async {
    setState(() => _statusMessage = 'Connecting…');
    await _rf88.open();
    // Connection is async — status updates via logcat / connection listener.
    // We optimistically mark as connected; adjust if you expose a state stream.
    setState(() {
      _connected = true;
      _statusMessage = 'Connected';
    });
  }

  Future<void> _disconnect() async {
    await _rf88.stopSearch();
    await _rf88.close();
    setState(() {
      _connected = false;
      _isScanning = false;
      _statusMessage = 'Disconnected';
    });
  }

  Future<void> _startScan() async {
    if (!_connected) return;
    setState(() {
      _isScanning = true;
      _statusMessage = 'Scanning…';
    });
    await _rf88.singleSearch();
    // Result arrives via _onTagRead; plugin auto-stops after first read or 2.5s
  }

  Future<void> _stopScan() async {
    await _rf88.stopSearch();
    setState(() {
      _isScanning = false;
      _statusMessage = 'Scan stopped';
    });
  }

  void _onTagRead(String tag) {
    if (!mounted) return;
    setState(() {
      _tags.insert(0, tag);
      _isScanning = false;
      _statusMessage = 'Tag read ✓';
    });
  }

  void _clearTags() => setState(() => _tags.clear());

  // ──────────────────────────────────────────────
  // UI
  // ──────────────────────────────────────────────

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('RF88 RFID Scanner'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        actions: [
          IconButton(
            icon: const Icon(Icons.delete_outline),
            tooltip: 'Clear tags',
            onPressed: _tags.isEmpty ? null : _clearTags,
          ),
        ],
      ),
      body: Column(
        children: [
          // Status banner
          _StatusBanner(message: _statusMessage, connected: _connected),

          // Control buttons
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: Row(
              children: [
                Expanded(
                  child: FilledButton.icon(
                    onPressed: _initialized && !_connected ? _connect : null,
                    icon: const Icon(Icons.link),
                    label: const Text('Connect'),
                  ),
                ),
                const SizedBox(width: 8),
                Expanded(
                  child: FilledButton.tonal(
                    onPressed: _connected ? _disconnect : null,
                    child: const Text('Disconnect'),
                  ),
                ),
              ],
            ),
          ),

          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16),
            child: SizedBox(
              width: double.infinity,
              child: FilledButton.icon(
                onPressed: _connected
                    ? (_isScanning ? _stopScan : _startScan)
                    : null,
                icon: Icon(_isScanning ? Icons.stop : Icons.sensors),
                label: Text(_isScanning ? 'Stop Scan' : 'Scan Tag'),
                style: _isScanning
                    ? FilledButton.styleFrom(
                        backgroundColor: Theme.of(context).colorScheme.error,
                      )
                    : null,
              ),
            ),
          ),

          const SizedBox(height: 8),
          const Divider(),

          // Tag list
          Expanded(
            child: _tags.isEmpty
                ? const Center(
                    child: Text(
                      'No tags read yet.\nPress "Scan Tag" or use the pistol trigger.',
                      textAlign: TextAlign.center,
                      style: TextStyle(color: Colors.grey),
                    ),
                  )
                : ListView.separated(
                    padding: const EdgeInsets.all(8),
                    itemCount: _tags.length,
                    separatorBuilder: (_, __) => const Divider(height: 1),
                    itemBuilder: (context, index) => ListTile(
                      leading: CircleAvatar(
                        child: Text('${_tags.length - index}'),
                      ),
                      title: Text(
                        _tags[index],
                        style: const TextStyle(
                          fontFamily: 'monospace',
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      subtitle: Text('Scan #${_tags.length - index}'),
                    ),
                  ),
          ),
        ],
      ),
    );
  }
}

class _StatusBanner extends StatelessWidget {
  const _StatusBanner({required this.message, required this.connected});

  final String message;
  final bool connected;

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      color: connected
          ? Colors.green.withValues(alpha: 0.1)
          : Colors.orange.withValues(alpha: 0.1),
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
      child: Row(
        children: [
          Icon(
            connected ? Icons.check_circle : Icons.info_outline,
            size: 18,
            color: connected ? Colors.green : Colors.orange,
          ),
          const SizedBox(width: 8),
          Expanded(
            child: Text(
              message,
              style: TextStyle(
                color: connected ? Colors.green[700] : Colors.orange[800],
                fontWeight: FontWeight.w600,
              ),
            ),
          ),
        ],
      ),
    );
  }
}
0
likes
150
points
16
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for the PointMobile RF88 RFID pistol-grip scanner module. Supports single-shot and trigger-based RFID tag reading via UART on Android. Works with PointMobile PM84 and other RF88-compatible devices.

Repository (GitHub)
View/report issues

Topics

#rfid #hardware #scanner #pointmobile #nfc

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on rf88_plugin

Packages that implement rf88_plugin