deepidsdk_flutter 2.4.0 copy "deepidsdk_flutter: ^2.4.0" to clipboard
deepidsdk_flutter: ^2.4.0 copied to clipboard

Flutter plugin for the DeepID SDK (Android + iOS). Device enrollment, SIM binding, on-demand posture attestation, and device fraud detection.

2.4.0 #

Breaking for integrators — you no longer place native binaries anywhere. Both SDKs are now downloaded by your build and pinned to the versions this plugin was built against. iOS needs no setup at all. Android needs a read:packages token in ~/.gradle/gradle.properties (gpr.user / gpr.key) instead of a file — README → Installation has the setup; contact DeepID for a token. Delete any deepidsdk.aar or DeepIdSDK.xcframework you previously placed in the pub cache.

Changed (iOS): the xcframework is downloaded and checksum-verified during pod install. The podspec fetches it from the public deepidsdk-ios-binary repo, pinned by version and SHA-256 in the plugin's natives.json, and caches it in ~/Library/Caches/com.deepidsdk.ios/ so it downloads once per version per machine rather than once per project. No credentials are involved: the framework is inert without the appKey / appSecret the backend verifies.

This closes the last silent-drift path in the plugin. An out-of-band xcframework had no version pin anywhere in the package — an older one still compiled, it just lacked that release's iOS fixes, with no warning at build or runtime. A mismatched pair is now unrepresentable on both platforms.

Changed: native SDK versions moved to natives.json. One file at the package root pins both platforms; ios/deepidsdk_flutter.podspec reads it with Ruby's JSON and android/build.gradle with Groovy's JsonSlurper, so a version bump is a single edit rather than two that can disagree.

Changed (Android): the SDK is resolved from GitHub Packages instead of a vendored AAR. android/build.gradle now declares com.deepidsdk:deepidsdk-android as an ordinary Maven dependency, pinned to the version this plugin was built against. android/libs/ and the generated android/local-maven/ tree are gone, along with the copy-at-configuration-time step that populated them.

This makes the plugin↔SDK pairing checkable. Previously the AAR was a file with no version in its name, so nothing in git recorded which SDK a given plugin revision expected, and a mismatch surfaced as an unresolved-reference error at a customer's build. The version is now pinned in a tracked file and upgrades with the plugin. Override it for a pre-release check with -PdeepidSdkVersion=x.y.z or DEEPID_SDK_VERSION.

Fixed (Android): the plugin no longer restates the SDK's dependency versions. Room, sqlite, okhttp, gson, security-crypto, play-integrity, play-services-appset, appcompat, material and core-ktx were declared in android/build.gradle and had to be kept in lockstep with the SDK's own build by hand — the hand-written POM the old local-Maven step generated declared no dependencies at all. A stale entry did not fail the build; it threw AbstractMethodError at runtime once Room's generated _Impl signatures shifted. The published POM now supplies all of them at the versions the SDK was compiled against, and the plugin declares only what its own Kotlin compiles against.

Added (Android): configuration-time credential check. A build with no usable credentials stops immediately with a message naming the setup step, instead of failing later with a bare 401 from the registry. GITHUB_USERNAME / GITHUB_TOKEN and GH_USERNAME / GH_TOKEN are accepted as well, as Gradle properties or environment variables, for CI. Apps that set RepositoriesMode.FAIL_ON_PROJECT_REPOS must declare DeepID's repository in their own settings.gradle; the README carries the block.

2.3.0 #

Requires the native binaries built for 2.3.0. The Android bridge calls into a SIM-binding API that older AARs do not have, so pairing this release with an older deepidsdk.aar fails the build with an unresolved-reference error naming a DeepID class. An older DeepIdSDK.xcframework still compiles, but every iOS fix below is simply absent from it. Replace both binaries when you upgrade.

Fix (Android): leaving the app mid-binding now rejects the binding on every device. Rejection previously rode entirely on onUserLeaveHint, which several OEM launcher and gesture-navigation stacks (observed on ColorOS) never deliver for Recents or a quick app switch — a customer could hop through another app and come back with the binding still alive. The hint remains the instant tier; a process-level lifecycle backstop now rejects whenever the app actually leaves the foreground, however it got there. Same-process interruptions — permission dialogs, the notification shade, OEM SMS-confirmation dialogs, incoming-call banners, and the SMS-charge notification the UPI rules exempt from "toggling" — cannot trip it. Entering split-screen, where neither signal fires, now rejects on entry.

