Basic Usage of the Reclaim Protocol Flutter SDK
This guide will walk you through the fundamental steps to integrate Reclaim's proof verification system into your Flutter application.
Prerequisites
Before you begin, ensure you have:
- Installed the SDK (see Installation Guide)
- Your Application ID, Application Secret and Provider ID from the Reclaim Developer Portal (opens in a new tab)
Keep your Application Secret secure and never expose it in client-side code.
Step-by-Step Guide
1. Import the SDK
First, import the necessary components from the SDK in your Dart file:
import 'package:flutter/material.dart';
import 'package:reclaim_sdk/reclaim.dart';
import 'package:reclaim_sdk/utils/interfaces.dart';
import 'package:reclaim_sdk/utils/types.dart';
import 'package:url_launcher/url_launcher.dart';
2. Initialize the SDK
Set up your credentials and initialize the SDK:
Future<ReclaimProofRequest> _initializeProofRequest() async {
final reclaimProofRequest = await ReclaimProofRequest.init(
"YOUR_APP_ID", // Replace with your actual Application ID
"YOUR_APP_SECRET", // Replace with your actual Application Secret
"YOUR_PROVIDER_ID", // Replace with your actual Provider ID
);
return reclaimProofRequest;
}
Replace 'YOUR_APP_ID', 'YOUR_APP_SECRET', and 'YOUR_PROVIDER_ID' with your actual credentials.
3. Generate a Request URL
Request URL is the URL that users will visit to initiate the proof request process. It redirects the user to the app clip or instant app flow for Reclaim Verifier App. You can generate it using the following method:
Future<String> _generateRequestUrl(ReclaimProofRequest request) async {
final requestUrl = await request.getRequestUrl();
print('Request URL: $requestUrl');
return requestUrl;
}
4. Launch the URL
We recommend using the url_launcher
package to open the request URL. Ensure you have added the url_launcher
package to your pubspec.yaml
file:
dependencies:
url_launcher: ^6.0.20
We use this method to open the request URL in an external browser. User is navigated to the Request URL from your app.
Future<void> _launchUrl(String url) async {
if (await canLaunchUrl(Uri.parse(url))) {
final launched = await launchUrl(
Uri.parse(url),
mode: LaunchMode.externalApplication,
);
if (launched) {
setState(() => _status = 'Session started. Waiting for proof...');
} else {
throw 'Could not launch $url';
}
} else {
throw 'Could not launch $url';
}
}
5. Start the Verification Session
Begin listening for proofs:
Future<void> _startVerificationSession(ReclaimProofRequest request) async {
await request.startSession(
onSuccess: _handleProofSuccess,
onError: _handleProofError,
);
}
void _handleProofSuccess(dynamic proof) {
print('Proof received: $proof');
// check if proof is of type String
var proofDataValue = '';
if (proof is String) {
// For custom callback URL, the proof is a just a string message suggesting the proof is successfully sent and the user should check their backend for the proof
proofDataValue = proof;
} else {
proofDataValue =
'Extracted data: ${proof.claimData.context}\n\nFull proof: ${proof.toString()}';
}
setState(() {
_status = 'Proof received!';
_proofData = proofDataValue;
});
}
void _handleProofError(Exception error) {
_handleError('Error in proof generation', error);
}
For detailed information about the proof
object, refer to the Advance Configuration section.
Complete Basic Example
Here's a full example putting all the steps together in a Flutter widget:
import 'package:flutter/material.dart';
import 'package:reclaim_sdk/reclaim.dart';
import 'package:reclaim_sdk/utils/interfaces.dart';
import 'package:url_launcher/url_launcher.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MaterialApp(home: ReclaimExample()));
}
class ReclaimExample extends StatefulWidget {
@override
_ReclaimExampleState createState() => _ReclaimExampleState();
}
class _ReclaimExampleState extends State<ReclaimExample> {
String _status = '';
String _proofData = '';
Future<void> _startVerificationSession(ReclaimProofRequest request) async {
await request.startSession(
onSuccess: _handleProofSuccess,
onError: _handleProofError,
);
}
void _handleProofSuccess(dynamic proof) {
print('Proof received: $proof');
// check if proof is of type String
var proofDataValue = '';
if (proof is String) {
// For custom callback URL, the proof is a just a string message suggesting the proof is successfully sent and the user should check their backend for the proof
proofDataValue = proof;
} else {
proofDataValue =
'Extracted data: ${proof.claimData.context}\n\nFull proof: ${proof.toString()}';
}
setState(() {
_status = 'Proof received!';
_proofData = proofDataValue;
});
}
void _handleProofError(Exception error) {
_handleError('Error in proof generation', error);
}
void _handleError(String message, dynamic error) {
print('$message: $error');
setState(() => _status = '$message: ${error.toString()}');
}
Future<ReclaimProofRequest> _initializeProofRequest() async {
final reclaimProofRequest = await ReclaimProofRequest.init(
"YOUR_APP_ID", // Replace with your actual Application ID
"YOUR_APP_SECRET", // Replace with your actual Application Secret
"YOUR_PROVIDER_ID", // Replace with your actual Provider ID
);
return reclaimProofRequest;
}
Future<String> _generateRequestUrl(ReclaimProofRequest request) async {
final requestUrl = await request.getRequestUrl();
print('Request URL: $requestUrl');
return requestUrl;
}
Future<void> _launchUrl(String url) async {
if (await canLaunchUrl(Uri.parse(url))) {
final launched = await launchUrl(
Uri.parse(url),
mode: LaunchMode.externalApplication,
);
if (launched) {
setState(() => _status = 'Session started. Waiting for proof...');
} else {
throw 'Could not launch $url';
}
}
}
Future<void> startReclaimSession() async {
try {
print('Starting Reclaim session');
final reclaimProofRequest = await _initializeProofRequest();
final requestUrl = await _generateRequestUrl(reclaimProofRequest);
await _launchUrl(requestUrl);
await _startVerificationSession(reclaimProofRequest);
} catch (error) {
_handleError('Error starting Reclaim session', error);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Reclaim SDK Demo')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ElevatedButton(
onPressed: startReclaimSession,
child: const Text('Start Reclaim Session'),
),
const SizedBox(height: 20),
Text(_status, style: const TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 20),
if (_proofData.isNotEmpty)
Expanded(
child: SingleChildScrollView(
child: Text(_proofData),
),
),
],
),
),
);
}
}
🚨 Safety First! 🚨
For real-world apps, don't put sensitive info like APP_SECRET in your frontend code. It's not safe!
Instead, do this:
- Store sensitive info like APP_SECRET on your backend
- Get the ReclaimProofRequestConfig from your backend
- Use
fromJsonString(reclaimProofRequestConfig)
on the frontend to get the reclaimProofRequest object and then generate the request URL.
This keeps your application secure and your secrets... well, secret! 🔒
Check out the Fullstack Example to see how to do this.
How It Works
- We initialize the SDK with your app credentials.
- We generate a request URL for the verification process.
- When the user presses the button, it opens the request URL.
- The SDK listens for the verification result and updates the status.
Next Steps
- Learn about Advanced Configuration options to customize the SDK for your specific needs.
- Review Best Practices for optimizing your Reclaim integration.
This example demonstrates a basic implementation. In a real application, you'd need to handle errors more robustly, manage state more efficiently, and integrate this flow into your broader application logic.
If you have any questions, don't hesitate to join our Telegram community (opens in a new tab) for support.
Happy coding with Reclaim Protocol in Flutter!