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.2
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:
-
AAR file: Copy
origo-3.4.0.aar
from the plugin'sandroid/repo/com/example/origo/3.4.0/
directory to yourandroid/repo/com/example/origo/3.4.0/
directory -
POM file: Copy
origo-3.4.0.pom
from the plugin'sandroid/repo/com/example/origo/3.4.0/
directory to yourandroid/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 SDKapplicationStartup()
- Perform application startup sequencegetEndpointSetupStatus()
- Get current endpoint setup statusendpointSetup(String sixteenDigitCode)
- Setup endpoint with activation codeendpointUpdate()
- Update endpoint configuration
Reader Operations
startScan()
- Start scanning for nearby readersstopScan()
- Stop scanning for readersopenClosestReader()
- Open the closest available reader
Debugging
toggleLogging()
- Toggle debug logging on/offgetLogs()
- 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 readersBLUETOOTH_CONNECT
- Required for connecting to readersBLUETOOTH_ADVERTISE
- Required for advertising capabilitiesACCESS_FINE_LOCATION
orACCESS_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:
dependencies:
permission_handler: ^11.3.1
origo_sdk: ^0.1.2
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.