flutter_android_bridge 0.3.0 copy "flutter_android_bridge: ^0.3.0" to clipboard
flutter_android_bridge: ^0.3.0 copied to clipboard

Flutter Android Bridge is a Flutter package that provides a bridge to interact with Android's native functionalities. This package allows Flutter applications to communicate with Android's package man [...]

example/lib/main.dart

import 'dart:io' show Platform;

import 'package:ffmpeg_kit_extended_flutter/ffmpeg_kit_extended_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_android_bridge/library.dart';

import 'android_mirror_view.dart';

void main() async {
  await FFmpegKitExtended.initialize();
  runApp(const MirrorApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Android Screen Mirror',
      theme: ThemeData.dark(useMaterial3: true),
      home: const MirrorPage(),
    );
  }
}

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

  @override
  State<MirrorPage> createState() => _MirrorPageState();
}

class _MirrorPageState extends State<MirrorPage> {
  final _adbPathController = TextEditingController(
    text:
        '${Platform.environment['HOME']}/Library/Android/sdk/platform-tools/adb',
  );
  final _addressController = TextEditingController(text: '192.168.1.112:5555');
  final _mirrorKey = GlobalKey<AndroidMirrorViewState>();

  FlutterAndroidClient? _client;
  bool _connecting = false;
  bool _running = false;
  bool _recordEnabled = false;
  String? _status;

  String get _recordPath =>
      '${Platform.environment['HOME']}/android_mirror_capture.h264';

  Future<void> _connect() async {
    setState(() {
      _connecting = true;
      _status = null;
    });
    try {
      final adb = FlutterAndroidBridge(_adbPathController.text.trim());
      final client = adb.newClient(_addressController.text.trim());
      final connected = await client.connect();
      if (!connected) {
        throw StateError('Could not connect to ${_addressController.text}');
      }
      setState(() {
        _client = client;
        _status = 'Connected';
      });
    } catch (e) {
      setState(() => _status = 'Connect failed: $e');
    } finally {
      if (mounted) setState(() => _connecting = false);
    }
  }

  Future<void> _start() async {
    final recordFile = _recordEnabled ? _recordPath : null;
    await _mirrorKey.currentState?.start(recordFile: recordFile);
    if (mounted) {
      setState(() {
        _running = true;
        _status = recordFile != null ? 'Recording to $recordFile' : 'Mirroring';
      });
    }
  }

  Future<void> _stop() async {
    await _mirrorKey.currentState?.stop();
    if (mounted) {
      setState(() {
        _running = false;
        _status = _recordEnabled
            ? 'Saved recording to $_recordPath'
            : 'Stopped';
      });
    }
  }

  @override
  void dispose() {
    _adbPathController.dispose();
    _addressController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final client = _client;
    return Scaffold(
      appBar: AppBar(title: const Text('Android Screen Mirror')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            TextField(
              controller: _adbPathController,
              decoration: const InputDecoration(
                labelText: 'adb path',
                border: OutlineInputBorder(),
              ),
            ),
            const SizedBox(height: 12),
            Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _addressController,
                    decoration: const InputDecoration(
                      labelText: 'device address (ip:port or serial)',
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
                const SizedBox(width: 12),
                FilledButton(
                  onPressed: _connecting ? null : _connect,
                  child: _connecting
                      ? const SizedBox(
                          width: 18,
                          height: 18,
                          child: CircularProgressIndicator(strokeWidth: 2),
                        )
                      : const Text('Connect'),
                ),
              ],
            ),
            const SizedBox(height: 12),
            Row(
              children: [
                FilledButton.icon(
                  onPressed: client != null && !_running ? _start : null,
                  icon: const Icon(Icons.play_arrow),
                  label: const Text('Start mirror'),
                ),
                const SizedBox(width: 12),
                OutlinedButton.icon(
                  onPressed: _running ? _stop : null,
                  icon: const Icon(Icons.stop),
                  label: const Text('Stop'),
                ),
                const SizedBox(width: 12),
                // Recording is chosen up front (before Start), so the file
                // captures the initial keyframe and stays decodable.
                Tooltip(
                  message: 'Record the session to $_recordPath',
                  child: FilterChip(
                    avatar: Icon(
                      _recordEnabled
                          ? Icons.fiber_manual_record
                          : Icons.radio_button_unchecked,
                      color: _recordEnabled ? Colors.red : null,
                    ),
                    label: const Text('Record'),
                    selected: _recordEnabled,
                    // Locked while running: can't toggle mid-stream.
                    onSelected: _running
                        ? null
                        : (v) => setState(() => _recordEnabled = v),
                  ),
                ),
                const SizedBox(width: 16),
                if (_status != null)
                  Expanded(
                    child: Text(
                      _status!,
                      overflow: TextOverflow.ellipsis,
                      style: const TextStyle(color: Colors.white70),
                    ),
                  ),
              ],
            ),
            const SizedBox(height: 16),
            Expanded(
              child: Container(
                color: Colors.black,
                alignment: Alignment.center,
                child: client == null
                    ? const Text('Connect to a device to begin')
                    : AndroidMirrorView(
                        key: _mirrorKey,
                        client: client,
                        debug: true,
                      ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
1
likes
130
points
272
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter Android Bridge is a Flutter package that provides a bridge to interact with Android's native functionalities. This package allows Flutter applications to communicate with Android's package manager, intents, and other native features through a simple and intuitive API

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

copy_with_extension, flutter, intl, isolate_pool_2, meta, properties

More

Packages that depend on flutter_android_bridge