ShareRing Vault SDK for Flutter

ShareRing Vault SDK for Flutter

A comprehensive Flutter plugin for secure vault operations, supporting cryptographic functions, document management, and authentication.

Prerequisites

Before getting started, ensure you have the following installed:

  • Flutter SDK: Version 3.3.0 or higher
  • Dart SDK: Version 3.9.2 or higher
  • Android Studio with Android SDK (API Level 24+)
  • Xcode 14.0+ (for iOS development)
  • CocoaPods (for iOS dependency management)
  • Java Development Kit (JDK): Version 11 or higher

Verify your setup:

flutter doctor

Features

  • Secure cryptographic operations
  • Document management and handling
  • User authentication and vault access
  • HD wallet support (SECP256K1)
  • Merkle tree operations for data integrity
  • GraphQL API integration
  • Secure backup and restore functionality

Getting Started

This plugin provides platform-specific implementations for Android and iOS to enable ShareRing secure vault functionality in your Flutter application.

Installation

Add this to your pubspec.yaml:

dependencies:
  shr_vault_flutter:
    git:
      url: https://github.com/ShareRing/sharering-vaults-flutter.git

Then run:

flutter pub get

Android Configuration

1. Update build.gradle (Project-level)

Ensure your project-level android/build.gradle includes the required repositories and configurations:

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

subprojects {
    project.afterEvaluate {
        if (project.hasProperty("android")) {
            android {
                compileSdk = 36
            }
        }
    }
}

tasks.register('clean', Delete) {
    delete rootProject.buildDir
}

2. Update android/app/build.gradle.kts (App-level)

Configure your app-level build file to reference the NFC AAR files and add dependencies using flatDir repository:

repositories {
    flatDir {
        dirs rootProject.file("android/libs")
    }
}

android {
    namespace = "com.sharering.shr_vault_flutter_example"
    compileSdk = 36

    defaultConfig {
        minSdkVersion 24
        targetSdkVersion 36
        multiDexEnabled = true
    }

    buildTypes {
        release {
            signingConfig = signingConfigs.debug

            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }

    // Add this to resolve META-INF conflicts
    packaging {
        resources {
            excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
        }
    }
}

Add or verify these settings in android/gradle.properties:

android.useAndroidX=true
android.enableJetifier=true
org.gradle.jvmargs=-Xmx2048m

3. AndroidManifest.xml Configuration

Ensure your android/app/src/main/AndroidManifest.xml includes the necessary permissions:

<manifest>
    <!-- NFC Permissions -->
    <uses-permission android:name="android.permission.NFC" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
    <uses-permission android:name="android.permission.READ_CALENDAR" />

    <!-- NFC Feature Declaration -->
    <uses-feature
        android:name="android.hardware.nfc"
        android:required="false" />

    <application>
        <!-- Your configuration -->
    </application>
</manifest>

iOS Configuration

1. Prerequisites for iOS

  • Minimum iOS Version: 15.0
  • CocoaPods: Latest version
  • Xcode: 14.0 or later

2. Install CocoaPods Dependencies

Navigate to the iOS directory and install dependencies:

cd ios
pod repo update
pod install
cd ..

3. Update Podfile

Update your ios/Podfile with the proper configuration for NFC support and performance optimization:

platform :ios, '15.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

# ... other configuration ...

target 'Runner' do
  use_frameworks!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
  target 'RunnerTests' do
    inherit! :search_paths
  end
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)

    # Performance optimization and NFC configuration
    target.build_configurations.each do |config|
      # Enable optimization for Release builds
      if config.name == 'Release'
        config.build_settings['GCC_OPTIMIZATION_LEVEL'] = '3'
        config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-O'
      end

      # Exclude arm64 for simulator (fixes NFCPassportReader framework compatibility)
      config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'

      # NFC support
      config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
        '$(inherited)',
        'PERMISSION_NFC=1',
      ]
    end
  end
end

Key Configuration Points:

  • platform :ios, '15.0' ensures minimum iOS 15 compatibility
  • use_frameworks! is required for NFC framework integration
  • EXCLUDED_ARCHS[sdk=iphonesimulator*] = 'arm64' fixes simulator build issues
  • Release optimization settings improve performance
  • PERMISSION_NFC=1 enables NFC functionality

4. Info.plist Configuration

