diff --git a/README.md b/README.md index cdddbe1..cb84a90 100644 --- a/README.md +++ b/README.md @@ -89,15 +89,17 @@ class _MyAppState extends State { } ``` -You can also configure `region` and `endpoint` in the `initFpjs` method, like below. For the web platform, you can use an additional `scriptUrlPattern` property to specify a custom URL for loading the JavaScript agent. This is required for proxy integrations. +You can also configure `region`, `endpoint` and `endpointFallbacks` in the `initFpjs` method, like below. For the web platform, you can use an additional `scriptUrlPattern` and `scriptUrlPatternFallbacks` properties to specify a custom URL for loading the JavaScript agent. This is required for proxy integrations. ```dart void doInit() async { await FpjsProPlugin.initFpjs( '', endpoint: 'https://subdomain.domain.com', + endpointFallbacks: ['https://subdomain2.domain.com', 'https://subdomain3.domain.com'], region: Region.eu, // or Region.ap, Region.us // Only necessary for the web platform - scriptUrlPattern: 'https://your.domain/fp_js/script_path?apiKey=&version=&loaderVersion=' + scriptUrlPattern: 'https://your.domain/fp_js/script_path?apiKey=&version=&loaderVersion=', + scriptUrlPatternFallbacks: ['https://your.second-domain/fp_js/script_path?apiKey=&version=&loaderVersion='] ); } ``` diff --git a/android/build.gradle b/android/build.gradle index 76941fc..95ea45d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -53,5 +53,5 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "com.fingerprint.android:pro:2.4.0" + implementation "com.fingerprint.android:pro:2.5.0" } diff --git a/android/src/main/kotlin/com/fingerprintjs/flutter/fpjs_pro/fpjs_pro_plugin/FpjsProPlugin.kt b/android/src/main/kotlin/com/fingerprintjs/flutter/fpjs_pro/fpjs_pro_plugin/FpjsProPlugin.kt index 1dd55bc..5aaaa36 100644 --- a/android/src/main/kotlin/com/fingerprintjs/flutter/fpjs_pro/fpjs_pro_plugin/FpjsProPlugin.kt +++ b/android/src/main/kotlin/com/fingerprintjs/flutter/fpjs_pro/fpjs_pro_plugin/FpjsProPlugin.kt @@ -59,11 +59,12 @@ class FpjsProPlugin: FlutterPlugin, MethodCallHandler { val regionString = call.argument("region") val endpoint = call.argument("endpoint") + val endpointFallbacks = call.argument?>("endpointFallbacks") val region = regionString?.let { parseRegion(it) } val extendedResponseFormat = call.argument("extendedResponseFormat") ?: false val pluginVersion = call.argument("pluginVersion") ?: "unknown" - initFpjs(token, region, endpoint, extendedResponseFormat, pluginVersion) + initFpjs(token, region, endpoint, endpointFallbacks, extendedResponseFormat, pluginVersion) result.success("Successfully initialized FingerprintJS Pro Client") } GET_VISITOR_ID -> { @@ -94,13 +95,14 @@ class FpjsProPlugin: FlutterPlugin, MethodCallHandler { channel.setMethodCallHandler(null) } - private fun initFpjs(apiToken: String, region: Configuration.Region?, endpoint: String?, extendedResponseFormat: Boolean, pluginVersion: String) { + private fun initFpjs(apiToken: String, region: Configuration.Region?, endpoint: String?, endpointFallbacks:List?, extendedResponseFormat: Boolean, pluginVersion: String) { val factory = FingerprintJSFactory(applicationContext) val configuration = Configuration( apiToken, region ?: Configuration.Region.US, endpoint ?: region?.endpointUrl ?: Configuration.Region.US.endpointUrl, extendedResponseFormat, + endpointFallbacks ?: emptyList(), listOf(Pair("fingerprintjs-pro-flutter", pluginVersion)) ) @@ -171,4 +173,4 @@ private fun getErrorCode(error: Error): String { else -> "UnknownError" } return errorType -} \ No newline at end of file +} diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 53f76a2..1d44918 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,8 +1,8 @@ PODS: - - FingerprintPro (2.4.0) + - FingerprintPro (2.6.0) - Flutter (1.0.0) - - fpjs_pro_plugin (2.1.1): - - FingerprintPro (~> 2.4.0) + - fpjs_pro_plugin (3.0.1): + - FingerprintPro (~> 2.6.0) - Flutter DEPENDENCIES: @@ -20,10 +20,10 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/fpjs_pro_plugin/ios" SPEC CHECKSUMS: - FingerprintPro: 550396e390f81754a6ca13991131ea28952c4e48 + FingerprintPro: 3f06f491c77d871ab543b49fd25fddc52dc34f8c Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - fpjs_pro_plugin: eca9d74d04a70d6ac1549d81fdae224940279c3a + fpjs_pro_plugin: 83f30abadcd58450a80c6ef5837f5e914d7ce238 PODFILE CHECKSUM: 2f1a6d2470f392e010cfe7ae5f9f694d8487db82 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/example/lib/main.dart b/example/lib/main.dart index fd1341c..107168f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:convert'; import 'package:env_flutter/env_flutter.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:fpjs_pro_plugin/error.dart'; import 'package:fpjs_pro_plugin/fpjs_pro_plugin.dart'; @@ -39,7 +38,7 @@ class _MyAppState extends State { dotenv.env['PROXY_INTEGRATION_PATH'] ?? 'no_proxy_integration'; final String _proxyIntegrationRequestPath = dotenv.env['PROXY_INTEGRATION_REQUEST_PATH'] ?? 'no_proxy_integration'; - final String? _proxyIntegrationScriptPath = + final String _proxyIntegrationScriptPath = dotenv.env['PROXY_INTEGRATION_SCRIPT_PATH'] ?? 'no_proxy_integration'; final String _region = dotenv.env['REGION'] ?? 'us'; @@ -133,8 +132,8 @@ class _MyAppState extends State { linkedId: 'checkDataWithTag', tags: tags), ]; - for (var _check in checks) { - await _check(); + for (var check in checks) { + await check(); setState(() { _checksResult += '.'; }); @@ -176,28 +175,37 @@ class _ExtendedResultDialog extends StatelessWidget { const _ExtendedResultDialog({Key? key, required this.handleIdentificate}) : super(key: key); - final AsyncCallback handleIdentificate; + final Future Function() handleIdentificate; @override Widget build(BuildContext context) { return ElevatedButton( - onPressed: () => { - handleIdentificate().then((identificationInfo) => showDialog( - context: context, - builder: (BuildContext context) => AlertDialog( - title: const Text('Extended result'), - content: FittedBox( - fit: BoxFit.contain, - child: Text(identificationInfo as String), - ), - actions: [ - ElevatedButton( - onPressed: () => Navigator.pop(context, 'OK'), - child: const Text('OK'), - ), - ], + onPressed: () async { + final resultContext = context; + String identificationInfo; + try { + identificationInfo = await handleIdentificate(); + } catch (e) { + identificationInfo = 'Identification error: $e'; + } + if (resultContext.mounted) { + showDialog( + context: resultContext, + builder: (BuildContext context) => AlertDialog( + title: const Text('Extended result'), + content: FittedBox( + fit: BoxFit.contain, + child: Text(identificationInfo), ), - )) + actions: [ + ElevatedButton( + onPressed: () => Navigator.pop(context, 'OK'), + child: const Text('OK'), + ), + ], + ), + ); + } }, child: const Text('Identify with extended result!'), ); diff --git a/ios/Classes/SwiftFpjsProPlugin.swift b/ios/Classes/SwiftFpjsProPlugin.swift index 78209a5..2350ba0 100644 --- a/ios/Classes/SwiftFpjsProPlugin.swift +++ b/ios/Classes/SwiftFpjsProPlugin.swift @@ -16,10 +16,10 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin { result(FlutterError(code: "missingArguments", message: "Missing or invalid arguments", details: nil)) return } - + if (call.method == "init") { if let token = args["apiToken"] as? String { - let region = parseRegion(passedRegion: args["region"] as? String, endpoint: args["endpoint"] as? String) + let region = parseRegion(passedRegion: args["region"] as? String, endpoint: args["endpoint"] as? String, endpointFallbacks: args["endpointFallbacks"] as? [String] ?? []) let extendedResponseFormat = args["extendedResponseFormat"] as? Bool ?? false let pluginVersion = args["pluginVersion"] as? String ?? "unknown" @@ -36,7 +36,7 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin { getVisitorData(metadata, result) } } - + private func prepareMetadata(_ linkedId: String?, tags: Any?) -> Metadata { var metadata = Metadata(linkedId: linkedId) guard @@ -45,7 +45,7 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin { else { return metadata } - + if let dict = jsonTags as? [String: JSONTypeConvertible] { dict.forEach { key, jsonType in metadata.setTag(jsonType, forKey: key) @@ -56,7 +56,7 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin { return metadata } - private func parseRegion(passedRegion: String?, endpoint: String?) -> Region { + private func parseRegion(passedRegion: String?, endpoint: String?, endpointFallbacks: [String]) -> Region { var region: Region switch passedRegion { case "eu": @@ -68,7 +68,7 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin { } if let endpointString = endpoint { - region = .custom(domain: endpointString) + region = .custom(domain: endpointString, fallback: endpointFallbacks) } return region @@ -84,7 +84,7 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin { result(FlutterError.init(code: "undefinedFpClient", message: "You need to call init method first", details: nil)) return } - + client.getVisitorId(metadata) { visitorIdResult in switch visitorIdResult { case .success(let visitorId): @@ -94,13 +94,13 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin { } } } - + private func getVisitorData(_ metadata: Metadata?, _ result: @escaping FlutterResult) { guard let client = fpjsClient else { result(FlutterError(code: "undefinedFpClient", message: "You need to call init method first", details: nil)) return } - + client.getVisitorIdResponse(metadata) { visitorIdResponseResult in switch visitorIdResponseResult { case .success(let visitorDataResponse): @@ -114,7 +114,7 @@ public class SwiftFpjsProPlugin: NSObject, FlutterPlugin { } } } - + private func processNativeLibraryError(_ error: FPJSError, result: @escaping FlutterResult) { let (code, description) = error.flutterFields result(FlutterError(code: code, message: description, details: nil)) diff --git a/ios/fpjs_pro_plugin.podspec b/ios/fpjs_pro_plugin.podspec index 9f75e4d..3fdf09f 100644 --- a/ios/fpjs_pro_plugin.podspec +++ b/ios/fpjs_pro_plugin.podspec @@ -15,7 +15,7 @@ Flutter plugin for FingerprintJS Pro. s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' - s.dependency 'FingerprintPro', '~> 2.4.0' + s.dependency 'FingerprintPro', '~> 2.6.0' s.platform = :ios, '13.0' diff --git a/lib/fpjs_pro_plugin.dart b/lib/fpjs_pro_plugin.dart index 040afee..730fd35 100644 --- a/lib/fpjs_pro_plugin.dart +++ b/lib/fpjs_pro_plugin.dart @@ -24,13 +24,17 @@ class FpjsProPlugin { /// Throws a [PlatformException] if [apiKey] is missing static Future initFpjs(String apiKey, {String? endpoint, + List? endpointFallbacks, String? scriptUrlPattern, + List? scriptUrlPatternFallbacks, Region? region, bool extendedResponseFormat = false}) async { await _channel.invokeMethod('init', { 'apiToken': apiKey, 'endpoint': endpoint, + 'endpointFallbacks': endpointFallbacks, 'scriptUrlPattern': scriptUrlPattern, + 'scriptUrlPatternFallbacks': scriptUrlPatternFallbacks, 'region': region?.stringValue, 'extendedResponseFormat': extendedResponseFormat, 'pluginVersion': pluginVersion, diff --git a/lib/fpjs_pro_plugin_web.dart b/lib/fpjs_pro_plugin_web.dart index 06bb494..6caa305 100644 --- a/lib/fpjs_pro_plugin_web.dart +++ b/lib/fpjs_pro_plugin_web.dart @@ -69,10 +69,16 @@ class FpjsProPluginWeb { options.region = call.arguments['region']; } if (call.arguments['endpoint'] != null) { - options.endpoint = call.arguments['endpoint']; + options.endpoint = [ + call.arguments['endpoint'], + ...(call.arguments['endpointFallbacks'] ?? []) + ]; } if (call.arguments['scriptUrlPattern'] != null) { - options.scriptUrlPattern = call.arguments['scriptUrlPattern']; + options.scriptUrlPattern = [ + call.arguments['scriptUrlPattern'], + ...(call.arguments['scriptUrlPatternFallbacks'] ?? []) + ]; } try { _fpPromise = promiseToFuture(FingerprintJS.load(options)); diff --git a/lib/js_agent_interop.dart b/lib/js_agent_interop.dart index 923fecd..692b8f9 100644 --- a/lib/js_agent_interop.dart +++ b/lib/js_agent_interop.dart @@ -211,8 +211,8 @@ class FingerprintJSOptions { external set region(String? region); /// Your custom API endpoint for getting visitor data. - external String? get endpoint; - external set endpoint(String? endpoint); + external List? get endpoint; + external set endpoint(List? endpoint); /// A JS agent script URL pattern. /// @@ -220,8 +220,8 @@ class FingerprintJSOptions { /// - — the major version of JS agent; /// - — the public key set via the `apiKey` option; /// - — the version of this package; - external String? get scriptUrlPattern; - external set scriptUrlPattern(String? scriptUrlPattern); + external List? get scriptUrlPattern; + external set scriptUrlPattern(List? scriptUrlPattern); external factory FingerprintJSOptions( {String apiKey, List integrationInfo});