Skip to main content

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

Apacuana SDK Core proporciona una interfaz para interactuar con los servicios de Apacuana.

apacuana_sdk_flutter #

Apacuana SDK para Flutter es un wrapper de alto nivel construido sobre apacuana_sdk_core_dart. Proporciona un Provider y un Notifier (basado en ChangeNotifier) que simplifican la integración de los servicios de Apacuana en apps Flutter, manejando:

  • Inicialización del SDK y estado de servicio.
  • Generación de certificados digitales en el dispositivo.
  • Firma electrónica de documentos.
  • Consulta del estado de certificados y documentos.
  • Gestión de revocaciones.
  • Flujos de Face Liveness con un modal embebido.

Este paquete abstrae detalles de estado, modales y almacenamiento local cifrado, exponiendo una API declarativa y fácil de usar desde widgets.


Índice #


Instalación #

En tu pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0
  dio: ^5.4.0
  apacuana_sdk_flutter: ^0.1.0   # Este paquete

Luego:

flutter pub get

Inicialización rápida #

Envuelve tu aplicación con el ApacuanaProvider. Este inicializa automáticamente el core cuando apiUrl y apiKey están presentes, y presenta los modales del SDK sobre tu UI.

Parámetros clave del config:

  • apiUrl: URL base de la API de Apacuana.
  • secretKey: Llave secreta del cliente.
  • apiKey: Clave pública de API (identifica tu integración).
  • verificationId: Identificador de verificación inicial (usado en algunos flujos como onpremise).
  • customerId (opcional): Usuario ya autenticado en tu sistema; si se provee el SDK intentará cargar su contexto.
  • encryptionKey: Clave simétrica para cifrar datos sensibles localmente (elige una distinta por entorno, 16/24/32 bytes para AES).
  • integrationType: Tipo de integración (ej. ONBOARDING, puede cambiar según el flujo que estés habilitando).

Ejemplo completo de inicialización (entorno dev):

import 'package:flutter/material.dart';
import 'package:apacuana_sdk_flutter/providers/apacuana_provider.dart';
import 'package:apacuana_sdk_flutter/providers/apacuana_notifier.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    // Puedes obtener el customerId de un login previo o almacenamiento seguro
    final String? customerId = null; // Reemplaza con tu lógica

    final config = {
      'apiUrl': 'https://api.dev.apacuana.3dlinkweb.com',
      'secretKey': 'fvTaYQzi1tubvKVZ2P9Ev3nw7v9WyEGh5k7PM9HDz8AB9J9uygJf76ihW9mTa8T08pv4Ww7XLY9r4B5KDc4BDikMJ6KGUJnX85CNh6QwDvBrS1apb5e3VVTWgHug7Y5f',
      'apiKey': '07NTZW6cCgSCKjhzSe1UJ2uJ6fTXHaAFKcfDtJqV5Vnhg0h2BitNr6iYCeM7ZZ7CpcAVcQqk4EP0VmxvWPkTgBczpa8mGZjSU2V4zr56CpqLUM1AfjvXw79Gt4nppiTW',
      'verificationId': '53d1daa5-cc7a-4a70-ae46-1a3e8a405f7a',
      if (customerId != null && customerId.isNotEmpty) 'customerId': customerId,
      'encryptionKey': 'estaesmiclavesecretaAES256123456',
      'integrationType': 'ONBOARDING',
    };

    return MaterialApp(
      title: 'Apacuana Demo',
      builder: (context, child) {
        return ApacuanaProvider(
          config: config,
          child: child ?? const SizedBox.shrink(),
        );
      },
      home: const HomePage(),
    );
  }
}

// Cómo obtener el notifier:
class HomePage extends StatelessWidget {
  const HomePage({super.key});
  @override
  Widget build(BuildContext context) {
    final notifier = ApacuanaProvider.of(context, listen: true);
    return Scaffold(
      appBar: AppBar(title: const Text('Demo Apacuana')),
      body: Center(child: Text('Estado SDK: ${notifier.status}')),
    );
  }
}

Arquitectura: Provider + Notifier #

