Origo SDK

Flutter plugin for Origo SDK integration, providing mobile key functionality for access control systems including endpoint setup, reader scanning, and lock management.

Features

  • Initialize Origo SDK with service codes and app credentials
  • Set up endpoints using 16-digit activation codes
  • Scan for and connect to nearby readers
  • Open the closest available reader
  • Update endpoint configurations
  • Debug logging and log retrieval
  • Cross-platform support (Android & iOS)

Installation

Add this to your package's pubspec.yaml file:

dependencies:
  origo_sdk: ^0.1.1

Then run:

flutter pub get

Platform Configuration

Android

Add the following permissions to your android/app/src/main/AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Required for Bluetooth communication -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    
    <!-- Required for Android 12+ Bluetooth permissions -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    
    <!-- Required for file operations (SDK versions ≤ 32) -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
    
    <!-- Required for notifications -->
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    
    <!-- Required for network operations -->
    <uses-permission android:name="android.permission.INTERNET"/>

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

Local Repository Setup (Required)

The Origo SDK uses a local Maven repository to distribute the native Android SDK. You must replicate this repository structure in your project to consume the SDK properly.

Step 1: Create the repository directory structure

Create the following directory structure in your Android project root (same level as your app folder):

your_flutter_project/ ├── android/ │ ├── app/ │ └── repo/ │ └── com/ │ └── example/ │ └── origo/ │ └── 3.4.0/ │ ├── origo-3.4.0.aar │ └── origo-3.4.0.pom

Step 2: Copy the required files

Copy the following files from the Origo SDK plugin to your project:

  1. AAR file: Copy origo-3.4.0.aar from the plugin's android/repo/com/example/origo/3.4.0/ directory to your android/repo/com/example/origo/3.4.0/ directory

  2. POM file: Copy origo-3.4.0.pom from the plugin's android/repo/com/example/origo/3.4.0/ directory to your android/repo/com/example/origo/3.4.0/ directory

iOS

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

<!-- Location permissions required by OrigoSDK -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app uses location services to detect nearby readers for secure access.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app uses location services to detect nearby readers for secure access, even when the app is in the background.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app uses location services to detect nearby readers for secure access, even when the app is in the background.</string>

<!-- Bluetooth permissions required by OrigoSDK -->
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app uses Bluetooth to communicate with secure readers.</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to communicate with secure readers.</string>

<!-- Background modes for location and Bluetooth -->
<key>UIBackgroundModes</key>
<array>
    <string>location</string>
    <string>bluetooth-central</string>
    <string>bluetooth-peripheral</string>
    <string>background-processing</string>
</array>

Usage

Basic Setup

import 'package:origo_sdk/origo_sdk.dart';
import 'package:flutter/services.dart';

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _origoSdk = OrigoSdk();
  bool _isInitialized = false;

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

  Future<void> _initializeSDK() async {
    try {
      final isInitialized = await _origoSdk.initialize(
        'YOUR_ORIGO_LOCK_SERVICE_CODE',
        'YOUR_ORIGO_APP_ID',
        'YOUR_ORIGO_APP_ID_DESCRIPTION',
      );
      
      setState(() {
        _isInitialized = isInitialized;
      });
      
      if (isInitialized) {
        // Perform application startup
        final startupResult = await _origoSdk.applicationStartup();
        print('Startup result: $startupResult');
      }
    } on PlatformException catch (e) {
      print('Failed to initialize SDK: ${e.message}');
    }
  }

  Future<void> _setupEndpoint() async {
    try {
      final result = await _origoSdk.endpointSetup('YOUR_16_DIGIT_CODE');
      print('Endpoint setup result: $result');
    } on PlatformException catch (e) {
      print('Failed to setup endpoint: ${e.message}');
    }
  }

  Future<void> _startScanning() async {
    try {
      final result = await _origoSdk.startScan();
      print('Scan started: $result');
    } on PlatformException catch (e) {
      print('Failed to start scan: ${e.message}');
    }
  }

  Future<void> _openClosestReader() async {
    try {
      final result = await _origoSdk.openClosestReader();
      print('Open reader result: $result');
    } on PlatformException catch (e) {
      print('Failed to open reader: ${e.message}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Origo SDK Example')),
        body: Padding(
          padding: EdgeInsets.all(16.0),
          child: Column(
            children: [
              Text('SDK Initialized: $_isInitialized'),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _isInitialized ? _setupEndpoint : null,
                child: Text('Setup Endpoint'),
              ),
              ElevatedButton(
                onPressed: _isInitialized ? _startScanning : null,
                child: Text('Start Scanning'),
              ),
              ElevatedButton(
                onPressed: _isInitialized ? _openClosestReader : null,
                child: Text('Open Closest Reader'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Available Methods

Core Methods

  • initialize(String origoLockServiceCode, String origoAppId, String origoAppIdDescription) - Initialize the SDK
  • applicationStartup() - Perform application startup sequence
  • getEndpointSetupStatus() - Get current endpoint setup status
  • endpointSetup(String sixteenDigitCode) - Setup endpoint with activation code
  • endpointUpdate() - Update endpoint configuration

Reader Operations

  • startScan() - Start scanning for nearby readers
  • stopScan() - Stop scanning for readers
  • openClosestReader() - Open the closest available reader

Debugging

  • toggleLogging() - Toggle debug logging on/off
  • getLogs() - Retrieve debug logs

## Permission Handling

⚠️ **Important**: The Origo SDK only checks if permissions are granted but does not request them. Your client application must handle permission requests before calling SDK methods that require them.

### Required Permissions

**Android:**
- `BLUETOOTH_SCAN` - Required for scanning nearby readers
- `BLUETOOTH_CONNECT` - Required for connecting to readers  
- `BLUETOOTH_ADVERTISE` - Required for advertising capabilities
- `ACCESS_FINE_LOCATION` or `ACCESS_COARSE_LOCATION` - Required for Bluetooth scanning on Android versions < 12

**iOS:**
- Bluetooth permissions - Required for reader communication
- Location permissions (when in use) - Required for reader detection

### Implementation

Use packages like `permission_handler` to request permissions before calling SDK methods:

```yaml
dependencies:
  permission_handler: ^11.3.1
  origo_sdk: ^0.1.1
import 'package:permission_handler.dart';

Future<void> _startScanning() async {
  // Request permissions before scanning
  Map<Permission, PermissionStatus> statuses = await [
    Permission.bluetoothScan,
    Permission.bluetoothConnect,
    Permission.bluetoothAdvertise,
    Permission.locationWhenInUse,
  ].request();

  bool allGranted = statuses.values.every(
    (status) => status == PermissionStatus.granted
  );

  if (!allGranted) {
    // Handle permission denial - guide user to settings if needed
    if (statuses.values.any((status) => status == PermissionStatus.permanentlyDenied)) {
      await openAppSettings();
    }
    return;
  }

  try {
    final result = await _origoSdk.startScan();
    print('Scan started: $result');
  } on PlatformException catch (e) {
    if (e.code == 'SCAN_ERROR' && e.message?.contains('permissions') == true) {
      // Permission was revoked, request again
      print('Permissions not granted: ${e.message}');
    }
  }
}

Error Handling

All methods may throw PlatformException. It's recommended to wrap calls in try-catch blocks:

try {
  final result = await _origoSdk.someMethod();
  // Handle success
} on PlatformException catch (e) {
  print('Error: ${e.message}');
  // Handle error
}

Requirements

  • Flutter >=3.3.0
  • Dart SDK >=3.6.0
  • Android API level 21+
  • iOS 11.0+

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

For issues and feature requests, please visit our GitHub repository.