fingerly_flutter is a plugin over the native iOS and Android SDKs. Collection happens in native code; Dart gets typed results.
Requirements
- Flutter 3.10 or newer, Dart 3.
- iOS 13 and Android 5.0 (API 21) or newer.
Install
flutter pub add fingerly_flutter
The iOS side supports both CocoaPods and Swift Package Manager.
Identify a device
import 'package:fingerly_flutter/fingerly.dart';
final fingerly = await Fingerly.load(apiKey: 'fly_pk_us_production_…');
Future<void> signIn(String email, String password) async {
final result = await fingerly.identify(tag: 'sign-in');
await api.signIn(email, password, requestId: result.requestId);
}
Send requestId to your backend with the action, and decide there after reading the stored event with a secret key. See server-side verification.
API
| Member | Returns | Notes |
|---|---|---|
Fingerly.load({required String apiKey, String endpoint = '', ConsentState consent = ConsentState.granted}) | Future<Fingerly> | An empty endpoint uses the region in the key. The consent state is shared by the whole app, so pass it on every load. |
setConsent(ConsentState state) | Future<void> | Changes the consent state. consent reads it. Until it is granted, identify and collect throw FingerlyConsentException. |
identify({String? tag, bool submit = true}) | Future<IdentifyResult> | suspectScore is int? and null when nothing was scored. |
collect() | Future<SignalReport> | Collects without submitting. |
Fingerly.nativeVersion() | Future<String> | The native SDK version. |
Verdicts
| Verdict | Platform | What it means |
|---|---|---|
instrumentation | Both | An instrumentation toolkit is attached to the app. |
mitm | Both | Something is intercepting the app's encrypted traffic. |
automation | Both | A debugger or a test runner is driving the app. |
tampering | Both | The app's code has been hooked or modified. |
farm | Both | The device looks mass-provisioned or freshly reset. |
jailbreak, simulator | iOS | Jailbroken device; iOS Simulator. |
root, emulator, appCloner | Android | Rooted device; emulator; cloning framework. |
if (result.verdicts.jailbreak.value &&
result.verdicts.jailbreak.confidence == Confidence.high) {
// add friction, and let your server make the final decision
}
Errors
try {
await fingerly.identify();
} on FingerlyException catch (error) {
if (error.status == 401) { /* the key is wrong */ }
if (error.status == 402) { /* the organization is not accepting traffic */ }
}