El paquete expone:

  • ApacuanaProvider (Widget): inyecta y gestiona un ApacuanaNotifier en el árbol de widgets, inicializa el core y renderiza un modal propio (ApacuanaModal) por encima de tu UI cuando el SDK lo requiere (por ejemplo, para el flujo de liveness).
  • ApacuanaNotifier (ChangeNotifier): contiene el estado del SDK y los métodos de alto nivel para llamar a los servicios (certificados, firmas, liveness, revocaciones, etc.). Es el punto de entrada en tu UI para realizar operaciones.

Ventajas:

  • Inicialización automática.
  • Un solo punto de acceso al SDK desde la UI (ApacuanaProvider.of(context)).
  • Modal gestionado por el SDK (aparecerá cuando el flujo lo requiera).

Configuración del SDK (config) #

El config que pasas al ApacuanaProvider es un Map<String, dynamic> que el core usa para inicializarse:

  • apiUrl (String, requerido): URL base del backend.
  • apiKey (String, requerido): clave de API si tu backend la requiere.
  • encryptionKey (String, recomendado): clave para cifrar datos sensibles (claves privadas, certificados) en el dispositivo.
  • customerId (String, opcional): si ya tienes sesión de usuario, permite inicializar con token y userData.
  • Otros campos que tu core soporte (p. ej. entorno, timeouts, etc.).

El Provider hace:

  • Si apiUrl y apiKey existen y no están vacíos: notifier.initCore(config).
  • Si customerId está presente, el core intentará recuperar token/userData y configurar autenticación.

API del Notifier (métodos y ejemplos) #

Para obtener el notifier:

final apn = ApacuanaProvider.of(context);

El estado del servicio:

  • apn.status: ApacuanaServiceStatus (idle | initializing | ready | error)
  • apn.error: último error (si hubo) durante la init.

Importante: muchas operaciones requieren que el SDK esté ready.

getConfig #

  • Firma: Future<SdkConfig?> getConfig()
  • Requiere: SDK inicializado.
  • Retorno: objeto de configuración actual (SdkConfig) o null si falla.

Ejemplo:

final cfg = await apn.getConfig();
debugPrint('customerId: ${cfg?.customerId}, apiUrl: ${cfg?.apiUrl}');

getCustomer #

  • Firma: Future<ApacuanaSuccess> getCustomer()
  • Requiere: customerId (sesión)
  • Retorno: ApacuanaSuccess con data contendo token/userData (estructura exacta desde el core).

Ejemplo:

final res = await apn.getCustomer();
debugPrint('getCustomer success: ${res.success}, data: ${res.data}');

generateCert #

  • Firma: Future<ApiResult> generateCert({ required String pin, bool enableSaveWithBiometrics = false })
  • Requiere: SDK en estado ready y customerId.
  • Parámetros:
    • pin (String): PIN para proteger el uso local de la clave/cert.
    • enableSaveWithBiometrics (bool): si true, solicitará autenticación biométrica y asociará el usuario a biometría para accesos futuros.
  • Proceso (resumen):
    1. Genera un par de llaves RSA en el dispositivo.
    2. Construye un CSR y lo cifra (según flujo).
    3. Llama al core generateCert.
    4. Cifra y guarda en el dispositivo la clave privada, el certificado y el PIN.
  • Retorno: ApiResult con data: CertData (cert y certifiedId) cuando aplica.

Ejemplo:

final res = await apn.generateCert(pin: '1234', enableSaveWithBiometrics: false);
if (res.success) {
  final certData = res.data as CertData?;
  debugPrint('Cert creado: id=${certData?.certifiedId}');
} else {
  debugPrint('Error: ${res.message}');
}

isCertificateInDevice #

  • Firma: Future<bool> isCertificateInDevice()
  • Requiere: SDK en ready.
  • Retorno: true si hay un certificado guardado cifrado en el dispositivo.

Ejemplo:

final hasCert = await apn.isCertificateInDevice();

getCertStatus #

  • Firma: Future<Map<String, dynamic>> getCertStatus()
  • Requiere: SDK ready y customerId.
  • Descripción: Pregunta al core el estado del certificado (normaliza la respuesta a Map encodable).
  • Retorno: Map con success, data, etc.

Ejemplo:

final status = await apn.getCertStatus();
debugPrint(status.toString());

getCertTypes #

  • Firma: Future<dynamic> getCertTypes()
  • Requiere: público (no requiere customerId).
  • Retorno: tipos de certificados disponibles (estructura según core).

Ejemplo:

