Flutter身份验证与电子KYC插件authme_ekyc_sdk的使用

Flutter身份验证与电子KYC插件authme_ekyc_sdk的使用

本文档将指导你如何在Flutter项目中使用authme_ekyc_sdk插件来实现身份验证和电子KYC功能。通过本指南,你将了解如何安装该插件、初始化SDK以及启动各种认证功能。

功能

  • 身份验证:支持多种认证类型,如身份证、护照等。
  • 电子KYC:支持文档识别、活体检测等功能。

使用步骤

1. 添加依赖

在你的pubspec.yaml文件中添加authme_ekyc_sdk依赖:

dependencies:
  authme_ekyc_sdk: ^1.0.0

然后运行flutter pub get来获取依赖包。

2. 初始化SDK

在你的main.dart文件中,初始化SDK并设置必要的配置:

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:authme_ekyc_sdk/authme_ui_config.dart';
import 'package:authme_ekyc_sdk/ekyc_feature.dart';
import 'package:authme_ekyc_sdk/ekyc_locale.dart';
import 'package:authme_ekyc_sdk/ekyc_sdk_plugin_bridge.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter AuthMe eKYC SDK Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const AuthMeHomePage(),
    );
  }
}

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

  [@override](/user/override)
  State<AuthMeHomePage> createState() => _AuthMeHomePageState();
}

class _AuthMeHomePageState extends State<AuthMeHomePage> {
  final Color _buttonColor = const Color(0xFF00C1B6);
  final Color _defaultButtonColor = const Color(0xFFFFFFFF);
  String? _token;
  bool _isLoading = false;
  final AuthmeSdk _authMeSdk = AuthmeSdk();
  late StreamSubscription _resultSubscription;
  String _name = "";
  var timestamp = DateTime.now().millisecondsSinceEpoch;
  bool _isInitialized = false;

  AuthmeLocale _selectedLanguage = AuthmeLocale.zhHant;
  bool _needConfirm = true;
  bool _isResultPageDisplayable = true;
  bool _isResultEditable = true;

  ActionButtonConfig? _actionButtonConfig;
  ActionHintConfig? _actionHintConfig;
  CloseHintConfig? _closeHintConfig;
  BackHintConfig? _backHintConfig;
  StepButtonConfig? _stepButtonConfig;
  bool _showStatement = true;

