{"id":13823742,"url":"https://github.com/surfstudio/flutter-otp-autofill","last_synced_at":"2025-04-13T07:13:30.764Z","repository":{"id":40366041,"uuid":"384333186","full_name":"surfstudio/flutter-otp-autofill","owner":"surfstudio","description":"Made by Surf 🏄","archived":false,"fork":false,"pushed_at":"2024-10-21T14:01:58.000Z","size":277,"stargazers_count":101,"open_issues_count":17,"forks_count":52,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-13T07:13:22.146Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/surfstudio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2021-07-09T05:40:01.000Z","updated_at":"2025-04-08T09:50:45.000Z","dependencies_parsed_at":"2024-01-18T05:20:27.823Z","dependency_job_id":"7b302b6d-80d3-432b-a746-2ec9f87b9000","html_url":"https://github.com/surfstudio/flutter-otp-autofill","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surfstudio%2Fflutter-otp-autofill","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surfstudio%2Fflutter-otp-autofill/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surfstudio%2Fflutter-otp-autofill/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surfstudio%2Fflutter-otp-autofill/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/surfstudio","download_url":"https://codeload.github.com/surfstudio/flutter-otp-autofill/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248675422,"owners_count":21143768,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T09:00:42.861Z","updated_at":"2025-04-13T07:13:29.628Z","avatar_url":"https://github.com/surfstudio.png","language":"Dart","funding_links":[],"categories":["Plugins"],"sub_categories":["Others"],"readme":"# OTP autofill\n\n\u003cimg src=\"https://raw.githubusercontent.com/surfstudio/flutter-open-source/main/assets/logo_black.png#gh-light-mode-only\" width=\"200\"\u003e\n\u003cimg src=\"https://raw.githubusercontent.com/surfstudio/flutter-open-source/main/assets/logo_white.png#gh-dark-mode-only\" width=\"200\"\u003e\n\nMade by [Surf 🏄‍♂️🏄‍♂️🏄‍♂️](https://surf.dev/)\n\n[![Build Status](https://shields.io/github/actions/workflow/status/surfstudio/flutter-otp-autofill/on_pull_request.yml?logo=github\u0026logoColor=white)](https://github.com/surfstudio/flutter-otp-autofill)\n[![Coverage Status](https://img.shields.io/codecov/c/github/surfstudio/flutter-otp-autofill?logo=codecov\u0026logoColor=white)](https://app.codecov.io/gh/surfstudio/flutter-otp-autofill)\n[![Pub Version](https://img.shields.io/pub/v/otp_autofill?logo=dart\u0026logoColor=white)](https://pub.dev/packages/otp_autofill)\n[![Pub Likes](https://badgen.net/pub/likes/otp_autofill)](https://pub.dev/packages/otp_autofill)\n[![Pub popularity](https://badgen.net/pub/popularity/otp_autofill)](https://pub.dev/packages/otp_autofill/score)\n![Flutter Platform](https://badgen.net/pub/flutter-platform/otp_autofill)\n\n## Overview\n\nThis plugin uses the [SMS User Consent API](https://developers.google.com/identity/sms-retriever/user-consent/overview) and [SMS Retriever API](https://developers.google.com/identity/sms-retriever/overview) on Android.\n\nYou could use autofill from another input by using the OTPStrategy (e.g. from push-notification).\n\nFor testing you could create a `TestStrategy`.\n\n## iOS\n\nOn iOS, the OTP autofill feature is integrated into the `TextField` component.\nThe code received from an SMS is stored for a duration of 3 minutes.\n\n### Rules for sms\n\n1. Sms must contain the word `code` or its translation in iOS supported localizations.\n2. The sms should contain only one sequence of digits.\n\n### iOS Testing\n\nThe iOS platform is capable of receiving OTP from any phone number, not just a specific sender.\n\n## Android\n\n- `OTPInteractor.hint` - displays a system dialog that allows the user to select from their saved phone numbers (recommendation from Google).\n- `OTPInteractor.getAppSignature` - creates the hash code of your application, which is used in the [SMS Retriever API](https://developers.google.com/identity/sms-retriever/overview).\n- `OTPInteractor.startListenUserConsent` - the broadcast receiver that starts listening for OTP codes using the [SMS User Consent API](https://developers.google.com/identity/sms-retriever/user-consent/overview). It listens for a duration of 5 minutes, after which a timeout exception occurs.\n- `OTPInteractor.startListenRetriever` - the broadcast receiver that starts listening for OTP codes using the [SMS Retriever API](https://developers.google.com/identity/sms-retriever/overview). It listens for a duration of 5 minutes, after which a timeout exception occurs.\n- `OTPInteractor.stopListenForCode` - used in dispose.\n\nThe plugin is designed to receive the full text of an SMS message and requires a parser to extract the relevant information from the message.\n\nIf you use the [SMS User Consent API](https://developers.google.com/identity/sms-retriever/user-consent/overview), the system will prompt the user for permission to access and read incoming messages.\n\n### Rules for SMS when using [SMS User Consent API](https://developers.google.com/identity/sms-retriever/user-consent/overview)\n\n1. The message should contain an alphanumeric string of 4 to 10 characters, with at least one digit.\n2. The message was sent from a phone number that is not in the user's contacts.\n3. If the sender's phone number is specified, the message must originate from that number.\n\n### Rules for SMS when using [SMS Retriever API](https://developers.google.com/identity/sms-retriever/overview)\n\n1. The length should not exceed 140 bytes.\n2. It should contain a one-time code that the client sends back to your server to complete the verification process.\n3. It should include an 11-character hash string that identifies your app (refer to the [documentation for server](https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string) for more details). For testing, you can obtain it from `OTPInteractor.getAppSignature`.\n\n### Android Testing\n\nThe `OTPInteractor.startListenForCode` method allows the application to start receiving verification codes from a specific phone number, specified by the `senderPhone` argument.\n\nYou also can use Android Emulator to test the plugin. To do this, you need to send an SMS to the emulator with the following command:\n\n```bash\nadb emu sms send \u003csenderPhone\u003e \u003cmessage\u003e\n```\nE.g.:\n```bash\nadb emu sms send 900 \"Your code is 12345. Do not share it with anyone.\"\n```\n\nMake sure `senderPhone` is the same as the one you specified in the `startListenForCode` method.\n\n## Usage\n\nYou should use `OTPInteractor` to interact with OTP.\n\nTo simplify implementation, consider using the `OTPTextEditController` as a controller for your `TextField`.\n\n`OTPTextEditController.startListenUserConsent` - uses the [SMS User Consent API](https://developers.google.com/identity/sms-retriever/user-consent/overview) and listens to user strategies.\n`OTPTextEditController.startListenRetriever` - uses the [SMS Retriever API](https://developers.google.com/identity/sms-retriever/overview) and listens to user strategies.\n`OTPTextEditController.startListenOnlyStrategies` - only listens to user strategies.\n`OTPTextEditController.stopListen` - used in dispose.\n\n## Installation\n\nAdd `otp_autofill` to your `pubspec.yaml` file:\n\n```yaml\ndependencies:\n  otp_autofill: $currentVersion$\n```\n\n\u003cp\u003eAt this moment, the current version of \u003ccode\u003eotp_autofill\u003c/code\u003e is \u003ca href=\"https://pub.dev/packages/otp_autofill\"\u003e\u003cimg style=\"vertical-align:middle;\" src=\"https://img.shields.io/pub/v/otp_autofill.svg\" alt=\"otp_autofill version\"\u003e\u003c/a\u003e.\u003c/p\u003e\n\n### Android Installation\n\nSet `minSdkVersion` at least to 19 in `\u003cproject root\u003e/android/app/build.gradle`.\n\n``` gradle\nandroid {\n  ...\n  defaultConfig {\n    ...\n    minSdkVersion 19\n    ...\n  }\n  ...\n}\n```\n\n## Example\n\n1. Create a simple strategy\n\n```dart\nclass SampleStrategy extends OTPStrategy {\n  @override\n  Future\u003cString\u003e listenForCode() {\n    return Future.delayed(\n      const Duration(seconds: 4),\n      () =\u003e 'Your code is 54321',\n    );\n  }\n}\n```\n\n2. Initialize and set the listener\n\n```dart\nlate OTPTextEditController controller;\nfinal scaffoldKey = GlobalKey();\n\n@override\nvoid initState() {\n  super.initState();\n  _otpInteractor = OTPInteractor();\n  _otpInteractor.getAppSignature()\n      .then((value) =\u003e print('signature - $value'));\n  controller = OTPTextEditController(\n    codeLength: 5,\n    onCodeReceive: (code) =\u003e print('Your Application receive code - $code'),\n  )..startListenUserConsent(\n      (code) {\n        final exp = RegExp(r'(\\d{5})');\n        return exp.stringMatch(code ?? '') ?? '';\n      },\n      strategies: [\n        SampleStrategy(),\n      ],\n    );\n}\n```\n\n## Send new code\n\nTo receive a new code when a timeout exception occurs, you can pass a callback function to the `onTimeOutException` parameter and start listen for a new code.\n\n```dart\ncontroller = OTPTextEditController(\n      codeLength: 5,\n      onCodeReceive: (code) =\u003e print('Your Application receive code - $code'),\n      otpInteractor: _otpInteractor,\n      onTimeOutException: () {\n        //TODO: start new listen to get new code\n        controller.startListenUserConsent(\n          (code) {\n            final exp = RegExp(r'(\\d{5})');\n            return exp.stringMatch(code ?? '') ?? '';\n          },\n          strategies: [\n            SampleStrategy(),\n          ],\n        );\n      },\n    )..startListenUserConsent(\n        (code) {\n          final exp = RegExp(r'(\\d{5})');\n          return exp.stringMatch(code ?? '') ?? '';\n        },\n        strategies: [\n          TimeoutStrategy(),\n        ],\n      );\n```\n\n## Changelog\n\nAll significant changes to this project will be documented in [this file](./CHANGELOG.md).\n\n## Issues\n\nTo report any issues, submit them directly in the [Issues](https://github.com/surfstudio/flutter-otp-autofill/issues) section.\n\n## Contribute\n\nIf you wish to contribute to the package (for instance, by enhancing the documentation, fixing a bug, or introducing a new feature), please review our [contribution guide](./CONTRIBUTING.md) first and then submit your pull request.\n\nYour PRs are always welcome.\n\n## How to reach us\n\nPlease don't hesitate to ask any questions about this package. Join our community chat on Telegram. We communicate in both English and Russian.\n\n[![Telegram](https://img.shields.io/badge/chat-on%20Telegram-blue.svg)](https://t.me/SurfGear)\n\n## License\n\n[Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurfstudio%2Fflutter-otp-autofill","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsurfstudio%2Fflutter-otp-autofill","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurfstudio%2Fflutter-otp-autofill/lists"}