final types = await apn.getCertTypes();

getRequerimentsByTypeUser #

  • Firma: Future<dynamic> getRequerimentsByTypeUser({ required int type })
  • Requiere: público.
  • Parámetros:
    • type (int): tipo de usuario.
  • Retorno: requisitos para el tipo de usuario.

Ejemplo:

final reqs = await apn.getRequerimentsByTypeUser(type: 1);

addSigner #

  • Firma: Future<dynamic> addSigner(dynamic signer)
  • Requiere: customerId.
  • Parámetros:
    • signer (Map): datos del firmante (estructura definida por tu backend).
  • Retorno: respuesta del core.

Ejemplo:

final res = await apn.addSigner({
  'name': 'Juan',
  'doc': '12345678',
});

getDocsByCustomer #

  • Firma: Future<dynamic> getDocsByCustomer({ required int page, required int size, int? status })
  • Requiere: customerId.
  • Parámetros:
    • page (int) > 0
    • size (int) > 0
    • status (int?) opcional
  • Retorno: documentos paginados del usuario.

Ejemplo:

final res = await apn.getDocsByCustomer(page: 1, size: 20, status: null);

signDocument #

  • Firma: Future<ApiResult<dynamic>> signDocument({ required Map<String, dynamic> signature, required String pin, bool enableBiometric = false })
  • Requiere: customerId, certificado y clave privada almacenados.
  • Parámetros:
    • signature (Map): incluye como mínimo:
      • id (String): id de la firma o del documento.
      • positions (List
      • opcionalmente document (String base64) si el flujo usa documento embebido.
    • pin (String): PIN del usuario para autorizar la firma.
    • enableBiometric (bool): si true y el usuario tiene biometría habilitada, solicitará autenticación biométrica.
  • Retorno: ApiResult con la respuesta del core.

Ejemplo:

final signature = {
  'id': 'signature-id',
  'positions': [{'page':1,'x':100,'y':200}],
};
final res = await apn.signDocument(signature: signature, pin: '1234');

startLivenessCheck #

  • Firma: Future<Map<String, dynamic>> startLivenessCheck()
  • Requiere: customerId.
  • Descripción: Crea una sesión de liveness (via core), abre un modal con un WebView interno (WebViewLiveness), y al completar valida con el backend. Cierra el modal automáticamente.
  • Retorno: Map con resultado normalizado (incluye success, data, etc.). Puede devolver error por timeout o cancelación.

Ejemplo:

final res = await apn.startLivenessCheck();
if (res['success'] == true) {
  // éxito
}

validateFaceLiveness #

  • Firma: Future<dynamic> validateFaceLiveness({ required String sessionId })
  • Requiere: customerId.
  • Parámetros:
    • sessionId (String): id de sesión creada previamente.
  • Retorno: respuesta del core.

Ejemplo:

final res = await apn.validateFaceLiveness(sessionId: 'SESSION_ID');

requestRevocation #

  • Firma: Future<dynamic> requestRevocation(int reasonCode)
  • Requiere: customerId.
  • Parámetros:
    • reasonCode (int): motivo de revocación.
  • Retorno: respuesta del core.

Ejemplo:

final res = await apn.requestRevocation(3);

getRevocationReasons #

  • Firma: Future<dynamic> getRevocationReasons()
  • Requiere: customerId.
  • Retorno: lista/mapa de motivos de revocación.

Ejemplo:

final res = await apn.getRevocationReasons();

createApacuanaUser #

  • Firma: Future<dynamic> createApacuanaUser(Map<String, dynamic> userData)
  • Requiere: público.
  • Parámetros:
    • userData (Map): campos del usuario. Mínimos típicos: kinddoc, doc, email, name, lastname, phone (según tu backend).
  • Retorno: respuesta del core.

Ejemplo:

final payload = {
  'kinddoc': 'V',
  'doc': '12345678',
  'email': 'usuario@correo.com',
  'name': 'Nombre',
  'lastname': 'Apellido',
  'phone': 4141234567,
};
final res = await apn.createApacuanaUser(payload);

uploadSignatureVariant #

  • Firma: Future<dynamic> uploadSignatureVariant({ required MultipartFile file })
  • Requiere: customerId.
  • Parámetros:
    • file (MultipartFile de dio): imagen de la firma.
  • Retorno: respuesta del core.

Ejemplo:

import 'package:dio/dio.dart';

final file = await MultipartFile.fromFile('/path/firmita.png', filename: 'firmita.png');
final res = await apn.uploadSignatureVariant(file: file);

getSignatureVariant #

  • Firma: Future<dynamic> getSignatureVariant()
  • Requiere: customerId.
  • Retorno: imagen/variant de firma del usuario (estructura según backend).

Ejemplo:

final res = await apn.getSignatureVariant();

deleteSignatureVariant #

  • Firma: Future<dynamic> deleteSignatureVariant()
  • Requiere: customerId.
  • Retorno: resultado de la eliminación.

Ejemplo:

final res = await apn.deleteSignatureVariant();

Tipos útiles (ApiResult, CertData, DocsQuery) #

El Notifier expone y utiliza modelos simples para empaquetar resultados:

class ApiResult<T> {
  final bool success;
  final String message;
  final T? data;
  final String? code;
  final dynamic error;
  // ...
}

class CertData {
  final String cert;
  final String certifiedId;
  // ...
}

class DocsQuery {
  final int page;
  final int size;
  final int? status;
  // ...
}
  • ApiResult<T>: respuesta segura para mostrar en UI (success, message, data, code, error).
  • CertData: payload específico de certificados.
  • DocsQuery: helper para consultas paginadas de documentos.

Permisos y configuración de plataforma #

Dependiendo de qué flujos uses, revisa:

Android (AndroidManifest.xml):

  • Cámara (liveness, si usa cámara), almacenamiento si usas FilePicker para pruebas.
  • Internet (WebViewLiveness).
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>

iOS (Info.plist):

  • Descripciones de uso:
<key>NSCameraUsageDescription</key>
<string>Usamos la cámara para verificar la vivacidad.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Se requiere acceso a la galería si subes una firma desde fotos.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Se requiere acceso a la galería si subes una firma desde fotos.</string>

WebView (si usas WebViewLiveness):

  • Asegúrate de tener el paquete de WebView requerido y configuración mínima según su documentación (p. ej., webview_flutter o el que utilice tu widget de liveness).

Biometría:

  • Si habilitas biometría, añade local_auth y configura permisos según su guía oficial.

Buenas prácticas y manejo de errores #

  • Inicializa el SDK desde el arranque de la app, antes de llamar métodos (revisa apn.status).
  • Usa try/catch. El core puede lanzar errores de tipo ApacuanaAPIError; el Notifier suele envolver resultados en ApiResult o normalizar a Map.
  • Protege datos sensibles:
    • Usa encryptionKey distinta en producción.
    • No loguees claves privadas ni certificados completos.
  • Biometría:
    • Ofrece fallback al PIN si el dispositivo no soporta biometría.
  • Modales del SDK:
    • ApacuanaProvider renderiza ApacuanaModal automáticamente cuando el Notifier lo requiere (p. ej., liveness). No necesitas gestionarlo manualmente.
  • Estados comunes:
    • NOT_INITIALIZED_ERROR: espera a que apn.status == ApacuanaServiceStatus.ready o corrige tu config.
    • Errores de red: revisa conectividad y apiUrl.

Ejemplo de app #

Revisa la carpeta example/ del repositorio (si está disponible) para una app que:

  • Inicializa el SDK con ApacuanaProvider.
  • Presenta botones para invocar cada método y muestra resultados en JSON.

Ejemplo mínimo de botón para generar certificado:

ElevatedButton(
  onPressed: () async {
    final res = await ApacuanaProvider.of(context).generateCert(pin: '1234');
    if (res.success) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Cert OK')),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error: ${res.message}')),
      );
    }
  },
  child: const Text('Generar certificado'),
)

Licencia #

Este proyecto se distribuye bajo la licencia MIT (ver archivo LICENSE en la raíz del paquete).

0
likes
0
points
85
downloads

Publisher

unverified uploader

Weekly Downloads

Apacuana SDK Core proporciona una interfaz para interactuar con los servicios de Apacuana.

License

unknown (license)

Dependencies

apacuana_sdk_core_dart, asn1lib, basic_utils, convert, crypto, dio, encrypt, flutter, flutter_secure_storage, local_auth, pointycastle, provider, webview_flutter

More

Packages that depend on apacuana_sdk_flutter