  [@override](/user/override)
  void initState() {
    super.initState();
    _resultSubscription = _authMeSdk.resultStream.listen(
      (result) {
        if (result.containsKey('result')) {
          final resultMap = result['result'];
          if (resultMap is Map) {
            final data = resultMap['data'];
            final images = resultMap['images'];

            if (data is Map) {
              Map<String, dynamic> modifications = Map.from(data);

              modifications['address'] = 'new address';

              _authMeSdk.confirmScanResult(modifications).then((_) {
                log('Scan result confirmed:$modifications');
              }).catchError((error) {
                log('Failed to confirm scan result: $error');
              });

              if (images != null && images is Map<String, dynamic>) {
                final frontCropImage = images['frontCropImage'];
                final frontImage = images['frontImage'];
                final backCropImage = images['backCropImage'];
                final backImage = images['backImage'];

                final List<Uint8List> imageBytes = [
                  frontCropImage,
                  frontImage,
                  backCropImage,
                  backImage,
                ].map((base64) => base64Decode(base64!.split(',').last)).toList();

                Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) => ListView.builder(
                              padding: const EdgeInsets.all(10),
                              itemCount: imageBytes.length,
                              itemBuilder: (context, index) {
                                return Padding(
                                  padding: const EdgeInsets.only(bottom: 10),
                                  child: ClipRRect(
                                    borderRadius: BorderRadius.circular(10),
                                    child: Image.memory(
                                      imageBytes[index],
                                      fit: BoxFit.cover,
                                      height: 200,
                                      width: double.infinity,
                                    ),
                                  ),
                                );
                              },
                            )));
              }
            }
          }
        } else if (result.containsKey('error')) {
          log("錯誤: ${result['error']}");
        }
      },
      onError: (error) {
        log("Stream error: $error");
      },
    );
  }

  Future<void> _fetchToken() async {
    setState(() {
      _isLoading = true;
    });

    try {
      final response = await http.post(
        Uri.parse('https://stage.auth.authme.com/connect/token'),
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: {
          'client_id': 'd7e8cf57499b4c348fbfb4b3e92d0182',
          'client_secret': 'oy9rDBCv5trf6BJe',
          'grant_type': 'client_credentials',
          'scope': 'AuthmeServices customer_id:FlutterTest$timestamp event_name:default',
        },
      );
      log(response.toString());

      if (response.statusCode == 200) {
        final Map<String, dynamic> jsonResponse = json.decode(response.body);
        setState(() {
          _token = jsonResponse['access_token'];
          _isLoading = false;
        });
        _authMeSdk.refreshToken(_token!);
      } else {
        throw Exception('Failed to load token');
      }
    } catch (e) {
      setState(() {
        _isLoading = false;
      });
      print('Error fetching token: $e');
    }
  }

  Future<void> initSDK() async {
    try {
      var serverURL = "https://stage.api.authme.com";
      var activateToken = "YOUR_ACTIVATE_TOKEN_HERE";
      var activateCertificate = "YOUR_ACTIVATE_CERTIFICATE_HERE";

      final uiConfig = AuthMeUIConfig(
        actionButton: _actionButtonConfig,
        actionHint: _actionHintConfig,
        closeHint: _closeHintConfig,
        backHint: _backHintConfig,
        stepButton: _stepButtonConfig,
        showStatement: _showStatement,
      );

      await _authMeSdk.initialize(
        serverURL,
        activateToken,
        activateCertificate,
        showStatement: _showStatement,
      );
      _authMeSdk.setLocale(AuthmeLocale.zhHant);
    } on PlatformException catch (e) {
      log("Failed to initialize AuthMe SDK: ${e.message}");
    } catch (e) {
      log("An unexpected error occurred: ${e.runtimeType}");
    }
  }

  void _startAuthme() async {
    try {
      await _fetchToken();
      if (_token != null) {
        await _authMeSdk.startFeature(
          _token!,
          AuthmeFeature.TWID,
          needConfirm: _needConfirm,
          isResultPageDisplayable: _isResultPageDisplayable,
          isResultEditable: _isResultEditable,
          requestCode: 999,
        );
      } else {
        log('Token 不可用');
      }
    } on PlatformException catch (e) {
      log("Failed to start AuthMe SDK: ${e.message}");
    } catch (e) {
      log("An unexpected error occurred: ${e.runtimeType}");
    }
  }

  void _startAuthmeLiveness() async {
    try {
      _fetchToken();
      if (_token != null) {
        await _authMeSdk.startFeature(
          _token!,
          AuthmeFeature.Liveness,
          needConfirm: _needConfirm,
          isResultPageDisplayable: _isResultPageDisplayable,
          isResultEditable: _isResultEditable,
        );
      } else {
        log('Token 不可用');
      }
    } on PlatformException catch (e) {
      log("Failed to start Authme Liveness: ${e.message}");
    } catch (e) {
      log("An unexpected error occurred: ${e.runtimeType}");
    }
  }

  void _startAuthmePassport() async {
    _fetchToken();
    if (_token != null) {
      await _authMeSdk.startFeature(
        _token!,
        AuthmeFeature.Passport,
        needConfirm: _needConfirm,
        isResultPageDisplayable: _isResultPageDisplayable,
        isResultEditable: _isResultEditable,
      );
    } else {
      print('Token 不可用');
    }
  }

  void _startAuthmePassportNFC() async {
    _fetchToken();
    if (_token != null) {
      await _authMeSdk.startFeature(
        _token!,
        AuthmeFeature.NFCPassport,
        needConfirm: _needConfirm,
        isResultPageDisplayable: _isResultPageDisplayable,
        isResultEditable: _isResultEditable,
      );
    } else {
      print('Token 不可用');
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("Flutter AuthMe eKYC SDK Example"),
      ),
      body: _isLoading
          ? const Center(child: CircularProgressIndicator())
          : SingleChildScrollView(
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    _colorPanel(),
                    const SizedBox(height: 20),
                    _buildSettingsCard(),
                    const SizedBox(height: 20),
                    _buildFeaturesCard(),
                  ],
                ),
              ),
            ),
    );
  }

  Widget _colorPanel() {
    if (Platform.isIOS) {
      return Card(
        margin: EdgeInsets.zero,
        color: Colors.white,
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              ColorSettingsPanel(
                actionButtonConfig: _actionButtonConfig,
                actionHintConfig: _actionHintConfig,
                closeHintConfig: _closeHintConfig,
                backHintConfig: _backHintConfig,
                stepButtonConfig: _stepButtonConfig,
                showStatement: _showStatement,
                isInitialized: _isInitialized,
                onShowStatementChanged: (value) {
                  setState(() => _showStatement = value);
                },
                onActionButtonChanged: _updateActionButton,
                onActionHintChanged: _updateActionHint,
                onCloseHintChanged: _updateCloseHint,
                onBackHintChanged: _updateBackHint,
                onStepButtonChanged: _updateStepButton,
                onApplyConfig: () {
                  _authMeSdk.setUIConfig(AuthMeUIConfig(
                      actionButton: _actionButtonConfig,
                      actionHint: _actionHintConfig,
                      closeHint: _closeHintConfig,
                      backHint: _backHintConfig,
                      stepButton: _stepButtonConfig,
                      showStatement: _showStatement));

                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(
                      content: Text('UI 設定已更新'),
                      backgroundColor: Colors.green,
                    ),
                  );
                },
              ),
            ],
          ),
        ),
      );
    } else {
      return const SizedBox(height: 0);
    }
  }

  Widget _buildSettingsCard() {
    return Card(
      margin: EdgeInsets.zero,
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text('設置', style: Theme.of(context).textTheme.titleLarge),
                _isLoading
                    ? const SizedBox(
                        width: 20,
                        height: 20,
                        child: CircularProgressIndicator(strokeWidth: 2),
                      )
                    : const SizedBox(),
              ],
            ),
            const SizedBox(height: 16),
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 16),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    '語言設定',
                    style: Theme.of(context).textTheme.titleSmall,
                  ),
                  const SizedBox(height: 8),
                  DropdownButtonFormField<AuthmeLocale>(
                    value: _selectedLanguage,
                    decoration: const InputDecoration(
                      contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
                      border: OutlineInputBorder(),
                    ),
                    items: AuthmeLocale.values.map((language) {
                      return DropdownMenuItem(
                        value: language,
                        child: Text(language.displayName),
                      );
                    }).toList(),
                    onChanged: (AuthmeLocale? value) {
                      if (value != null) {
                        setState(() {
                          _selectedLanguage = value;
                        });
                        _updateLanguage(value);
                      }
                    },
                  ),
                ],
              ),
            ),
            SwitchListTile(
              title: const Text('需要確認'),
              value: _needConfirm,
              onChanged: (bool value) {
                setState(() => _needConfirm = value);
              },
            ),
            SwitchListTile(
              title: const Text('顯示結果頁面'),
              value: _isResultPageDisplayable,
              onChanged: (bool value) {
                setState(() => _isResultPageDisplayable = value);
              },
            ),
            SwitchListTile(
              title: const Text('允許編輯結果'),
              value: _isResultEditable,
              onChanged: (bool value) {
                setState(() => _isResultEditable = value);
              },
            ),
            const SizedBox(height: 8),
            Row(
              children: [
                Expanded(
                  child: ElevatedButton(
                    onPressed: _isInitialized
                        ? null
                        : () async {
                            setState(() {
                              _isInitialized = true;
                            });
                            try {
                              initSDK();
                              ScaffoldMessenger.of(context).showSnackBar(
                                const SnackBar(
                                  content: Text('SDK 初始化成功'),
                                  backgroundColor: Colors.green,
                                ),
                              );
                            } catch (e) {
                              setState(() {
                                _isInitialized = false;
                              });
                              ScaffoldMessenger.of(context).showSnackBar(
                                SnackBar(
                                  content: Text('初始化失敗: $e'),
                                  backgroundColor: Colors.red,
                                ),
                              );
                            }
                          },
                    style: ElevatedButton.styleFrom(
                      padding: const EdgeInsets.symmetric(vertical: 16),
                      backgroundColor: _buttonColor,
                      disabledBackgroundColor: _buttonColor.withOpacity(0.6),
                    ),
                    child: const Text(
                      "初始化 SDK",
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ),
                const SizedBox(width: 8),
                Expanded(
                  child: ElevatedButton(
                    onPressed: _isInitialized && _token == null
                        ? () => _fetchToken()
                        : null,
                    style: ElevatedButton.styleFrom(
                      padding: const EdgeInsets.symmetric(vertical: 16),
                      backgroundColor: _buttonColor,
                      disabledBackgroundColor: _buttonColor.withOpacity(0.6),
                    ),
                    child: const Text(
                      "Get Token",
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildFeaturesCard() {
    return Card(
      margin: EdgeInsets.zero,
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('功能', style: Theme.of(context).textTheme.titleLarge),
            const SizedBox(height: 16),
            GridView.count(
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              crossAxisCount: 2,
              mainAxisSpacing: 8,
              crossAxisSpacing: 8,
              childAspectRatio: 2.5,
              children: [
                _buildFeatureButton('Start AuthMe', _startAuthme),
                _buildFeatureButton('Start AuthMe Liveness', _startAuthmeLiveness),
                _buildFeatureButton('Start Authme Passport', _startAuthmePassport),
                _buildFeatureButton('Start Authme Passport NFC', _startAuthmePassportNFC),
              ],
            ),
            if (_name.isNotEmpty) ...[
              const SizedBox(height: 16),
              Text(
                "Name: $_name",
                style: const TextStyle(fontSize: 24),
              ),
            ],
          ],
        ),
      ),
    );
  }

  Widget _buildFeatureButton(String title, VoidCallback onPressed) {
    final bool isEnabled = _isInitialized && _token != null;
    final txtColor = isEnabled ? Colors.black : Colors.grey;

    return ElevatedButton(
      onPressed: isEnabled ? onPressed : null,
      style: ElevatedButton.styleFrom(
        backgroundColor: _defaultButtonColor,
        disabledBackgroundColor: _defaultButtonColor,
      ),
      child: Text(
        title,
        textAlign: TextAlign.center,
        maxLines: 2,
        overflow: TextOverflow.ellipsis,
        style: TextStyle(color: txtColor),
      ),
    );
  }

  Future<void> _updateLanguage(AuthmeLocale language) async {
    try {
      await _authMeSdk.setLocale(language);
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('語言設定已更新'),
          backgroundColor: Colors.green,
        ),
      );
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('更新語言失敗: ${e.toString()}'),
          backgroundColor: Colors.red,
        ),
      );
    } finally {}
  }

  void _updateActionButton({Color? backgroundColor, Color? contentColor}) {
    setState(() {
      _actionButtonConfig = ActionButtonConfig(
        backgroundColor: backgroundColor ?? _actionButtonConfig?.backgroundColor ?? Colors.blue,
        contentColor: contentColor ?? _actionButtonConfig?.contentColor ?? Colors.white,
      );
    });
  }

  void _updateActionHint({Color? backgroundColor, Color? contentColor}) {
    setState(() {
      _actionHintConfig = ActionHintConfig(
        backgroundColor: backgroundColor ?? _actionHintConfig?.backgroundColor ?? Colors.white,
        contentColor: contentColor ?? _actionHintConfig?.contentColor ?? Colors.black,
      );
    });
  }

  void _updateCloseHint({Color? backgroundColor, Color? contentColor}) {
    setState(() {
      _closeHintConfig = CloseHintConfig(
        backgroundColor: backgroundColor ?? _closeHintConfig?.backgroundColor ?? Colors.white,
        contentColor: contentColor ?? _closeHintConfig?.contentColor ?? Colors.black,
      );
    });
  }

  void _updateBackHint({Color? contentColor}) {
    setState(() {
      _backHintConfig = BackHintConfig(
        contentColor: contentColor ?? _backHintConfig?.contentColor ?? Colors.black,
      );
    });
  }

  void _updateStepButton({Color? backgroundColor, Color? contentColor}) {
    setState(() {
      _stepButtonConfig = StepButtonConfig(
        backgroundColor: backgroundColor ?? _stepButtonConfig?.backgroundColor ?? Colors.blue,
        contentColor: contentColor ?? _stepButtonConfig?.contentColor ?? Colors.white,
      );
    });
  }

  [@override](/user/override)
  void dispose() {
    _resultSubscription.cancel();
    _authMeSdk.dispose();
    super.dispose();
  }
}