Fix (iOS): switching away mid-binding now rejects the binding immediately on every device. The previous five-second grace was a scheduled work item, which froze the moment iOS suspended the process; whether the rejection ever fired depended on how long each device kept the backgrounded app runnable, and then on a race against the cancel-on-return path. The rejection now runs synchronously inside the didEnterBackground handler, before suspension can interfere. The deliberate trip to the Messages app on the URL-scheme fallback remains exempt, and the five-second composer-handoff rule is unchanged — those two are the NPCI behaviours; the grace period never was one. A late composer callback or a foreground return can no longer revive a flow that already ended.

Changed (iOS): a background rejection is now reported as DeepIdErrorCode.bindingAbandoned, matching Android. It previously surfaced as userCancelled, which misfiled an abandonment as a deliberate dismissal.

Fix (iOS): a binding rejected while the SMS composer was open left the composer standing. The verification SMS is composed in a system sheet inside the app, so leaving the app mid-compose now rejects the binding — but the composer stayed on screen, putting the customer back in front of a live compose sheet still holding the verification token for a binding the SDK had already refused. One tap on Send and the backend would see a token the host was told to treat as abandoned. Any terminal result now takes the composer down with it, matching Android, where rejecting finishes the whole Activity.

Fix (iOS): SIM binding text was invisible on devices in Dark Mode. Screen titles, the confirmation description and the countdown timer were drawn in .primary — an adaptive colour that resolves to white — on a sheet whose background is a fixed light card, so on a device set to Dark Mode they disappeared while the hardcoded-dark body text stayed readable. The sheet reported as "UI elements not showing" was fully rendered and functional; it was white-on-white. The themed text colours are now fixed, and the SDK pins its own view subtree to the light colour scheme so untinted system elements resolve against the card rather than the device appearance. Nothing changes in Light Mode. A host that themes cardBackground dark must theme the text colours to match.

Fix (iOS): the confirm step could render "Make sure is selected as a default SIM…" with a hole where the SIM name belongs, whenever CoreTelephony reported no provider (common on eSIM-only devices) and no phoneNumber was passed. That case now uses a complete standalone sentence.

New (Android): the UPI 'SMS sent check', with an onSmsSentCheck callback. After the platform's sentIntent confirms the verification SMS left the radio, the SDK now reads the device's sent SMS box and validates a record addressed to the verification number carrying the verification content — the guideline's assurance that a binding cannot be granted on a token that was never sent from the device the app is installed on. When the check runs and finds no matching record, the binding fails. When it cannot run — READ_SMS not granted, an unreadable provider — the flow proceeds, because an unreadable sent box is not evidence the SMS was not sent; the result says why so hosts can enforce a stricter policy themselves. Either way the outcome is delivered mid-flow to the new optional onSmsSentCheck parameter of startSimBinding() as an [SmsSentCheckResult]. The AAR manifest now declares READ_SMS (same permission group as SEND_SMS, so the existing SMS consent dialog covers it); iOS never delivers this callback since iOS offers no read access to the SMS store. AAR coordinate bumped to com.deepidsdk:deepidsdk:1.3.0.

2.2.0 #

New: on-demand posture attestation. verifySecurityPolicy() re-measures the device immediately before a critical operation and returns a server-issued reference your backend redeems.

final result = await DeepId.verifySecurityPolicy(
  action: 'payment.initiate',
  reference: orderId,
);

switch (result) {
  case Allowed(:final attestationId):
    await myBackend.pay(orderId, attestation: attestationId); // backend verifies
  case Blocked(:final displayMessage):
    showError(displayMessage);
  case Challenge(:final attestationId):
    await startStepUp(attestationId);
  case Unavailable():
    showError('Could not verify device security.');            // do NOT proceed
}

The problem it solves: enrollment establishes posture once, at app start, and everything after that trusts a measurement that may be days old. The attack is specific — the user logs in on a clean device, passes every check, and then the attacker attaches a hooking framework. Nothing in the previous design re-measured before the operation that actually matters.

⚠️ What this returns is advisory. It is not the security boundary. On a compromised device, a branch that reads Allowed and proceeds is a branch the attacker patches. Allowed.attestationId is the part that cannot be forged: send it to your backend and redeem it against POST /api/biz/attestations/verify before honouring the operation. An integration that acts only on the local return value has bought nothing.