Add the following keys to your ios/Runner/Info.plist for NFC functionality:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <!-- NFC Configuration -->
    <key>NFCReaderUsageDescription</key>
    <string>This app uses NFC to securely read documents.</string>

    <key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
    <array>
        <string>00000000000000</string>
    </array>

    <!-- Camera for Document Capture -->
    <key>NSCameraUsageDescription</key>
    <string>Camera access is needed to capture documents.</string>

    <!-- Photo Library Access -->
    <key>NSPhotoLibraryUsageDescription</key>
    <string>Photo library access is needed to select documents.</string>

    <!-- Calendar Access (if needed) -->
    <key>NSCalendarsUsageDescription</key>
    <string>Calendar access is needed for document dates.</string>

    <!-- Other required keys -->
    <key>UIRequiredDeviceCapabilities</key>
    <array>
        <string>nfc</string>
    </array>
</dict>
</plist>

5. Add NFC Framework and Native Libraries

  1. Open ios/Runner.xcworkspace (NOT Runner.xcodeproj) in Xcode
  2. Select the Runner project
  3. Go to Build Phases > Link Binary With Libraries
  4. Verify that CoreNFC.framework is added (should be included by default)

6. Code Signing & Capabilities

For development on physical devices:

  1. Open ios/Runner.xcworkspace in Xcode
  2. Select the Runner project
  3. Go to Signing & Capabilities
  4. Select your team from the dropdown
  5. Update the Bundle Identifier (e.g., com.sharering.shrVaultExample)
  6. Click + Capability and add:
    • NFC Tag Reading: Required for NFC functionality
    • Keychain Sharing: For secure credential storage (if needed)

7. Troubleshooting iOS Setup

Error: “Pods directory not found”

cd ios
rm -rf Pods Podfile.lock
pod install
cd ..

Error: “CoreNFC not available”

  • Ensure Deployment Target is iOS 15.0 or higher
  • Verify NFC capability is added in Xcode

Build & Run

Initial Setup

# Clean previous builds
flutter clean

# Get dependencies
flutter pub get

# iOS only: Install CocoaPods dependencies
cd ios && pod install && cd ..

API Usage Guide

Authentication

Sign Up

Registers a new user and creates a vault account.

import 'package:shr_vault_flutter/shr_vault_flutter.dart';

// In your widget/screen
final UserInfo? user = await ShrVaultFlutter.signup(context);

if (user != null) {
  print('Signup successful!');
  print('Email: ${user.email}');
  print('Wallet Address: ${user.walletAddress}');
} else {
  print('Signup cancelled or failed');
}

Parameters:

  • context: BuildContext – The current context for showing the modal

Returns:

  • UserInfo? – User information if signup succeeds, null if cancelled

UserInfo Properties:

- email: String
- authToken: String
- walletAddress: String
- pubKey: String
- mnemonic: String (12-word recovery phrase)
- vctToken: String?
- dvctToken: String?
- biometricEnabled: String?
- tempPin: String?

Log In

Authenticates an existing user with their vault account using a recovery phrase.

final UserInfo? user = await ShrVaultFlutter.login(context);

if (user != null) {
  print('Login successful!');
  print('Welcome back: ${user.email}');
} else {
  print('Login cancelled');
}

Parameters:

  • context: BuildContext – The current context for showing the modal

Returns:

  • UserInfo? – User information if login succeeds, null if cancelled

Document Management

Add New Document

Navigates to document selection screen where users can choose and upload documents.

final bool success = await ShrVaultFlutter.gotoAddDoc(context);

if (success) {
  print('Document added successfully');
  // Refresh your document list
} else {
  print('Document addition cancelled');
}

Parameters:

  • context: BuildContext – The current context for navigation

Returns:

  • bool – True if document was added, false if cancelled

Supported Document Types:

  • ID Card (with/without NFC)
  • Passport (with/without NFC)
  • Driver’s License
  • Voter Card
  • Aadhaar (India)
  • PAN (India)
  • TIN Card
  • Resident Permit
  • Student ID Card

Get Document List

Fetches all documents with their current processing status.

final List<DocumentItem>? documents = await ShrVaultFlutter.getListDoc(context);

if (documents != null && documents.isNotEmpty) {
  for (var doc in documents) {
    print('${doc.type}: ${doc.fullName} (${doc.status})');
  }
} else {
  print('No documents found');
}

Parameters:

  • context: BuildContext – Required for internal operations

Returns:

  • List<DocumentItem>? – List of documents, null if error

DocumentItem Properties:

- documentId: String?
- document_id: String?
- type: String
- name: String
- subtitle: String
- status: String? (pending, processing, approved, declined, completed, blocked)
- hasDocument: bool
- archived: bool
- fullName: String?
- firstName: String?
- lastName: String?
- surname: String?
- number: String?
- dob: String?
- expiryDate: String?
- issuesDate: String?
- issuedDate: String?
- issuanceDate: String?
- documentPhotos: String? (JSON encoded)
- verificationLabel: String? (verified, checked)
- dvct: String? (Digital Verifiable Credential Token)
- docHash: String?
- address: String?
- placeOfBirth: String?
- gender: String?
- nationality: String?
- issuerAuthority: String?
- selfImage: String?
- category: String?
- document_type: String?
- issuing_country: String?
- metadata: String?
- lastUsedTime: String?
- verification: Map<String, dynamic>?
- attachments: List<AttachmentsDoc>?
- config: DocumentConfig?

