vex_channel 1.0.0 copy "vex_channel: ^1.0.0" to clipboard
vex_channel: ^1.0.0 copied to clipboard

VexChannel — Zero-boilerplate platform channels for Flutter. Write pure Dart, access every native API on Android, iOS, macOS, Windows, Linux and Web without touching Kotlin/Swift/C++ once.

example/lib/main.dart

// example/lib/main.dart
// VexChannel Example — demonstrates every major feature

import 'package:flutter/material.dart';
import 'package:vex_channel/vex_channel.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  VexChannel.enableLogging(verbose: true);
  runApp(const VexExampleApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'VexChannel Demo',
      theme: ThemeData(
        colorSchemeSeed: Colors.deepPurple,
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  String _output = 'Tap a button to test VexChannel';

  void _show(String msg) => setState(() => _output = msg);

  // ── Battery ────────────────────────────────────────────────────────────────

  Future<void> _getBattery() async {
    final battery = VexChannel.bridge(VexBattery.instance);
    final info = await battery.info;
    _show('🔋 Battery: ${info.level.toStringAsFixed(1)}%\n'
        'State: ${info.state.name}\n'
        'Low power: ${info.isLowPowerMode}');
  }

  // ── Device Info ────────────────────────────────────────────────────────────

  Future<void> _getDeviceInfo() async {
    final d = VexChannel.bridge(VexDeviceInfoModule.instance);
    final info = await d.get();
    _show('📱 Device: ${info.brand} ${info.model}\n'
        'OS: ${info.systemName} ${info.systemVersion}\n'
        'Physical: ${info.isPhysicalDevice}\n'
        'SDK: ${info.sdkVersion}');
  }

  // ── Connectivity ───────────────────────────────────────────────────────────

  Future<void> _getConnectivity() async {
    final conn = VexChannel.bridge(VexConnectivity.instance);
    final type = await conn.currentType;
    final ssid = await conn.wifiSSID;
    _show('📡 Network: ${type.name}\nSSID: ${ssid ?? "N/A"}');
  }

  // ── Haptics ────────────────────────────────────────────────────────────────

  Future<void> _haptics() async {
    final h = VexChannel.bridge(VexHaptics.instance);
    await h.success;
    _show('📳 Success haptic fired!');
  }

  // ── Clipboard ──────────────────────────────────────────────────────────────

  Future<void> _clipboard() async {
    final cb = VexChannel.bridge(VexClipboard.instance);
    await cb.setText('Hello from VexChannel! 🚀');
    final text = await cb.getText();
    _show('📋 Clipboard: $text');
  }

  // ── Storage ────────────────────────────────────────────────────────────────

  Future<void> _storage() async {
    final store = VexChannel.bridge(VexStorage.instance);
    await store.setString('vex_demo_key', 'VexChannel rocks!');
    final val = await store.getString('vex_demo_key');
    await store.setInt('launch_count', 42);
    final count = await store.getInt('launch_count');
    _show('💾 Storage:\nKey: $val\nLaunch count: $count');
  }

  // ── Sensors stream ─────────────────────────────────────────────────────────

  Future<void> _sensors() async {
    final sensors = VexChannel.bridge(VexSensors.instance);
    _show('🌀 Listening to accelerometer...');
    sensors.accelerometer.take(5).listen(
      (data) => _show('🌀 Accel: x=${data.x.toStringAsFixed(2)} '
          'y=${data.y.toStringAsFixed(2)} z=${data.z.toStringAsFixed(2)}'),
    );
  }

  // ── File System ────────────────────────────────────────────────────────────

  Future<void> _fileSystem() async {
    final fs = VexChannel.bridge(VexFileSystem.instance);
    final docs = await fs.documentsDirectory;
    final path = '$docs/vex_test.txt';
    await fs.writeAsString(path, 'VexChannel file I/O test ✅');
    final content = await fs.readAsString(path);
    final size = await fs.fileSize(path);
    _show('📁 Docs: $docs\nWritten & read: $content\nSize: $size bytes');
  }

  // ── Permissions ────────────────────────────────────────────────────────────

  Future<void> _permissions() async {
    final perms = VexChannel.bridge(VexPermissions.instance);
    final camera = await perms.check(VexPermission.camera);
    final location = await perms.check(VexPermission.location);
    _show('🔐 Camera: ${camera.name}\nLocation: ${location.name}');
  }

  // ── Low-level raw invoke (no bridge) ──────────────────────────────────────

  Future<void> _rawInvoke() async {
    final res = await VexChannel.invoke<double>(
      channel: 'vex_channel/battery',
      method: 'getBatteryLevel',
    );
    res.when(
      success: (v) => _show('⚡ Raw invoke: battery=$v%'),
      failure: (e) => _show('✗ Error: $e'),
    );
  }

  // ── Custom bridge (zero-boilerplate pattern demo) ─────────────────────────

  Future<void> _customBridge() async {
    final bridge = VexChannel.bridge(MyCustomBridge());
    final result = await bridge.getAppVersion();
    _show('🎯 Custom Bridge: version=$result\n'
        'Platform: ${VexChannel.currentPlatform.name}');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('⚡ VexChannel'),
        backgroundColor: Colors.deepPurple,
        foregroundColor: Colors.white,
      ),
      body: Column(
        children: [
          Expanded(
            child: Container(
              width: double.infinity,
              margin: const EdgeInsets.all(16),
              padding: const EdgeInsets.all(16),
              decoration: BoxDecoration(
                color: Colors.grey[100],
                borderRadius: BorderRadius.circular(12),
                border: Border.all(color: Colors.deepPurple.withValues(alpha: 0.3)),
              ),
              child: SingleChildScrollView(
                child: Text(_output, style: const TextStyle(fontFamily: 'monospace')),
              ),
            ),
          ),
          Expanded(
            child: GridView.count(
              crossAxisCount: 3,
              padding: const EdgeInsets.all(12),
              mainAxisSpacing: 8,
              crossAxisSpacing: 8,
              children: [
                _Btn('🔋 Battery', _getBattery, Colors.orange),
                _Btn('📱 Device', _getDeviceInfo, Colors.blue),
                _Btn('📡 Network', _getConnectivity, Colors.green),
                _Btn('📳 Haptics', _haptics, Colors.purple),
                _Btn('📋 Clipboard', _clipboard, Colors.teal),
                _Btn('💾 Storage', _storage, Colors.red),
                _Btn('🌀 Sensors', _sensors, Colors.indigo),
                _Btn('📁 Files', _fileSystem, Colors.brown),
                _Btn('🔐 Perms', _permissions, Colors.pink),
                _Btn('⚡ Raw', _rawInvoke, Colors.amber),
                _Btn('🎯 Custom', _customBridge, Colors.cyan),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class _Btn extends StatelessWidget {
  final String label;
  final VoidCallback onTap;
  final Color color;
  const _Btn(this.label, this.onTap, this.color);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onTap,
      style: ElevatedButton.styleFrom(
        backgroundColor: color,
        foregroundColor: Colors.white,
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
      ),
      child: Text(label, textAlign: TextAlign.center, style: const TextStyle(fontSize: 12)),
    );
  }
}

// ─── Custom bridge example ─────────────────────────────────────────────────

/// Shows how a developer creates their OWN bridge with VexChannel:
/// 1. Extend VexBridgeBase
/// 2. Set channelName
/// 3. Call invokeMethod / openStream
/// No native code changes needed for the Dart side!
class MyCustomBridge extends VexBridgeBase {
  @override
  String get channelName => 'com.myapp/custom';

  Future<String> getAppVersion() async {
    // This calls native — the developer only writes Dart
    final res = await invokeMethod<String>('getAppVersion');
    return res.unwrapOr('1.0.0');
  }

  Stream<Map<String, dynamic>> get liveEvents =>
      openStream<Map<String, dynamic>>(eventName: 'liveEvents');
}
2
likes
130
points
27
downloads

Documentation

Documentation
API reference

Publisher

verified publishermysteriouscoder.com

Weekly Downloads

VexChannel — Zero-boilerplate platform channels for Flutter. Write pure Dart, access every native API on Android, iOS, macOS, Windows, Linux and Web without touching Kotlin/Swift/C++ once.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

collection, crypto, flutter, flutter_web_plugins, json_annotation, path, plugin_platform_interface

More

Packages that depend on vex_channel

Packages that implement vex_channel