AttestationResult is a sealed hierarchy, so switch is exhaustive and Unavailable — the case most likely to be skipped — cannot be omitted silently. It is also a normal result rather than a thrown exception, deliberately: an exception lands in the catch you wrote for connectivity, and that is how fail-open paths get written by accident. For any operation NPCI considers critical, treat Unavailable exactly as Blocked.

Also new:

  • prewarmAttestation(action:) — fetches the challenge on screen entry so the attestation at button press costs one round trip instead of two. Only the challenge is pre-fetched; posture is always measured at call time.
  • isAttestationSupported — the native binaries are dropped in out-of-band and can be older than this plugin. Requires deepidsdk 2.2.0+ (Android) and DeepIdSDK.xcframework 2.2.0+ (iOS).

Enforcement differs by platform, and it is not symmetric. Android presents a blocking alert for block and a dismissible one for warn. iOS has no policy-enforcement layer, so it reports policyAction and does nothing. Neither platform terminates the process for close. If your response to a compromised device matters, implement it from Blocked rather than relying on the configured action.

New: the /api/sdk/sim-binding/init response is delivered to Flutter mid-flow. startSimBinding() takes an optional onSimBindingInit callback that fires as soon as the init call resolves — before the verification SMS is sent, and long before the returned Future completes.

final result = await DeepId.startSimBinding(
  phoneNumber: '+919876543210',
  onSimBindingInit: (init) {
    if (init.ok != true) print('Init rejected (${init.clientId}): ${init.error}');
  },
);

The new SimBindingInitResponse carries all eight server fields: ok, clientId, bindingHash, smsTargetMobile, smsContent, instructions, error, message.

clientId (e.g. sim_binding_hRXbkIMrSsQpUmwciUpm) is the backend's identifier for the attempt. It is present whenever the server answered — including most rejections — and unlike bindingHash it carries no secret, so it is the field to log, surface on a support screen, or quote to DeepID when reporting a failed binding.

Called for every outcome, so there is one branch to handle: the server's response verbatim when there is one (accepted or rejected), and a synthesized ok: false carrying the reason in error when the call never reached the server. Previously a rejected init surfaced only as a flattened string on the thrown DeepIdException, with the server's own error / message / instructions discarded — on iOS at two separate layers.

Delivered once per init attempt, not once per binding flow. A flow normally makes exactly one, but both platforms can start a second — Android after a retry or an invalidated token, iOS if the user double-taps confirm — and each attempt gets its own clientId and bindingHash. The callback is dropped when the Future settles so it cannot fire into a later flow.

⚠️ bindingHash and smsContent are the live verification token the SDK is about to send from the bound SIM. Exposing them is deliberate, so callers can correlate a binding attempt server-side — it is not an oversight, and it does mean the host app can read the token. Do not log or persist them, and do not send the SMS yourself; use clientId when all you need is something to correlate on. SimBindingInitResponse.toString() redacts both; toMap() does not.

Requires updated native binaries — the Dart API cannot surface what the prebuilt SDKs do not expose. Both were rebuilt for this release: deepidsdk.aar (new SimBindingCallback.onSimBindingInit, clientId on SimBindingInitResponse) and DeepIdSDK.xcframework (new DeepIdSDKManager.onSimBindingInit, clientId on DeepIdSDKInitResponse, which is now public). The Gradle AAR coordinate moved to 1.2.2 so the new bytes are actually picked up instead of a cached module.

Internal: the iOS plugin now retains its FlutterMethodChannel. It previously let the channel go out of scope in register(with:), which was fine while traffic was one-way but leaves no route back to Dart.