DocumentConfig Properties:

- country: String (country code)
- document_name: String (display name of document type)
- etsiv2_ready: bool (supports ETSIv2 verification)
- nfc_processable: bool (supports NFC reading)

AttachmentsDoc Properties:

- source: String (e.g., 'cropped_face', 'document_front', 'document_back')
- mimetype: String (e.g., 'image/jpeg', 'image/png')
- data: String (base64 encoded image data)

Get Document Details

Retrieves detailed information for a specific document and checks its processing status.

final DocumentItem? document = await ShrVaultFlutter.getDetailDocById(
  documentId,
  context,
);

Status Flow & Behavior:

StatusBehaviorAction
processingShows “Document is being processed” message and returns nullUser waits for processing to complete
approvedReturns document and navigates to detail screenUser reviews document and must confirm to proceed
completedReturns full document detailsDocument is fully processed and approved
declinedReturns document with rejection detailsDocument verification failed, user can resubmit

Workflow:

  1. Call getDetailDocById() to fetch document
  2. If status is processing, shows loading message, returns null
  3. If status is approved, navigates to confirmation screen where user confirms
  4. After user confirms, status automatically changes to completed
  5. If status is completed, returns document, shows success state

Parameters:

  • documentId: String – The ID of the document to retrieve
  • context: BuildContext – For showing dialogs and navigation

Returns:

  • DocumentItem? – Document details, null if not found or still processing

Recovery Phrase

Get Recovery Phrase

Retrieves the user’s 12-word mnemonic recovery phrase. Requires PIN or biometric authentication.

try {
  final String? phrase = await ShrVaultFlutter.getPharse(context);
  if (phrase != null) {
    print('Recovery phrase retrieved');
    // Display securely to user
  }
} catch (e) {
  print('Error: $e'); // 'User need to login first'
}

Parameters:

  • context: BuildContext – For showing PIN dialog if biometric fails

Returns:

  • String? – The 12-word mnemonic phrase

Throws:

  • 'User need to login first' if no user is logged in or authentication fails

NFC Operations

Start NFC Reader

Initializes the NFC reader session. Call this before attempting to read an ID card.

await ShrVaultFlutter.startRead();

Behavior:

  • If NFC is disabled, automatically opens NFC settings (does not throw)
  • If NFC is not supported, logs debug message (does not throw)
  • Exceptions are handled internally

Check NFC Support

final bool supported = await ShrVaultFlutter.isSupported();
if (supported) {
  print('NFC is supported on this device');
}

Check NFC Enabled

final bool enabled = await ShrVaultFlutter.isEnabled();
if (!enabled) {
  print('NFC is disabled. Please enable it.');
}

Open NFC Settings

await ShrVaultFlutter.goToNfcSettings();

Read ID Card via NFC

try {
  final Map<String, dynamic> data = await ShrVaultFlutter.readIdCard(
    documentNumber: 'ABC123456',
    dateOfBirth: '901215',  // YYMMDD format
    dateOfExpiry: '301215', // YYMMDD format
  );
  print('NFC data: $data');
} on PlatformException catch (e) {
  if (e.code == 'NFC_DISABLED') {
    print('NFC is disabled');
  } else if (e.code == 'NFC_NOT_SUPPORTED') {
    print('NFC is not supported');
  }
}

Listen to NFC Events

ShrVaultFlutter.onNfcEvents().listen((event) {
  if (event is Map) {
    switch (event['status']) {
      case 'ready':
        print('NFC ready: ${event['message']}');
        break;
      case 'reading':
        print('Reading: ${event['message']}');
        break;
      case 'done':
        print('Complete: ${event['message']}');
        break;
      case 'error':
        print('Error: ${event['message']}');
        break;
    }
  }
});

Backup & Restore

Backup Vault

Exports encrypted backup file containing all vault data.

await ShrVaultFlutter.backupFile(context);

// File will be exported to device downloads/documents folder
print('Backup created successfully');

Parameters:

  • context: BuildContext – For showing file picker/dialogs

Returns:

  • dynamic – Returns false if user is not logged in or private key is unavailable

Backup Includes:

  • All documents and their metadata
  • User information
  • Encryption keys
  • Recovery data

Security:

  • Encrypted with user’s private key
  • Requires device authentication

Import Backup File

Restores vault data from a previously created backup file.

final bool success = await ShrVaultFlutter.importBackupFile(context);

