android_restore_credentials 0.1.0 copy "android_restore_credentials: ^0.1.0" to clipboard
android_restore_credentials: ^0.1.0 copied to clipboard

PlatformAndroid

Android-only Flutter plugin for Zero-Tap sign-in restoration via Credential Manager Restore Credentials.

example/lib/main.dart

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'package:android_restore_credentials/android_restore_credentials.dart';

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

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _plugin = AndroidRestoreCredentials();
  String _status = 'Idle';
  bool _busy = false;

  @override
  void initState() {
    super.initState();
    // Tier 2 — foreground restoration: attempt a silent get on first launch
    // to cover the case where background (BackupAgent) restore did not run,
    // backup is off, or restore is independent of app-data backup.
    _restoreOnFirstLaunch();
  }

  Future<void> _restoreOnFirstLaunch() async {
    if (!mounted) return;
    if (!kIsWeb && defaultTargetPlatform != TargetPlatform.android) {
      setState(() => _status = 'Restore Credentials only run on Android.');
      return;
    }
    setState(() => _status = 'Checking for a restore key on first launch…');
    try {
      final assertion = await _plugin.getRestoreKey(requestJson: _fixtureGetJson);
      if (!mounted) return;
      // In a real app you would POST `assertion` to your RP to verify and
      // establish a session. Here we just display it.
      setState(() => _status = 'Restored (first launch): $assertion');
    } on PlatformException catch (e) {
      if (!mounted) return;
      // `no_credential` is the normal "nothing to restore" case.
      setState(() => _status = 'No restore key on first launch (${e.code}).');
    }
  }

  @override
  Widget build(BuildContext context) {
    final onAndroid = !kIsWeb && defaultTargetPlatform == TargetPlatform.android;
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Restore Credentials example')),
        body: Center(
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(_status, textAlign: TextAlign.center),
                const SizedBox(height: 16),
                if (onAndroid) ...[
                  ElevatedButton(
                    onPressed: _busy ? null : _create,
                    child: const Text('Create restore key (after sign-in)'),
                  ),
                  ElevatedButton(
                    onPressed: _busy ? null : _get,
                    child: const Text('Get restore key'),
                  ),
                  ElevatedButton(
                    onPressed: _busy ? null : _clear,
                    child: const Text('Clear restore key (on sign-out)'),
                  ),
                ] else
                  const Text('Restore Credentials only run on Android.'),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Future<void> _run(String label, Future<String?> Function() action) async {
    setState(() {
      _busy = true;
      _status = '$label…';
    });
    try {
      final result = await action();
      if (!mounted) return;
      setState(() => _status = '$label: $result');
    } on PlatformException catch (e) {
      if (!mounted) return;
      setState(() => _status = '$label failed: ${e.code} ${e.message}');
    } finally {
      if (mounted) setState(() => _busy = false);
    }
  }

  Future<void> _create() => _run(
        'Created',
        () async => _plugin.createRestoreKey(requestJson: _fixtureCreateJson),
      );

  Future<void> _get() => _run(
        'Got',
        () async => _plugin.getRestoreKey(requestJson: _fixtureGetJson),
      );

  Future<void> _clear() async {
    setState(() {
      _busy = true;
      _status = 'Clearing…';
    });
    try {
      await _plugin.clearRestoreKey();
      if (!mounted) return;
      setState(() => _status = 'Cleared');
    } on PlatformException catch (e) {
      if (!mounted) return;
      setState(() => _status = 'Clear failed: ${e.code} ${e.message}');
    } finally {
      if (mounted) setState(() => _busy = false);
    }
  }
}

/// Fixture WebAuthn JSON for the example only. A real host fetches this from
/// its relying-party server.
const _fixtureCreateJson = '''
{
  "challenge": "dGVzdA",
  "rp": {"name": "Example", "id": "example.com"},
  "user": {"id": "dXNlcg", "name": "user", "displayName": "User"},
  "pubKeyCredParams": [{"type": "public-key", "alg": -7}]
}
''';

const _fixtureGetJson = '''
{
  "challenge": "dGVzdA",
  "rpId": "example.com"
}
''';
5
likes
160
points
54
downloads

Documentation

API reference

Publisher

verified publisherwunderbytes.eu

Weekly Downloads

Android-only Flutter plugin for Zero-Tap sign-in restoration via Credential Manager Restore Credentials.

Repository (GitHub)
View/report issues

Topics

#android #credential-manager #restore-credentials #sign-in

License

BSD-3-Clause (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on android_restore_credentials

Packages that implement android_restore_credentials