Reliability: the wrapper's error contract is now airtight. Every failure crossing the plugin boundary surfaces as a DeepIdException with a typed DeepIdErrorCode — a raw MissingPluginException, or a TypeError from a malformed native payload, can no longer sail past an on DeepIdException handler. The host app always finds out what happened:

  • New codes — if you switch exhaustively over DeepIdErrorCode, add branches for these:
    • loggedOut — a pending onEnrollment cancelled by logout(). Previously reported as unknown, indistinguishable from a real failure.
    • unsupportedPlatform — the method channel has no native handler (web/desktop targets, or unmocked widget tests). Previously a raw MissingPluginException.
    • malformedResponse — the native layer answered on the success path with a payload this build could not read; usually a plugin/native version mismatch. Previously a raw TypeError, or worse, an EnrollmentResult carrying empty identifiers documented as guaranteed non-empty.
  • DeepIdException.nativeCode preserves the raw platform code, so a native code this build cannot map (unknown) is still identifiable in logs.
  • Enrollment failures are never dropped. With no onError handler, onEnrollment routes the failure through FlutterError.reportError (console + installed crash reporting) instead of swallowing it.
  • Concurrent onEnrollment listeners share one native wait. Previously a second waitForEnrollment replaced the first's pending result on the native side, and the first caller's callback simply never fired.
  • startSimBinding validates the success payload: a result the wrapper cannot parse — or one claiming success: false on the success channel — throws typed instead of returning a "success" the host has to second-guess.
  • verifySecurityPolicy now cannot throw: parse failures and MissingPluginException degrade to Unavailable(internalError) like every other no-verdict path, and AttestationResult.fromMap is hardened to match its documented never-throws contract.
  • A host onSimBindingInit callback that throws no longer dies inside the method-channel handler; it is reported through FlutterError, attributed, and the binding flow continues. Likewise, an exception thrown by the host's onEnrollment onSuccess surfaces as the host's own uncaught error rather than being re-reported as a fake SDK enrollment failure.
  • initialize rejects an empty appKey / appSecret immediately with the typed code, before any native round trip.
  • logout() and the isInitialized / isAttestationSupported getters treat a missing native side as their documented no-op answers (false) instead of leaking an exception.

2.1.0 #

Device binding is stricter in this release, to meet the UPI rules on failing a binding when the customer leaves the app mid-flow and on confirming the verification SMS was really sent. Bindings that previously succeeded quietly can now fail visibly — see the behaviour notes at the end of this entry.

New (Android): the verification SMS is confirmed as sent before verification starts. The send was previously fire-and-forget, so an SMS that never left the device — mobile radio off, no service, carrier send limit reached — still moved the flow on to polling and surfaced 45 seconds later as a generic timeout. The SDK now waits for the platform's send result and fails immediately with the real reason (e.g. "The mobile radio is off"), typically within a second.

New (Android): leaving the app mid-binding rejects the binding immediately. Going Home, opening Recents, or switching apps while a binding is in flight now fails it on the spot rather than after a grace period, and drops the local binding token. Deliberate departures only: notifications — including the carrier's SMS-charge notice — incoming calls, and system permission dialogs do not trigger it. Screen lock and system-initiated backgrounding are still handled by the existing grace-period watcher.

New (Android): the verification sheet no longer appears in the Recents thumbnail, since it shows the customer's number while a token is live.

New (iOS): cancelling the Messages composer now fails the binding. It previously dismissed the sheet and left the flow waiting. Binding is also declined if control takes longer than five seconds to return from the composer.

Fix (iOS): the URL-scheme fallback rejected every binding it handled. On the path where the in-app composer is unavailable and the SDK opens Messages directly, the app backgrounding itself tripped the abandonment watcher about five seconds after hand-off, failing bindings the customer had completed correctly. That hand-off is now an expected trip and verification resumes when the app returns.

New API: DeepIdErrorCode.bindingAbandoned is reported when a binding fails because the customer left the app, as distinct from DeepIdErrorCode.userCancelled for a deliberate dismissal. Treat it as a failed binding and offer a retry. If you switch exhaustively over DeepIdErrorCode you will need to add a branch for it.

Fix (Android): logout() could silently fail to log the device out. If enrollment or SDK init was still finishing when you called it — a few seconds after onEnrollment fires, or any time before it — the native SDK wrote the old session back to storage after logout had cleared it. The next initialize() then resumed the session logout was supposed to end instead of enrolling fresh, and the enrollment callback delivered the pre-logout deepId / sessionId. On Android that stale deepId was also persisted as the authoritative one, so it kept coming back on every later launch and enrollment.

Fix (Android): repeated login/logout cycles degraded toward an ANR. The native SDK's continuous security monitoring and device polling outlived logout() for the life of the process, and the next initialize() started a second set on top of them. Each cycle added another main-thread security scan on the same interval.