if (success) {
  print('Backup imported successfully');
} else {
  print('Import failed or cancelled');
}

Parameters:

  • context: BuildContext – For file picker dialog

Returns:

  • Future<bool> – Returns true if import succeeds, false if cancelled or failed

Import Process:

  1. Select backup file from device
  2. Enter backup password
  3. Verify integrity
  4. Restore to local storage
  5. Sync with server

Requirements:

  • Valid backup file (.bak format)
  • Correct backup password
  • Internet connection for verification

Document Status Constants

The SDK uses the following document status values:

class DOCUMENT_STATUS {
  static const String pending = 'pending';
  static const String processing = 'processing';
  static const String approved = 'approved';
  static const String declined = 'declined';
  static const String completed = 'completed';
  static const String blocked = 'blocked';
}

Document Categories

class DOCUMENT_CATEGORY {
  static const String goverment = 'GOVERNMENT';
  static const String health = 'HEALTH';
  static const String other = 'OTHER';
  static const String customize = 'CUSTOMIZE';
}

Document Name Constants

class DOCUMENT_NAME {
  static const String id = 'ID Card';
  static const String dl = 'Driver License';
  static const String passport = 'Passport';
  static const String aadhaar = 'Aadhaar';
  static const String pan = 'PAN';
  static const String tin = 'TIN Card';
  static const String voterCard = 'Voter Card';
  static const String residentPermit = 'Resident Permit';
  static const String studentId = 'Student ID Card';
}

DID Prefixes

The SDK uses the following DID (Decentralized Identifier) prefixes:

const didVCTPrefix = 'did:shr';
const didDVCTPrefix = 'did:dvct';
const didSBTPrefix = 'did:sbt';

Example Usage

Complete Authentication Flow

import 'package:flutter/material.dart';
import 'package:shr_vault_flutter/shr_vault_flutter.dart';
import 'package:shr_vault_flutter/models/user/user.dart';

class WelcomeScreen extends StatefulWidget {
  @override
  State<WelcomeScreen> createState() => _WelcomeScreenState();
}

class _WelcomeScreenState extends State<WelcomeScreen> {
  Future<void> _handleSignup() async {
    final UserInfo? user = await ShrVaultFlutter.signup(context);
    if (user != null) {
      // Navigate to main app
      print('Signup successful: ${user.email}');
    }
  }

  Future<void> _handleLogin() async {
    final UserInfo? user = await ShrVaultFlutter.login(context);
    if (user != null) {
      // Navigate to main app
      print('Login successful: ${user.email}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          ElevatedButton(
            onPressed: _handleSignup,
            child: Text('Sign Up'),
          ),
          ElevatedButton(
            onPressed: _handleLogin,
            child: Text('Login with Recovery Phrase'),
          ),
        ],
      ),
    );
  }
}

Document Management Flow

import 'package:flutter/material.dart';
import 'package:shr_vault_flutter/shr_vault_flutter.dart';
import 'package:shr_vault_flutter/models/document/document_item.dart';

class VaultPage extends StatefulWidget {
  @override
  State<VaultPage> createState() => _VaultPageState();
}

class _VaultPageState extends State<VaultPage> {
  List<DocumentItem>? _documents;

  @override
  void initState() {
    super.initState();
    _loadDocuments();
  }

  Future<void> _loadDocuments() async {
    final docs = await ShrVaultFlutter.getListDoc(context);
    setState(() {
      _documents = docs;
    });
  }

  Future<void> _addDocument() async {
    final success = await ShrVaultFlutter.gotoAddDoc(context);
    if (success) {
      _loadDocuments(); // Refresh list
    }
  }

  Future<void> _viewDocument(String? documentId) async {
    if (documentId == null) return;
    await ShrVaultFlutter.getDetailDocById(documentId, context);
    _loadDocuments(); // Refresh in case status changed
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _documents == null
          ? Center(child: CircularProgressIndicator())
          : ListView.builder(
              itemCount: _documents!.length,
              itemBuilder: (context, index) {
                final doc = _documents![index];
                return ListTile(
                  title: Text(doc.name),
                  subtitle: Text('Status: ${doc.status}'),
                  onTap: () => _viewDocument(doc.document_id),
                );
              },
            ),
      floatingActionButton: FloatingActionButton(
        onPressed: _addDocument,
        child: Icon(Icons.add),
      ),
    );
  }
}

NFC Support by Country

The SDK supports NFC ID card reading for specific countries:

static const countrySupportNFCIDCard = ['BRB', 'VNM'];

For passports, NFC reading is available more broadly through the standard ICAO 9303 protocol.


Support

If you need assistance with the ShareRing Vault SDK for Flutter or have any questions about integration, please contact ShareRing support at hello@sharering.network or via the chat button on our website.