更多关于Flutter身份验证与电子KYC插件authme_ekyc_sdk的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter身份验证与电子KYC插件authme_ekyc_sdk的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


authme_ekyc_sdk 是一个用于 Flutter 的插件,主要用于身份验证和电子 KYC(Know Your Customer)流程。该插件通常用于需要验证用户身份的应用程序,例如金融、电子商务或其他需要用户身份验证的场景。

以下是如何在 Flutter 项目中使用 authme_ekyc_sdk 的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 authme_ekyc_sdk 插件的依赖。

dependencies:
  flutter:
    sdk: flutter
  authme_ekyc_sdk: ^版本号  # 替换为最新的版本号

然后运行 flutter pub get 来安装依赖。

2. 初始化 SDK

在使用 authme_ekyc_sdk 之前,通常需要初始化 SDK。这通常涉及到设置 API 密钥或其他配置。

import 'package:authme_ekyc_sdk/authme_ekyc_sdk.dart';

void initializeSDK() async {
  try {
    await AuthMeEkycSdk.initialize(apiKey: 'YOUR_API_KEY');
    print('SDK initialized successfully');
  } catch (e) {
    print('Failed to initialize SDK: $e');
  }
}

3. 启动身份验证流程

初始化 SDK 后,你可以启动身份验证流程。通常,这涉及到调用一个方法来启动 KYC 流程。

void startKYCProcess() async {
  try {
    final result = await AuthMeEkycSdk.startKYC();
    if (result.success) {
      print('KYC process completed successfully');
      // 处理成功结果,例如获取用户信息
      print('User Info: ${result.userInfo}');
    } else {
      print('KYC process failed: ${result.errorMessage}');
    }
  } catch (e) {
    print('Failed to start KYC process: $e');
  }
}

4. 处理回调

在某些情况下,你可能需要处理来自 SDK 的回调,例如用户取消操作或发生错误。

void handleCallbacks() {
  AuthMeEkycSdk.setCallbackListener((event) {
    switch (event) {
      case AuthMeEkycEvent.cancelled:
        print('User cancelled the KYC process');
        break;
      case AuthMeEkycEvent.error:
        print('An error occurred during the KYC process');
        break;
      default:
        print('Unknown event: $event');
    }
  });
}

5. 集成到 UI

最后,你可以将 KYC 流程集成到你的应用程序 UI 中。例如,可以在按钮点击时启动 KYC 流程。

ElevatedButton(
  onPressed: () {
    startKYCProcess();
  },
  child: Text('Start KYC Process'),
);
回到顶部