Requires updated native binaries — both platforms. Most of the above lives in the native SDKs rather than this plugin: the SMS send confirmation and the logout ordering fix are in deepidsdk.aar, and the composer cancel, five-second hand-off rule and URL-scheme fix are in DeepIdSDK.xcframework. Replace both binaries in your pub cache as part of this upgrade (see Prerequisites).

Upgrading the plugin without replacing the binaries is the failure case to avoid: the build still succeeds and the flow still works, but you silently keep the old permissive behaviour — no SMS send confirmation, no composer cancel handling — while appearing to be on 2.1.0. The plugin does fence off a retired SDK instance on its own side, so an older AAR can no longer feed post-logout state back into EnrollmentResult, and the Android leave-the-app rejection ships in the plugin itself and works regardless.

Behaviour notes for integrators. Failure paths that used to pass silently now surface as errors, so expect a higher visible failure rate rather than a change in what actually works:

  • A customer who switches away mid-binding gets bindingAbandoned instead of a binding that continued in the background.
  • A verification SMS the device could not send now fails fast with the carrier reason instead of timing out after 45 seconds.
  • Verification SMS content longer than a single 160-character message now fails visibly at send time instead of being silently truncated or dropped.

bindingAbandoned is the only API addition; no existing signatures changed.

2.0.0 #

Breaking: device intelligence is now computed entirely by the DeepID backend on both platforms. The SDK still collects device facts and sends them, but no longer derives scores or verdicts on-device, and iOS ships a smaller binary.

  • deviceIntelligence in EnrollmentResult (and from getFreshDeviceIntelligence()) is now whatever the backend returns, and is null until your backend starts sending the field. If your code reads specific keys such as device_score, re-check that logic — the shape has changed.
  • getFreshDeviceIntelligence() now always makes a network round trip on iOS, matching Android.
  • SIM binding's verification timeout is now 45 seconds on both platforms (previously 15s on Android, 20s on iOS).
  • SIM binding now fails if the app is backgrounded for more than 5 seconds while the flow is in progress — a new possible cause of a simBindingFailed error.
  • Fixed an iOS bug where the SIM binding confirmation screen could show a blank SIM name on single-SIM devices.
  • Breaking: DeepId.logout() now returns Future<bool> (true if an active session was cleared, false if there was nothing to log out of) instead of Future<void>. Existing calls that don't use the return value are unaffected.

Upgrading:

flutter clean
rm -rf ~/.pub-cache/hosted/pub.flutter-io.cn/deepidsdk_flutter-*
cd ios && rm -rf Pods Podfile.lock && pod install

Android just needs a rebuild with the new deepidsdk.aar.

1.0.5 #

  • Feature: added DeepId.logout() — clears the current enrolled session (deepId, sessionId, DeepId credentials, SIM binding state, and any locally persisted identifier) on both Dart and native sides. After logout(), calling initialize() again performs a fresh enrollment and fires the onEnrollment callback with a new deepId / sessionId. Safe to call when no session is active; a pending onEnrollment is rejected with the message Enrollment cancelled by logout(). Example app demonstrates the flow with a new "Logout" button under "Initialize & Enroll".
  • Fix (Android): EnrollmentResult.deepId is now stable across process restarts, matching the contract documented on the field. On the second-and-subsequent launches with an existing enrollment, the plugin was delivering a different identifier than the one returned on the first fresh enrollment. The plugin now persists the correct identifier from the first enrollment and returns it on every subsequent restore.
  • Fix (Android + iOS): DeepId.getFreshDeviceIntelligence() now works on every launch, not only the first fresh enrollment. Previously, on a second-and-subsequent launch with an existing enrollment, the native device-intelligence collector was never re-initialized in the new process, so the call resolved with null ("Fresh device intelligence is unavailable"). The underlying SDKs now lazily re-create the collector on demand, the first time getFreshDeviceIntelligence() is invoked after a process start.
  • Migration: If you tested against 1.0.4 or earlier and observed the wrong deepId on subsequent launches, clear the app's storage once after upgrading (Android Settings → Apps → Storage → Clear Data, or uninstall + reinstall). Devices that never ran an affected build are not impacted. The fresh device intelligence fix requires no migration.
  • Requires updated native binaries — replace deepidsdk.aar and the iOS xcframeworks under ~/.pub-cache/hosted/pub.flutter-io.cn/deepidsdk_flutter-1.0.5/ with the matching artifacts from DeepID.

