mobile_proof_plugin 0.1.1 copy "mobile_proof_plugin: ^0.1.1" to clipboard
mobile_proof_plugin: ^0.1.1 copied to clipboard

Flutter plugin for TLSN-based mobile proofs with WebView capture and custom MPC provider flows.

example/lib/main.dart

import 'dart:async';

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'mobile_proof_plugin example',
      theme: ThemeData(
        colorSchemeSeed: const Color(0xFF2563EB),
        useMaterial3: true,
      ),
      home: const ExampleHomePage(),
    );
  }
}

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

  @override
  State<ExampleHomePage> createState() => _ExampleHomePageState();
}

class _ExampleHomePageState extends State<ExampleHomePage> {
  static const String _providerRegistryAssetPath =
      'packages/mobile_proof_plugin/assets/providers.json';

  final TextEditingController _verifierUrlController = TextEditingController(
    text: 'http://10.0.2.2:7047',
  );
  bool _running = false;
  String _status = 'Ready';

  @override
  void dispose() {
    _verifierUrlController.dispose();
    super.dispose();
  }

  Future<void> _runProof() async {
    final verifierUrl = Uri.tryParse(_verifierUrlController.text.trim());
    if (verifierUrl == null) {
      setState(() {
        _status = 'Invalid verifier URL';
      });
      return;
    }

    setState(() {
      _running = true;
      _status = 'Starting provider flow...';
    });

    final client = MobileProofClient(bridge: MethodChannelNativeBridge());
    final StreamSubscription<SessionProgress> progressSub =
        client.subscribeProgress().listen((progress) {
      if (!mounted) return;
      setState(() {
        _status = '[${progress.phase.name}] ${progress.message}';
      });
    });

    try {
      await client.attestProvider(
        context: context,
        providerId: 'kaggle.current_user.v1',
        providerRegistryAssetPath: _providerRegistryAssetPath,
        transportConfig: TransportConfig(
          deploymentMode: DeploymentMode.hosted,
          verifierUrl: verifierUrl,
          trustedNotaryKeys: const <String>[
            // Replace with production notary keys.
            'REPLACE_WITH_BASE64_NOTARY_PUBLIC_KEY'
          ],
          enforceNativeCore: false,
          enableLogging: true,
        ),
      );
      if (!mounted) return;
      setState(() {
        _status = 'Proof generated successfully';
      });
    } on ProofException catch (error) {
      if (!mounted) return;
      setState(() {
        _status = 'Proof failed: [${error.code.name}] ${error.message}';
      });
    } finally {
      await progressSub.cancel();
      await client.dispose();
      if (mounted) {
        setState(() {
          _running = false;
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('mobile_proof_plugin')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            TextField(
              controller: _verifierUrlController,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Verifier URL',
              ),
            ),
            const SizedBox(height: 12),
            FilledButton(
              onPressed: _running ? null : _runProof,
              child: Text(_running ? 'Running...' : 'Run Provider Attestation'),
            ),
            const SizedBox(height: 12),
            Text('Status: $_status'),
          ],
        ),
      ),
    );
  }
}