1.0.4 #

  • Fix (build-blocking): corrected minimum iOS target to 15.0 (was 13.0) — podspec, example Podfile, and Xcode project updated.
  • Fix (build-blocking): corrected minimum Android API to 29 (was 21) — manifest-merger fails for hosts below API 29.
  • Fix (documentation): Added troubleshooting steps for the iOS release build.

1.0.3 #

  • iOS: refreshed DeepIdSDK.xcframework with an updated device-identifier source for the enrollment and SIM binding callbacks. The deepId field name, type, and shape are unchanged — existing integrations require no code changes, though the returned identifier value may differ after re-enrollment.
  • iOS: internal native plugin-bridge updates to match the refreshed binary.
  • No public Dart API changes.

1.0.2 #

  • iOS: added ShieldPtr.xcframework as a required vendored framework alongside DeepIdSDK.xcframework. Both must be placed under ios/Frameworks/ before running pod install.
  • Documentation: updated Prerequisites, "Verify before continuing", iOS setup, and Troubleshooting sections to reflect the second xcframework requirement.

1.0.1 #

  • Documentation: clarified that native SDK binaries must be placed inside the pub cache directory (~/.pub-cache/hosted/pub.flutter-io.cn/deepidsdk_flutter-<version>/), not a local plugin checkout.
  • Documentation: corrected enrollmentTimeout default from 30 s to 150 s in the API reference and error-handling sections.
  • Documentation: corrected iOS mobile field description — server value is returned first, phoneNumber parameter is the fallback.
  • Documentation: renamed Android binary from deepidsdk-release.aar to deepidsdk.aar throughout.

1.0.0 #

Initial release of deepidsdk_flutter.

Features #

  • DeepId.initialize(appKey:, appSecret:, onEnrollment:, onEnrollmentError:, enrollmentTimeout:) — initializes the native SDK and kicks off background device enrollment. Returns once the SDK is constructed (does not wait for enrollment to complete). Pass onEnrollment here or call DeepId.onEnrollment() separately to be notified when deepId + sessionId are ready.
  • DeepId.onEnrollment(onSuccess:, onError:, timeout:) — callback-driven enrollment listener. Fires exactly once when both identifiers are available, or delivers a DeepIdException on timeout or failure.
  • DeepId.startSimBinding({phoneNumber}) — presents the native SIM binding sheet (Android: Jetpack Compose Activity; iOS: SwiftUI page sheet). Awaits user confirmation and carrier verification, then returns a SimBindingResult.
  • DeepId.isInitialized — async getter; true after a successful initialize() call.
  • DeepId.deepId / DeepId.sessionId — synchronous accessors populated after the enrollment callback fires.

Types #

  • EnrollmentResult — carries deepId and sessionId from a completed enrollment.
  • SimBindingResult — carries success, deepId, sessionId, mobile, and message from a completed SIM binding flow.
  • DeepIdException — typed exception with a DeepIdErrorCode and a human-readable message. Thrown by initialize() and startSimBinding(), and passed to onEnrollmentError.
  • DeepIdErrorCode — exhaustive enum covering all failure modes: notInitialized, invalidAppKey, invalidAppSecret, initFailed, enrollmentTimeout, enrollmentNotComplete, simBindingFailed, userCancelled, and more.

Platform support #

Platform Minimum version
Android API 21 (Android 5.0)
iOS 13.0

Notes #

  • The native SDK binaries (Android AAR and iOS xcframework) are distributed separately by DeepID and are not bundled in this package. See the README.md Prerequisites section for placement instructions.
  • On Android, READ_PHONE_STATE and SEND_SMS are dangerous permissions that must be granted at runtime before calling startSimBinding().
  • On iOS, add NSMotionUsageDescription to your Info.plist before submitting to the App Store.
0
likes
120
points
148
downloads

Documentation

Documentation
API reference

Publisher

verified publishersurepass.io

Weekly Downloads

Flutter plugin for the DeepID SDK (Android + iOS). Device enrollment, SIM binding, on-demand posture attestation, and device fraud detection.

Homepage
Repository (GitHub)
View/report issues

Topics

#security #fraud-detection #attestation #sim-binding #authentication

License

unknown (license)

Dependencies

flutter

More

Packages that depend on deepidsdk_flutter

Packages that implement deepidsdk_flutter