├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── android ├── .gitignore ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── com │ └── truecallersdk │ ├── Constants.kt │ └── TruecallerSdkPlugin.kt ├── example ├── .gitignore ├── .metadata ├── README.md ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── truecaller_sdk_example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── Runner-Bridging-Header.h │ │ └── Runner.entitlements ├── lib │ ├── customization │ │ ├── config_options.dart │ │ ├── main_customization_screen.dart │ │ ├── oauth_result_screen.dart │ │ └── result_screen.dart │ ├── main.dart │ └── non_tc_screen.dart ├── pubspec.yaml └── test │ └── widget_test.dart ├── images ├── main.jpg ├── main_customization_screen.jpg └── truecaller_logo.png ├── ios ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ ├── Constants.swift │ ├── Extensions.swift │ ├── SwiftTruecallerSdkPlugin.swift │ ├── TruecallerSdkPlugin.h │ └── TruecallerSdkPlugin.m └── truecaller_sdk.podspec ├── lib ├── src │ ├── scope_options.dart │ ├── truecaller.dart │ └── truecaller_callback.dart └── truecaller_sdk.dart ├── pubspec.yaml └── test └── truecaller_sdk_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter/Dart/Pub related 2 | .DS_Store 3 | .dart_tool/ 4 | .idea/ 5 | .packages 6 | .pub/ 7 | build/ 8 | pubspec.lock 9 | truecaller_sdk.iml 10 | 11 | # example 12 | **/truecaller_sdk_example.iml 13 | **/.dart_tool 14 | **/.idea 15 | **/build 16 | **/.flutter-plugins 17 | **/.flutter-plugins-dependencies 18 | **/pubspec.lock 19 | 20 | 21 | # Android related 22 | **/android/**/gradle-wrapper.jar 23 | **/android/.gradle 24 | **/android/gradlew 25 | **/android/gradlew.bat 26 | **/android/local.properties 27 | **/android/truecaller_sdk_example_android.iml 28 | **/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java 29 | 30 | # iOS/XCode related 31 | **/ios/**/*.mode1v3 32 | **/ios/**/*.mode2v3 33 | **/ios/**/*.moved-aside 34 | **/ios/**/*.pbxuser 35 | **/ios/**/*.perspectivev3 36 | **/ios/**/*sync/ 37 | **/ios/**/.sconsign.dblite 38 | **/ios/**/.tags* 39 | **/ios/**/.vagrant/ 40 | **/ios/**/DerivedData/ 41 | **/ios/**/Icon? 42 | **/ios/**/Pods/ 43 | **/ios/**/.symlinks/ 44 | **/ios/**/profile 45 | **/ios/**/xcuserdata 46 | **/ios/.generated/ 47 | **/ios/Flutter/App.framework 48 | **/ios/Flutter/Flutter.framework 49 | **/ios/Flutter/Flutter.podspec 50 | **/ios/Flutter/Generated.xcconfig 51 | **/ios/Flutter/app.flx 52 | **/ios/Flutter/app.zip 53 | **/ios/Flutter/flutter_assets/ 54 | **/ios/Flutter/flutter_export_environment.sh 55 | **/ios/ServiceDefinitions.json 56 | **/ios/Runner/GeneratedPluginRegistrant.* 57 | 58 | # Exceptions to above rules. 59 | !**/ios/**/default.mode1v3 60 | !**/ios/**/default.mode2v3 61 | !**/ios/**/default.pbxuser 62 | !**/ios/**/default.perspectivev3 63 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 8af6b2f038c1172e61d418869363a28dffec3cb4 8 | channel: stable 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | #### Breaking change 4 | 5 | * Flutter plugin supporting OAuth flow and manual verification flow. 6 | * Based on Truecaller's OAuth SDK for Android version [3.0.0](https://docs.truecaller.com/truecaller-sdk/android/oauth-sdk-3.0) 7 | 8 | ## 0.1.2 9 | 10 | * Updated Flutter channel to stable version 3.3.0 11 | * Updated Android Gradle Plugin to 7.2.2 and Kotlin to 1.7.0 12 | * Fixed a bug related to type mismatch 13 | 14 | ## 0.1.1 15 | 16 | * Flutter plugin for Truecaller SDK based on Truecaller's Android SDK 2.7.0 17 | * TruecallerSdk.requestVerification() would now throw a PlatformException in case an invalid number is supplied to it. 18 | 19 | ## 0.1.0 20 | 21 | * Migrated the plugin and example to support null safety 22 | 23 | ## 0.0.4 24 | 25 | * Flutter plugin for Truecaller SDK based on Truecaller's Android SDK 2.6.0 26 | * More optimisations, bug fixes and support for targetSdkVersion 30 27 | 28 | ## 0.0.3 29 | 30 | * Flutter plugin for Truecaller SDK based on Truecaller's Android SDK 2.5.0 31 | * A new error with code = 15 has been added to handle a rare device specific ActivityNotFound Exception 32 | * Enhanced the plugin to automatically clear the resources taken up by SDK when its no longer needed to save memory 33 | * Updated name validations to handle common scenarios during `non-truecaller verification` flow. 34 | The first name and last name values to be passed need to follow below mentioned rules : 35 | - The strings need to contains at least 1 alphabet, and cannot be completely comprised of numbers or special characters 36 | - String length should be less than 128 characters 37 | - First name is a mandatory field, last name can be empty (but non-nullable) 38 | * Time out exceptions have been removed for OTP and Missed Call from `non-truecaller verification` flow. Use TTL value returned by the stream callback to 39 | handle the time out logic at your own end which can be retrieved from `TruecallerUserCallback.ttl` when `TruecallerSdkCallback.result` equals 40 | `TruecallerSdkCallbackResult.missedCallInitiated` or `TruecallerSdkCallbackResult.otpInitiated`. This means that as soon as you initiate the number 41 | verification flow by OTP or Missed call, you will receive a TTL value which you can use appropriately to show a countdown timer and once it expires you 42 | need to restart the verification process. 43 | 44 | ## 0.0.2 45 | 46 | * Flutter plugin for Truecaller SDK based on Truecaller's Android SDK 2.4.0 47 | * Only supports Android at the moment 48 | * Supports verification of both Truecaller and Non-Truecaller users 49 | * TTL is now exposed to partners when OTP or Missed Call is initiated so that partners are aware of time left to complete the user verification and can take 50 | an appropriate action once TTL expires. 51 | * Optional nullable Error is passed in case of **`TruecallerSdkCallbackResult.verification`** which can be used to determine user action which led to initiating 52 | manual verification like whether the user pressed on the `footer CTA` on the verification screen OR the `system back button`. 53 | 54 | ## 0.0.1 55 | 56 | * Flutter plugin for Truecaller SDK based on Truecaller's Android SDK 2.3.0 57 | * Only supports Android at the moment 58 | * Only supports verification of Truecaller users at the moment -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015-present, True Software Scandinavia AB. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # truecaller_sdk 2 | 3 |

4 | 5 |

6 | 7 | Flutter plugin that uses [Truecaller's OAuth SDK for Android](https://docs.truecaller.com/truecaller-sdk/) based on OAuth 2.0 which is the industry-standard protocol for authorization. 8 | 9 | For more details, please refer [here](https://docs.truecaller.com/truecaller-sdk/android/oauth-sdk-3.0/implementing-user-flow-for-your-app) 10 | 11 | ## Steps to integrate 12 | 13 | ### 1. Update `pubspec.yaml`: 14 | Include the latest truecaller_sdk in your `pubspec.yaml` 15 | ```yaml 16 | dependencies: 17 | ... 18 | truecaller_sdk: ^1.0.0 19 | ... 20 | ``` 21 | ### 2. Generate Client Id and add it to `AndroidManifest.xml`: 22 | * [Register](https://sdk-console-noneu.truecaller.com/) to create your business account and manage OAuth projects . 23 | * Refer to the [official documentation](https://docs.truecaller.com/truecaller-sdk/android/oauth-sdk-3.0/integration-steps/generating-client-id) for 24 | generating client id. 25 | * Open your [AndroidManifest.xml](/example/android/app/src/main/AndroidManifest.xml) under /android module and add a `meta-data` element to the `application` 26 | element with your client id: 27 | ```xml 28 | 29 | ... 30 | 31 | .. 32 | 33 | 34 | ... 35 | 36 | ``` 37 | 38 | ### 3. Make changes to `MainActivity.kt`: 39 | * Head to the [MainActivity.kt](/example/android/app/src/main/kotlin/com/example/truecaller_sdk_example/MainActivity.kt) under /android module 40 | * SDK requires the use of a `FragmentActivity` as opposed to `Activity`, so extend your `MainActivity.kt` with `FlutterFragmentActivity`. 41 | * Override the two functions `configureFlutterEngine(flutterEngine: FlutterEngine)` and `getBackgroundMode()` in your `MainActivity.kt`: 42 | ```kotlin 43 | class MainActivity: FlutterFragmentActivity() { 44 | override fun configureFlutterEngine(flutterEngine: FlutterEngine) { 45 | GeneratedPluginRegistrant.registerWith(flutterEngine) 46 | } 47 | 48 | override fun getBackgroundMode(): FlutterActivityLaunchConfigs.BackgroundMode { 49 | return FlutterActivityLaunchConfigs.BackgroundMode.transparent 50 | } 51 | } 52 | ``` 53 | * Update `launchMode` of `MainActivity.kt` to `singleTask` in `AndroidManifest.xml` : 54 | ```xml 55 | 56 | ... 57 | 59 | .. 60 | ... 61 | 62 | ``` 63 | 64 | ### 4. Add required Permissions to `AndroidManifest.xml`: 65 | Permissions are mandatory only if you are initializing the SDK with `TcSdkOptions.OPTION_VERIFY_ALL_USERS` in order to verify the users manually. 66 | 67 | For Android 8 and above : 68 | ```xml 69 | 70 | 71 | 72 | ``` 73 | 74 | For Android 7 and below : 75 | ```xml 76 | 77 | 78 | 79 | ``` 80 | 81 | These permissions are required for the SDK to be able to automatically detect the drop call and complete the verification flow. 82 | 83 | To read more about different scenarios for user verifications, [click here](https://docs.truecaller.com/truecaller-sdk/android/oauth-sdk-3.0/scenarios-for-all-user-verifications-truecaller-and-non-truecaller-users). 84 | 85 | ## Example 1 (to verify only Truecaller users having Truecaller app on their device) 86 | 87 | ```dart 88 | 89 | //Import package 90 | import 'package:truecaller_sdk/truecaller_sdk.dart'; 91 | 92 | //Step 1: Initialize the SDK with OPTION_VERIFY_ONLY_TC_USERS 93 | TcSdk.initializeSDK(sdkOption: TcSdkOptions.OPTION_VERIFY_ONLY_TC_USERS); 94 | 95 | //Step 2: Check if SDK is usable on that device, otherwise fall back to any other login alternative 96 | bool isUsable = await TcSdk.isOAuthFlowUsable; 97 | 98 | //Step 3: If isUsable is true, then do the following before you can invoke the OAuth consent screen - 99 | //3.1: Set a unique OAuth state and store that state in your session so that you can match it with the state received from the authorization server to prevent 100 | //any request forgery attacks. 101 | //3.2: Set the OAuth scopes that you'd want to request from the user. You can either ask all of them together or a subset of it. 102 | //3.3: Generate a random code verifier either yourself or using the SDK method as shown below. Store the code verifier in the current session since it would 103 | //be required later to generate the access token. 104 | //3.4: Generate code challenge using the code verifier from the previous step 105 | //3.5 Set the code challenge 106 | //3.6 Finally, after setting all of the above, invoke the consent screen by calling getAuthorizationCode 107 | TcSdk.isOAuthFlowUsable.then((isOAuthFlowUsable) { 108 | if (isOAuthFlowUsable) { 109 | oAuthState = "some_unique_uuid" //store the state to use later 110 | TcSdk.setOAuthState(oAuthState); //3.1 111 | TcSdk.setOAuthScopes(['profile', 'phone', 'openid']); //3.2 112 | TcSdk.generateRandomCodeVerifier.then((codeVerifier) { //3.3 113 | TcSdk.generateCodeChallenge(codeVerifier).then((codeChallenge) { //3.4 114 | if (codeChallenge != null) { 115 | this.codeVerifier = codeVerifier; //store the code verifier to use later 116 | TcSdk.setCodeChallenge(codeChallenge); //3.5 117 | TcSdk.getAuthorizationCode; //3.6 118 | } else { 119 | print("***Code challenge NULL. Device not supported***"); 120 | } 121 | }); 122 | }); 123 | } else { 124 | print("***Not usable***"); 125 | } 126 | } 127 | 128 | //Step 4: Be informed about the TcSdk.getAuthorizationCode callback result(success, failure, verification) 129 | StreamSubscription streamSubscription = TcSdk.streamCallbackData.listen((tcSdkCallback) { 130 | switch (tcSdkCallback.result) { 131 | case TcSdkCallbackResult.success: 132 | TcOAuthData tcOAuthData = tcSdkCallback.tcOAuthData!; 133 | String authorizationCode = tcOAuthData.authorizationCode; //use this along with codeVerifier generated in step 3.3 to generate an access token 134 | String stateReceivedFromServer = tcOAuthData.state; //match it with what you set in step 3.1 135 | List scopesGranted = tcOAuthData.scopesGranted; //list of scopes granted by the user 136 | break; 137 | case TcSdkCallbackResult.failure: 138 | //Handle the failure 139 | int errorCode = tcSdkCallback.error!.code; 140 | String message = tcSdkCallback.error!.message; 141 | break; 142 | case TcSdkCallbackResult.verification: 143 | // won't receive this callback if initializing SDK with sdkOption as TcSdkOptions.OPTION_VERIFY_ONLY_TC_USERS 144 | print("Verification Required!!"); 145 | break; 146 | default: 147 | print("Invalid result"); 148 | } 149 | }); 150 | 151 | //Step 5: Dispose streamSubscription 152 | @override 153 | void dispose() { 154 | streamSubscription?.cancel(); 155 | super.dispose(); 156 | } 157 | ``` 158 | 159 | //Step 4a 160 | Using the “code verifier” from step 3.3, and the “authorization code” received in success callback of step 4, you need to make a network call to 161 | Truecaller’s backend so as to [fetch the access token](https://docs.truecaller.com/truecaller-sdk/android/oauth-sdk-3.0/integration-steps/integrating-with-your-backend/fetching-user-token) 162 | 163 | //Step 4b 164 | Make a network call to [fetch the userInfo](https://docs.truecaller.com/truecaller-sdk/android/oauth-sdk-3.0/integration-steps/integrating-with-your-backend/fetching-user-profile) using access token from step 4a. The response would be corresponding to the scopes granted by the user. 165 | 166 | ## Example 2 (to verify both Truecaller users (Example 1) and non-Truecaller users via manual verification) 167 | 168 | ```dart 169 | 170 | //Import package 171 | import 'package:truecaller_sdk/truecaller_sdk.dart'; 172 | 173 | //Step 1: Initialize the SDK with SDK_OPTION_WITH_OTP 174 | TcSdk.initializeSDK(sdkOption: TcSdkOptions.OPTION_VERIFY_ALL_USERS); 175 | 176 | //Follow steps 2 and 3 from Example 1 177 | 178 | //Step 4: Be informed about the TcSdk.getAuthorizationCode callback result(success, failure, verification) 179 | StreamSubscription streamSubscription = TcSdk.streamCallbackData.listen((tcSdkCallback) { 180 | switch (tcSdkCallback.result) { 181 | case TcSdkCallbackResult.success: 182 | TcOAuthData tcOAuthData = tcSdkCallback.tcOAuthData!; 183 | String authorizationCode = tcOAuthData.authorizationCode; // use this along with codeVerifier generated in step 3.3 to generate an access token 184 | String stateReceivedFromServer = tcOAuthData.state; // match it with what you set in step 3.1 185 | List scopesGranted = tcOAuthData.scopesGranted; 186 | break; 187 | case TcSdkCallbackResult.failure: 188 | //Handle the failure 189 | int errorCode = tcSdkCallback.error!.code; 190 | String message = tcSdkCallback.error!.message; 191 | break; 192 | case TcSdkCallbackResult.verification: 193 | //If the callback comes here, it indicates that user has to be manually verified, so follow step 5 194 | //You'd receive nullable error which can be used to determine user action that led to manual verification 195 | int errorCode = tcSdkCallback.error!.code; 196 | String message = tcSdkCallback.error!.message; 197 | print("Verification Required!!"); 198 | break; 199 | default: 200 | print("Invalid result"); 201 | } 202 | }); 203 | 204 | //Step 5: Initiate manual verification by asking user for his number only if you receive callback result as 205 | //TcSdkCallbackResult.verification in the previous step. 206 | //Please ensure proper validations are in place so as to send a valid phone number string to the below method, 207 | //otherwise an exception would be thrown. 208 | //Also, request the required permissions from the user and ensure they are granted before calling this method. 209 | TcSdk.requestVerification(phoneNumber: "PHONE_NUMBER"); 210 | 211 | //Step 6: Be informed about the TcSdk.requestVerification callback result via [streamCallbackData] stream 212 | //result could be either of (missedCallInitiated, missedCallReceived, otpInitiated, otpReceived, 213 | //verifiedBefore, verificationComplete, exception) 214 | StreamSubscription streamSubscription = TcSdk.streamCallbackData.listen((tcSdkCallback) { 215 | switch (tcSdkCallback.result) { 216 | case TcSdkCallbackResult.missedCallInitiated: 217 | //Number Verification would happen via Missed call, so you can show a loader till you receive the call 218 | //You'd also receive ttl (in seconds) that determines time left to complete the user verification 219 | //Once TTL expires, you need to start from step 5. So you can either ask the user to input another number 220 | //or you can also auto-retry the verification on the same number by giving a retry button 221 | String? ttl = tcSdkCallback.ttl; 222 | //You'd also receive a request nonce whose value would be same as the State that you set in step 3.1 223 | String requestNonce = tcSdkCallback.requestNonce; 224 | break; 225 | case TcSdkCallbackResult.missedCallReceived: 226 | //Missed call received and now you can complete the verification as mentioned in step 7a 227 | break; 228 | case TcSdkCallbackResult.otpInitiated: 229 | //Number Verification would happen via OTP 230 | //You'd also receive ttl (in seconds) that determines time left to complete the user verification 231 | //Once TTL expires, you need to start from step 5. So you can either ask the user to input another number 232 | //or you can also auto-retry the verification on the same number by giving a retry button 233 | String? ttl = tcSdkCallback.ttl; 234 | //You'd also receive a request nonce whose value would be same as the State that you set in step 3.1 235 | String requestNonce = tcSdkCallback.requestNonce; 236 | break; 237 | case TcSdkCallbackResult.otpReceived: 238 | //OTP received and now you can complete the verification as mentioned in step 7b 239 | //If SMS Retriever hashcode is configured on Truecaller's developer dashboard, get the OTP from callback 240 | String? otp = tcSdkCallback.otp; 241 | break; 242 | case TcSdkCallbackResult.verificationComplete: 243 | //Number verification has been completed successfully and you can get the accessToken from callback 244 | String? token = tcSdkCallback.accessToken; 245 | //You'd also receive a request nonce whose value would be same as the State that you set in step 3.1 246 | String requestNonce = tcSdkCallback.requestNonce; 247 | break; 248 | case TcSdkCallbackResult.verifiedBefore: 249 | //Number has already been verified before, hence no need to verify. Retrieve the Profile data from callback 250 | String firstName = tcSdkCallback.profile!.firstName; 251 | String? lastName = tcSdkCallback.profile!.lastName; 252 | String phNo = tcSdkCallback.profile!.phoneNumber; 253 | String? token = tcSdkCallback.profile!.accessToken; 254 | //You'd also receive a request nonce whose value would be same as the State that you set in step 3.1 255 | String requestNonce = tcSdkCallback.profile!.requestNonce; 256 | break; 257 | case TcSdkCallbackResult.exception: 258 | //Handle the exception 259 | int exceptionCode = tcSdkCallback.exception!.code; 260 | String exceptionMsg = tcSdkCallback.exception!.message; 261 | break; 262 | default: 263 | print("Invalid result"); 264 | } 265 | }); 266 | 267 | //Step 7: Complete user verification 268 | //7a: If Missed call has been received successfully, i.e. if you received callback result as 269 | // TcSdkCallbackResult.missedCallReceived in the previous step call this method with user's name 270 | TcSdk.verifyMissedCall(firstName: "FIRST_NAME", lastName: "LAST_NAME"); 271 | 272 | //7b: If OTP has been initiated, show user an input OTP screen where they can enter the OTP. 273 | //If the OTP is received on the same device, and you've configured the SMS Retriever, you can prefill the OTP which 274 | //you'd receive if the callback result is TcSdkCallbackResult.otpReceived, and call this method with user's name 275 | //Otherwise, if OTP is not auto-read or if the OTP is received on any other device, call this method with the user's name 276 | //and OTP entered by the user. 277 | TcSdk.verifyOtp(firstName: "FIRST_NAME", lastName: "LAST_NAME", otp: "OTP"); 278 | 279 | //Step 7: Dispose streamSubscription 280 | @override 281 | void dispose() { 282 | streamSubscription?.cancel(); 283 | super.dispose(); 284 | } 285 | ``` 286 | 287 | As mentioned in Step 6 above, when `TcSdkCallbackResult` equals `TcSdkCallbackResult.missedCallInitiated` or `TcSdkCallbackResult.otpInitiated`, you will receive an additional parameter for the time to live i.e TTL (in seconds) which is passed as String extra and can be retrieved from 288 | the callback using `tcSdkCallback.ttl`. This value determines amount of time left to complete the user verification. You can use this value to show 289 | a waiting message to your user before they can retry for another attempt i.e fresh verification for same number cannot be re-initiated till the TTL expires. 290 | Once the TTL expires, you need to start the verification process again from step 5. 291 | 292 | ##### NOTE ##### 293 | * For details on different kinds of errorCodes, refer [here](https://docs.truecaller.com/truecaller-sdk/android/oauth-sdk-3.0/integration-steps/handling-error-scenarios). 294 | * For details on different kinds of exceptions, refer [here](https://docs.truecaller.com/truecaller-sdk/android/oauth-sdk-3.0/integration-steps/non-truecaller-user-verification/trueexception). 295 | * For details on Server Side Response Validation, refer [here](https://docs.truecaller.com/truecaller-sdk/android/oauth-sdk-3.0/integration-steps/non-truecaller-user-verification/server-side-validation). 296 | * For sample implementations, head over to [example](example) module. 297 | 298 | ## Customization Options 299 | 300 | ### Language 301 | To customise the consent screen in any of the supported Indian languages, add the following line before calling `TcSdk.getAuthorizationCode`: 302 | ```dart 303 | /// initialize the SDK and check isUsable first before calling this method 304 | /// Default value is "en" i.e English 305 | TcSdk.setLocale("hi") // this sets the language to Hindi 306 | ``` 307 | 308 | ### Consent screen UI 309 | You can customize the consent screen UI using the options available in class `TcSdkOptions` under `scope_options.dart` and pass them while initializing the SDK. 310 | 311 | ```dart 312 | /// [sdkOption] determines whether you want to use the SDK for verifying - 313 | /// 1. [TcSdkOptions.OPTION_VERIFY_ONLY_TC_USERS] i.e only Truecaller users 314 | /// 2. [TcSdkOptions.OPTION_VERIFY_ALL_USERS] i.e both Truecaller and Non-Truecaller users 315 | /// [consentHeadingOption] determines the heading of the consent screen. 316 | /// [ctaText] determines prefix text in login/primary button 317 | /// [footerType] determines the footer button/secondary button text. 318 | /// [buttonShapeOption] to set login button shape 319 | /// [buttonColor] to set login button color 320 | /// [buttonTextColor] to set login button text color 321 | static initializeSDK( 322 | {required int sdkOption, 323 | int consentHeadingOption = TcSdkOptions.SDK_CONSENT_HEADING_LOG_IN_TO, 324 | int footerType = TcSdkOptions.FOOTER_TYPE_ANOTHER_MOBILE_NO, 325 | int ctaText = TcSdkOptions.CTA_TEXT_PROCEED, 326 | int buttonShapeOption = TcSdkOptions.BUTTON_SHAPE_ROUNDED, 327 | int? buttonColor, 328 | int? buttonTextColor}) 329 | ``` 330 | 331 | By default, `initializeSDK()` has default argument values for all the arguments except the `sdkOption` which is a required argument, so if you 332 | don't pass any explicit values to the other arguments, this method will initialize the SDK with default values as above. 333 | 334 | ##### Note 335 | For list of supported locales and details on different kinds of customizations, refer [here](https://docs.truecaller.com/truecaller-sdk/android/oauth-sdk-3.0/integration-steps/customisation) 336 | 337 | ##### Support 338 | For any technical/flow related questions, please feel free to reach out via our [support channel](https://developer.truecaller.com/support) for a fast and dedicated response. 339 | 340 | ## License 341 | 342 | [`truecaller_sdk` is MIT-licensed](LICENSE). 343 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | group 'com.truecallersdk' 32 | version '1.0-SNAPSHOT' 33 | 34 | buildscript { 35 | ext.kotlin_version = '1.8.22' 36 | repositories { 37 | google() 38 | mavenCentral() 39 | } 40 | 41 | dependencies { 42 | classpath 'com.android.tools.build:gradle:7.4.2' 43 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 44 | } 45 | } 46 | 47 | rootProject.allprojects { 48 | repositories { 49 | google() 50 | mavenCentral() 51 | } 52 | } 53 | 54 | apply plugin: 'com.android.library' 55 | apply plugin: 'kotlin-android' 56 | 57 | def sdkVariant = "flutter" 58 | def sdkVariantVersion = "1.0.0" 59 | 60 | android { 61 | compileSdkVersion 28 62 | 63 | sourceSets { 64 | main.java.srcDirs += 'src/main/kotlin' 65 | } 66 | defaultConfig { 67 | minSdkVersion 22 68 | resValue("string", "sdk_variant", "${sdkVariant}") 69 | resValue("string", "sdk_variant_version", "${sdkVariantVersion}") 70 | } 71 | lintOptions { 72 | disable 'InvalidPackage' 73 | } 74 | } 75 | 76 | dependencies { 77 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 78 | implementation 'com.truecaller.android.sdk:truecaller-sdk:3.0.0' 79 | } 80 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | # 4 | # Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | # 6 | # Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | # 8 | # In accordance with the Truecaller SDK Agreement available 9 | # here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | # accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | # limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | # Truecaller SDK Product in object code form only, solely for the purpose of using 13 | # the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | # 15 | # THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | # WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | # TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | # SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | # EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | # OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | # OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | # POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | # PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | # 30 | org.gradle.jvmargs=-Xmx1536M 31 | android.useAndroidX=true 32 | android.enableJetifier=true 33 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | # 4 | # Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | # 6 | # Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | # 8 | # In accordance with the Truecaller SDK Agreement available 9 | # here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | # accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | # limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | # Truecaller SDK Product in object code form only, solely for the purpose of using 13 | # the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | # 15 | # THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | # WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | # TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | # SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | # EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | # OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | # OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | # POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | # PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | # 30 | 31 | distributionBase=GRADLE_USER_HOME 32 | distributionPath=wrapper/dists 33 | zipStoreBase=GRADLE_USER_HOME 34 | zipStorePath=wrapper/dists 35 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip 36 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | rootProject.name = 'truecaller_sdk' 32 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /android/src/main/kotlin/com/truecallersdk/Constants.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | package com.truecallersdk 32 | 33 | import androidx.annotation.Keep 34 | 35 | class Constants { 36 | companion object { 37 | //scope options 38 | const val SDK_OPTION = "sdkOption"; 39 | const val CONSENT_HEADING_OPTION = "consentHeadingOption"; 40 | const val LOGIN_TEXT_PRE = "loginTextPrefix"; 41 | const val CTA_TEXT_PRE = "ctaText"; 42 | const val FOOTER_TYPE = "footerType"; 43 | const val BTN_SHAPE = "buttonShapeOption"; 44 | const val BTN_CLR = "buttonColor"; 45 | const val BTN_TXT_CLR = "buttonTextColor"; 46 | const val LOCALE = "locale"; 47 | 48 | //oauth customization 49 | const val SCOPES = "scopes"; 50 | const val OAUTH_STATE = "oAuthState"; 51 | const val CODE_VERIFIER = "codeVerifier"; 52 | const val CODE_CHALLENGE = "codeChallenge"; 53 | 54 | //callback data 55 | const val RESULT = "result"; 56 | const val DATA = "data"; 57 | 58 | //tc callback 59 | const val SUCCESS = "success" 60 | const val FAILURE = "failure" 61 | const val VERIFICATION = "verification" 62 | 63 | //non-tc callback 64 | const val MISSED_CALL_INITIATED = "missedCallInitiated" 65 | const val MISSED_CALL_RECEIVED = "missedCallReceived" 66 | const val OTP_INITIATED = "otpInitiated" 67 | const val OTP_RECEIVED = "otpReceived" 68 | const val VERIFIED_BEFORE = "verifiedBefore" 69 | const val VERIFICATION_COMPLETE = "verificationComplete" 70 | const val EXCEPTION = "exception" 71 | 72 | //non-tc values 73 | const val PH_NO = "ph" 74 | const val COUNTRY_ISO = "ci" 75 | const val FIRST_NAME = "fname" 76 | const val LAST_NAME = "lname" 77 | const val OTP = "otp" 78 | } 79 | } 80 | 81 | @Keep 82 | data class CallbackData( 83 | val otp: String? = null, 84 | val ttl: String? = null, 85 | val accessToken: String? = null, 86 | val requestNonce: String? = null, 87 | val profile: String? = null, 88 | ) -------------------------------------------------------------------------------- /android/src/main/kotlin/com/truecallersdk/TruecallerSdkPlugin.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | package com.truecallersdk 32 | 33 | import android.app.Activity 34 | import android.content.Intent 35 | import androidx.annotation.NonNull 36 | import androidx.fragment.app.FragmentActivity 37 | import com.google.gson.Gson 38 | import com.truecaller.android.sdk.common.VerificationCallback 39 | import com.truecaller.android.sdk.common.VerificationDataBundle 40 | import com.truecaller.android.sdk.common.TrueException 41 | import com.truecaller.android.sdk.common.models.TrueProfile 42 | import com.truecaller.android.sdk.oAuth.CodeVerifierUtil 43 | import com.truecaller.android.sdk.oAuth.TcOAuthCallback 44 | import com.truecaller.android.sdk.oAuth.TcOAuthData 45 | import com.truecaller.android.sdk.oAuth.TcOAuthError 46 | import com.truecaller.android.sdk.oAuth.TcSdk 47 | import com.truecaller.android.sdk.oAuth.TcSdkOptions 48 | import io.flutter.embedding.engine.plugins.FlutterPlugin 49 | import io.flutter.embedding.engine.plugins.activity.ActivityAware 50 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding 51 | import io.flutter.plugin.common.BinaryMessenger 52 | import io.flutter.plugin.common.EventChannel 53 | import io.flutter.plugin.common.MethodCall 54 | import io.flutter.plugin.common.MethodChannel 55 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler 56 | import io.flutter.plugin.common.MethodChannel.Result 57 | import io.flutter.plugin.common.PluginRegistry 58 | import io.flutter.plugin.common.PluginRegistry.Registrar 59 | import java.util.Locale 60 | 61 | const val INITIALIZE_SDK = "initializeSDK" 62 | const val IS_OAUTH_FLOW_USABLE = "isOAuthFlowUsable" 63 | const val SET_LOCALE = "setLocale" 64 | const val GENERATE_RANDOM_CODE_VERIFIER = "generateRandomCodeVerifier" 65 | const val GENERATE_CODE_CHALLENGE = "generateCodeChallenge" 66 | const val SET_CODE_CHALLENGE = "setCodeChallenge" 67 | const val SET_OAUTH_SCOPES = "setOAuthScopes" 68 | const val SET_OAUTH_STATE = "setOAuthState" 69 | const val GET_AUTHORIZATION_CODE = "getAuthorizationCode" 70 | const val REQUEST_VERIFICATION = "requestVerification" 71 | const val VERIFY_OTP = "verifyOtp" 72 | const val VERIFY_MISSED_CALL = "verifyMissedCall" 73 | const val TC_METHOD_CHANNEL = "tc_method_channel" 74 | const val TC_EVENT_CHANNEL = "tc_event_channel" 75 | 76 | /** TruecallerSdkPlugin */ 77 | public class TruecallerSdkPlugin : FlutterPlugin, MethodCallHandler, EventChannel.StreamHandler, 78 | ActivityAware, PluginRegistry.ActivityResultListener { 79 | 80 | /** The MethodChannel that will the communication between Flutter and native Android 81 | * This local reference serves to register the plugin with the Flutter Engine and unregister it 82 | * when the Flutter Engine is detached from the Activity 83 | **/ 84 | private var methodChannel: MethodChannel? = null 85 | private var eventChannel: EventChannel? = null 86 | private var eventSink: EventChannel.EventSink? = null 87 | private var activity: Activity? = null 88 | private val gson = Gson() 89 | 90 | override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { 91 | onAttachedToEngine(flutterPluginBinding.binaryMessenger) 92 | } 93 | 94 | /**This static function is optional and equivalent to onAttachedToEngine. It supports the old 95 | * pre-Flutter-1.12 Android projects. You are encouraged to continue supporting 96 | * plugin registration via this function while apps migrate to use the new Android APIs 97 | * post-flutter-1.12 via https:flutter.dev/go/android-project-migration. 98 | * It is encouraged to share logic between onAttachedToEngine and registerWith to keep 99 | * them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called 100 | * depending on the user's project. onAttachedToEngine or registerWith must both be defined 101 | * in the same class. 102 | **/ 103 | companion object { 104 | @JvmStatic 105 | fun registerWith(registrar: Registrar) { 106 | val truecallerSdkPlugin = TruecallerSdkPlugin() 107 | truecallerSdkPlugin.activity = registrar.activity() 108 | truecallerSdkPlugin.onAttachedToEngine(registrar.messenger()) 109 | } 110 | } 111 | 112 | private fun onAttachedToEngine(messenger: BinaryMessenger) { 113 | methodChannel = MethodChannel(messenger, TC_METHOD_CHANNEL) 114 | methodChannel?.setMethodCallHandler(this) 115 | eventChannel = EventChannel(messenger, TC_EVENT_CHANNEL) 116 | eventChannel?.setStreamHandler(this) 117 | } 118 | 119 | override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { 120 | when (call.method) { 121 | INITIALIZE_SDK -> { 122 | getTcSdkOptions(call)?.let { TcSdk.init(it) } ?: result.error("UNAVAILABLE", "Activity not available.", null) 123 | } 124 | 125 | IS_OAUTH_FLOW_USABLE -> { 126 | result.success(TcSdk.getInstance() != null && TcSdk.getInstance().isOAuthFlowUsable) 127 | } 128 | 129 | SET_LOCALE -> { 130 | call.argument(Constants.LOCALE)?.let { 131 | TcSdk.getInstance().setLocale(Locale(it)) 132 | } 133 | } 134 | 135 | GENERATE_RANDOM_CODE_VERIFIER -> { 136 | result.success(CodeVerifierUtil.generateRandomCodeVerifier()) 137 | } 138 | 139 | GENERATE_CODE_CHALLENGE -> { 140 | call.argument(Constants.CODE_VERIFIER)?.let { 141 | result.success(CodeVerifierUtil.getCodeChallenge(it)) 142 | } 143 | } 144 | 145 | SET_CODE_CHALLENGE -> { 146 | call.argument(Constants.CODE_CHALLENGE)?.let { 147 | TcSdk.getInstance().setCodeChallenge(it) 148 | } 149 | } 150 | 151 | SET_OAUTH_SCOPES -> { 152 | call.argument>(Constants.SCOPES)?.let { 153 | TcSdk.getInstance().setOAuthScopes(it.toTypedArray()) 154 | } 155 | } 156 | 157 | SET_OAUTH_STATE -> { 158 | call.argument(Constants.OAUTH_STATE)?.let { 159 | TcSdk.getInstance().setOAuthState(it) 160 | } 161 | } 162 | 163 | GET_AUTHORIZATION_CODE -> { 164 | activity?.let { TcSdk.getInstance().getAuthorizationCode(it as FragmentActivity) } ?: result.error( 165 | "UNAVAILABLE", 166 | "Activity not available.", 167 | null 168 | ) 169 | } 170 | 171 | REQUEST_VERIFICATION -> { 172 | val phoneNumber = call.argument(Constants.PH_NO)?.takeUnless(String::isBlank) 173 | ?: return result.error("Invalid phone", "Can't be null or empty", null) 174 | val countryISO = call.argument(Constants.COUNTRY_ISO) ?: "IN" 175 | activity?.let { 176 | try { 177 | TcSdk.getInstance() 178 | .requestVerification(countryISO, phoneNumber, verificationCallback, it as FragmentActivity) 179 | } catch (e: RuntimeException) { 180 | result.error(e.message ?: "UNAVAILABLE", e.message ?: "UNAVAILABLE", null) 181 | } 182 | } 183 | ?: result.error("UNAVAILABLE", "Activity not available.", null) 184 | } 185 | 186 | VERIFY_OTP -> { 187 | val firstName = call.argument(Constants.FIRST_NAME)?.takeUnless(String::isBlank) 188 | ?: return result.error("Invalid name", "Can't be null or empty", null) 189 | val lastName = call.argument(Constants.LAST_NAME) ?: "" 190 | val trueProfile = TrueProfile.Builder(firstName, lastName).build() 191 | val otp = call.argument(Constants.OTP)?.takeUnless(String::isBlank) 192 | ?: return result.error("Invalid otp", "Can't be null or empty", null) 193 | TcSdk.getInstance().verifyOtp( 194 | trueProfile, 195 | otp, 196 | verificationCallback 197 | ) 198 | } 199 | 200 | VERIFY_MISSED_CALL -> { 201 | val firstName = call.argument(Constants.FIRST_NAME)?.takeUnless(String::isBlank) 202 | ?: return result.error("Invalid name", "Can't be null or empty", null) 203 | val lastName = call.argument(Constants.LAST_NAME) ?: "" 204 | val trueProfile = TrueProfile.Builder(firstName, lastName).build() 205 | TcSdk.getInstance().verifyMissedCall( 206 | trueProfile, 207 | verificationCallback 208 | ) 209 | } 210 | 211 | else -> { 212 | result.notImplemented() 213 | } 214 | } 215 | } 216 | 217 | private fun getTcSdkOptions(call: MethodCall): TcSdkOptions? { 218 | return activity?.let { 219 | TcSdkOptions.Builder(it, oAuthCallback) 220 | .sdkOptions(call.argument(Constants.SDK_OPTION) ?: TcSdkOptions.OPTION_VERIFY_ONLY_TC_USERS) 221 | .consentHeadingOption(call.argument(Constants.CONSENT_HEADING_OPTION) ?: TcSdkOptions.SDK_CONSENT_HEADING_LOG_IN_TO) 222 | .loginTextPrefix(call.argument(Constants.LOGIN_TEXT_PRE) ?: TcSdkOptions.LOGIN_TEXT_PREFIX_TO_GET_STARTED) 223 | .footerType(call.argument(Constants.FOOTER_TYPE) ?: TcSdkOptions.FOOTER_TYPE_ANOTHER_MOBILE_NO) 224 | .ctaText(call.argument(Constants.CTA_TEXT_PRE) ?: TcSdkOptions.CTA_TEXT_PROCEED) 225 | .buttonShapeOptions(call.argument(Constants.BTN_SHAPE) ?: TcSdkOptions.BUTTON_SHAPE_ROUNDED) 226 | .buttonColor(call.argument(Constants.BTN_CLR)?.toInt() ?: 0) 227 | .buttonTextColor(call.argument(Constants.BTN_TXT_CLR)?.toInt() ?: 0) 228 | .build() 229 | } 230 | } 231 | 232 | private val oAuthCallback: TcOAuthCallback = object : TcOAuthCallback { 233 | override fun onSuccess(tcOAuthData: TcOAuthData) { 234 | eventSink?.success( 235 | mapOf( 236 | Constants.RESULT to Constants.SUCCESS, 237 | Constants.DATA to gson.toJson(tcOAuthData) 238 | ) 239 | ) 240 | } 241 | 242 | override fun onFailure(tcOAuthError: TcOAuthError) { 243 | eventSink?.success( 244 | mapOf( 245 | Constants.RESULT to Constants.FAILURE, 246 | Constants.DATA to gson.toJson(tcOAuthError) 247 | ) 248 | ) 249 | } 250 | 251 | override fun onVerificationRequired(tcOAuthError: TcOAuthError?) { 252 | eventSink?.success( 253 | mapOf( 254 | Constants.RESULT to Constants.VERIFICATION, 255 | Constants.DATA to gson.toJson(tcOAuthError) 256 | ) 257 | ) 258 | } 259 | } 260 | 261 | private val verificationCallback: VerificationCallback = object : VerificationCallback { 262 | override fun onRequestSuccess(requestCode: Int, bundle: VerificationDataBundle?) { 263 | when (requestCode) { 264 | VerificationCallback.TYPE_MISSED_CALL_INITIATED -> { 265 | eventSink?.success( 266 | mapOf( 267 | Constants.RESULT to Constants.MISSED_CALL_INITIATED, 268 | Constants.DATA to gson.toJson( 269 | CallbackData( 270 | ttl = bundle?.getString(VerificationDataBundle.KEY_TTL), 271 | requestNonce = bundle?.getString(VerificationDataBundle.KEY_REQUEST_NONCE) 272 | ) 273 | ) 274 | ) 275 | ) 276 | } 277 | 278 | VerificationCallback.TYPE_MISSED_CALL_RECEIVED -> { 279 | eventSink?.success( 280 | mapOf( 281 | Constants.RESULT to Constants.MISSED_CALL_RECEIVED 282 | ) 283 | ) 284 | } 285 | 286 | VerificationCallback.TYPE_OTP_INITIATED -> { 287 | eventSink?.success( 288 | mapOf( 289 | Constants.RESULT to Constants.OTP_INITIATED, 290 | Constants.DATA to gson.toJson( 291 | CallbackData( 292 | ttl = bundle?.getString(VerificationDataBundle.KEY_TTL), 293 | requestNonce = bundle?.getString(VerificationDataBundle.KEY_REQUEST_NONCE) 294 | ) 295 | ) 296 | ) 297 | ) 298 | } 299 | 300 | VerificationCallback.TYPE_OTP_RECEIVED -> { 301 | eventSink?.success( 302 | mapOf( 303 | Constants.RESULT to Constants.OTP_RECEIVED, 304 | Constants.DATA to gson.toJson( 305 | CallbackData( 306 | otp = bundle?.getString(VerificationDataBundle.KEY_OTP) 307 | ) 308 | ) 309 | ) 310 | ) 311 | } 312 | 313 | VerificationCallback.TYPE_PROFILE_VERIFIED_BEFORE -> { 314 | eventSink?.success( 315 | mapOf( 316 | Constants.RESULT to Constants.VERIFIED_BEFORE, 317 | Constants.DATA to gson.toJson( 318 | CallbackData( 319 | profile = gson.toJson(bundle?.profile) 320 | ) 321 | ) 322 | ) 323 | ) 324 | } 325 | 326 | else -> { 327 | eventSink?.success( 328 | mapOf( 329 | Constants.RESULT to Constants.VERIFICATION_COMPLETE, 330 | Constants.DATA to gson.toJson( 331 | CallbackData( 332 | accessToken = bundle?.getString(VerificationDataBundle.KEY_ACCESS_TOKEN), 333 | requestNonce = bundle?.getString(VerificationDataBundle.KEY_REQUEST_NONCE) 334 | ) 335 | ) 336 | ) 337 | ) 338 | } 339 | } 340 | } 341 | 342 | override fun onRequestFailure(callbackType: Int, trueException: TrueException) { 343 | eventSink?.success( 344 | mapOf( 345 | Constants.RESULT to Constants.EXCEPTION, 346 | Constants.DATA to gson.toJson(trueException) 347 | ) 348 | ) 349 | } 350 | } 351 | 352 | override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink?) { 353 | this.eventSink = eventSink 354 | } 355 | 356 | override fun onCancel(arguments: Any?) { 357 | eventSink = null 358 | } 359 | 360 | override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { 361 | cleanUp() 362 | } 363 | 364 | override fun onAttachedToActivity(binding: ActivityPluginBinding) { 365 | this.activity = binding.activity 366 | binding.addActivityResultListener(this) 367 | } 368 | 369 | override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { 370 | this.activity = binding.activity 371 | binding.addActivityResultListener(this) 372 | } 373 | 374 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { 375 | return if (requestCode == TcSdk.SHARE_PROFILE_REQUEST_CODE) { 376 | TcSdk.getInstance().onActivityResultObtained(activity as FragmentActivity, requestCode, resultCode, data) 377 | } else false 378 | } 379 | 380 | override fun onDetachedFromActivity() { 381 | cleanUp() 382 | } 383 | 384 | override fun onDetachedFromActivityForConfigChanges() { 385 | cleanUp() 386 | } 387 | 388 | private fun cleanUp() { 389 | TcSdk.clear() 390 | activity = null 391 | methodChannel?.setMethodCallHandler(null) 392 | methodChannel = null 393 | eventChannel?.setStreamHandler(null) 394 | eventChannel = null 395 | eventSink = null 396 | } 397 | } 398 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Exceptions to above rules. 43 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 44 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 8af6b2f038c1172e61d418869363a28dffec3cb4 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # truecaller_sdk_example 2 | 3 | Demonstrates how to use the `truecaller_sdk` plugin. 4 | 5 | You can find 2 example implementations under [example/lib](lib) directory 6 | 7 | 1. [main.dart](https://github.com/truecaller/flutter-sdk/blob/master/example/lib/main.dart) - a very basic, crude implementation of 8 | `truecaller_sdk` plugin which would look like this - 9 | 10 | 11 | 12 | To run this file, just execute the following command after navigating to `/example` directory - 13 | 14 | ```flutter run --target=lib/main.dart``` 15 | 16 | 17 | 2. [main_customization_screen.dart](https://github.com/truecaller/flutter-sdk/blob/master/example/lib/customization/main_customization_screen.dart) - sample implementation that shows different customization options available for `truecaller_sdk` plugin which would look like this - 18 | 19 | 20 | 21 | To run this file, just execute the following command after navigating to `/example` directory - 22 | 23 | ```flutter run --target=lib/customization/main_customization_screen.dart``` 24 | 25 | 26 | ##### Note : If you run these examples and proceed with user verification, SDK would give you error code 3 which indicates an incorrect app key. So you need to replace the partnerKey in [AndroidManifest.xml](android/app/src/main/AndroidManifest.xml) with your own app key as mentioned in [step 2](/README.md) of `Steps to integrate` section. 27 | 28 | 29 | ## License 30 | 31 | [MIT-licensed](../LICENSE). 32 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | def localProperties = new Properties() 32 | def localPropertiesFile = rootProject.file('local.properties') 33 | if (localPropertiesFile.exists()) { 34 | localPropertiesFile.withReader('UTF-8') { reader -> 35 | localProperties.load(reader) 36 | } 37 | } 38 | 39 | def flutterRoot = localProperties.getProperty('flutter.sdk') 40 | if (flutterRoot == null) { 41 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 42 | } 43 | 44 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 45 | if (flutterVersionCode == null) { 46 | flutterVersionCode = '1' 47 | } 48 | 49 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 50 | if (flutterVersionName == null) { 51 | flutterVersionName = '1.0' 52 | } 53 | 54 | apply plugin: 'com.android.application' 55 | apply plugin: 'kotlin-android' 56 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 57 | 58 | android { 59 | compileSdkVersion 33 60 | 61 | sourceSets { 62 | main.java.srcDirs += 'src/main/kotlin' 63 | } 64 | 65 | defaultConfig { 66 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 67 | applicationId "com.example.truecaller_sdk_example" 68 | minSdkVersion 22 69 | targetSdkVersion 30 70 | versionCode flutterVersionCode.toInteger() 71 | versionName flutterVersionName 72 | } 73 | 74 | buildTypes { 75 | release { 76 | // TODO: Add your own signing config for the release build. 77 | // Signing with the debug keys for now, so `flutter run --release` works. 78 | signingConfig signingConfigs.debug 79 | } 80 | } 81 | lint { 82 | disable 'InvalidPackage' 83 | } 84 | } 85 | 86 | flutter { 87 | source '../..' 88 | } 89 | 90 | dependencies { 91 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 92 | } 93 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 30 | 31 | 33 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | 51 | 52 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 65 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/truecaller_sdk_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | package com.example.truecaller_sdk_example 32 | 33 | import io.flutter.embedding.android.FlutterActivityLaunchConfigs 34 | import io.flutter.embedding.android.FlutterFragmentActivity 35 | import io.flutter.embedding.engine.FlutterEngine 36 | import io.flutter.plugins.GeneratedPluginRegistrant 37 | 38 | class MainActivity : FlutterFragmentActivity() { 39 | override fun configureFlutterEngine(flutterEngine: FlutterEngine) { 40 | GeneratedPluginRegistrant.registerWith(flutterEngine) 41 | } 42 | 43 | override fun getBackgroundMode(): FlutterActivityLaunchConfigs.BackgroundMode { 44 | return FlutterActivityLaunchConfigs.BackgroundMode.transparent 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 41 | 42 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 30 | 31 | 32 | 33 | 38 | 44 | 47 | 48 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 30 | 31 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | buildscript { 32 | ext.kotlin_version = '1.8.22' 33 | repositories { 34 | google() 35 | mavenCentral() 36 | } 37 | 38 | dependencies { 39 | classpath 'com.android.tools.build:gradle:7.4.2' 40 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 41 | } 42 | } 43 | 44 | allprojects { 45 | repositories { 46 | google() 47 | mavenCentral() 48 | } 49 | } 50 | 51 | rootProject.buildDir = '../build' 52 | subprojects { 53 | project.buildDir = "${rootProject.buildDir}/${project.name}" 54 | } 55 | subprojects { 56 | project.evaluationDependsOn(':app') 57 | } 58 | 59 | tasks.register("clean", Delete) { 60 | delete rootProject.buildDir 61 | } 62 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | # 4 | # Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | # 6 | # Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | # 8 | # In accordance with the Truecaller SDK Agreement available 9 | # here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | # accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | # limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | # Truecaller SDK Product in object code form only, solely for the purpose of using 13 | # the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | # 15 | # THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | # WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | # TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | # SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | # EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | # OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | # OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | # POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | # PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | # 30 | org.gradle.jvmargs=-Xmx1536M 31 | android.useAndroidX=true 32 | android.enableJetifier=true 33 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Aug 03 12:58:09 IST 2022 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | include ':app' 6 | 7 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 8 | def properties = new Properties() 9 | 10 | assert localPropertiesFile.exists() 11 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 12 | 13 | def flutterSdkPath = properties.getProperty("flutter.sdk") 14 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 15 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 16 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - truecaller_sdk (0.0.1): 4 | - Flutter 5 | - TrueSDK 6 | - TrueSDK (0.1.8) 7 | 8 | DEPENDENCIES: 9 | - Flutter (from `Flutter`) 10 | - truecaller_sdk (from `.symlinks/plugins/truecaller_sdk/ios`) 11 | 12 | SPEC REPOS: 13 | trunk: 14 | - TrueSDK 15 | 16 | EXTERNAL SOURCES: 17 | Flutter: 18 | :path: Flutter 19 | truecaller_sdk: 20 | :path: ".symlinks/plugins/truecaller_sdk/ios" 21 | 22 | SPEC CHECKSUMS: 23 | Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a 24 | truecaller_sdk: 08d7553ccf979fe1bdc512261edac15c087176d7 25 | TrueSDK: 6845b0387144212913ec8fd851f4a57998c1ea21 26 | 27 | PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c 28 | 29 | COCOAPODS: 1.11.2 30 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | import truecaller_sdk 4 | import TrueSDK 5 | 6 | @UIApplicationMain 7 | @objc class AppDelegate: FlutterAppDelegate { 8 | override func application( 9 | _ application: UIApplication, 10 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 11 | ) -> Bool { 12 | GeneratedPluginRegistrant.register(with: self) 13 | 14 | TCTrueSDK.sharedManager().setup(withAppKey: "I7ViZ490028736bba408881687123b4cec49f", 15 | appLink: "https://si9f1dc18a1d0041efa219162d27d1c865.truecallerdevs.com") 16 | 17 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | truecaller_sdk_example 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleURLTypes 24 | 25 | 26 | CFBundleTypeRole 27 | Editor 28 | CFBundleURLSchemes 29 | 30 | truecallersdk-I7ViZ490028736bba408881687123b4cec49f 31 | 32 | 33 | 34 | CFBundleVersion 35 | $(FLUTTER_BUILD_NUMBER) 36 | LSApplicationQueriesSchemes 37 | 38 | truesdk 39 | 40 | LSRequiresIPhoneOS 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIMainStoryboardFile 45 | Main 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UISupportedInterfaceOrientations~ipad 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationPortraitUpsideDown 56 | UIInterfaceOrientationLandscapeLeft 57 | UIInterfaceOrientationLandscapeRight 58 | 59 | UIViewControllerBasedStatusBarAppearance 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.associated-domains 6 | 7 | applinks:si9f1dc18a1d0041efa219162d27d1c865.truecallerdevs.com 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/lib/customization/config_options.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | import 'package:flutter/material.dart'; 32 | import 'package:truecaller_sdk/truecaller_sdk.dart'; 33 | 34 | class HeadingOption { 35 | static List getHeadingOptions() { 36 | return [ 37 | "Login", 38 | "Signup", 39 | "Signin", 40 | "Verify", 41 | "Register", 42 | "Get Started", 43 | "Proceed with", 44 | "Verify with", 45 | "Verify profile with", 46 | "Verify your profile with", 47 | "Verify phone number with", 48 | "Verify your number with", 49 | "Continue with", 50 | "Complete order with", 51 | "Place order with", 52 | "Complete booking with", 53 | "Checkout with", 54 | "Manage details with", 55 | "Manage your details with", 56 | "Login to %s with one tap", 57 | "Subscribe to", 58 | "Get updates from", 59 | "Continue reading on", 60 | "Get new updates from", 61 | "Login/Signup with" 62 | ]; 63 | } 64 | } 65 | 66 | class FooterOption { 67 | String name; 68 | 69 | FooterOption(this.name); 70 | 71 | static Map getFooterOptionsMap() { 72 | return { 73 | TcSdkOptions.FOOTER_TYPE_ANOTHER_MOBILE_NO: "Use Another Number", 74 | TcSdkOptions.FOOTER_TYPE_ANOTHER_METHOD: "Use Another Method", 75 | TcSdkOptions.FOOTER_TYPE_MANUALLY: "Enter Details Manually", 76 | TcSdkOptions.FOOTER_TYPE_LATER: "I'll do later", 77 | TcSdkOptions.FOOTER_TYPE_SKIP: "Skip", 78 | }; 79 | } 80 | } 81 | 82 | class ConfigOptions { 83 | static Map getColorList() { 84 | return { 85 | "green": Colors.green.value, 86 | "white": Colors.white.value, 87 | "red": Colors.red.value, 88 | "blue": Colors.blue.value, 89 | "black": Colors.black.value, 90 | "grey": Colors.grey.value, 91 | "cyan": Colors.cyan.value, 92 | "brown": Colors.brown.value, 93 | "yellow": Colors.yellow.value, 94 | "lime": Colors.lime.value, 95 | "purple": Colors.purple.value, 96 | "pink": Colors.pink.value, 97 | "deepOrange": Colors.deepOrange.value, 98 | "indigo": Colors.indigo.value, 99 | "teal": Colors.teal.value, 100 | }; 101 | } 102 | 103 | static List getCtaPrefixOptions() { 104 | return [ 105 | "Proceed", 106 | "Continue", 107 | "Accept", 108 | "Confirm", 109 | "Use %s", 110 | "Continue with %s", 111 | "Proceed with %s" 112 | ]; 113 | } 114 | } 115 | 116 | class AccessTokenHelper { 117 | final TcOAuthData tcOAuthData; 118 | final String codeVerifier; 119 | 120 | AccessTokenHelper(this.tcOAuthData, this.codeVerifier); 121 | } 122 | -------------------------------------------------------------------------------- /example/lib/customization/main_customization_screen.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | import 'dart:async'; 32 | 33 | import 'package:flutter/material.dart'; 34 | import 'package:truecaller_sdk/truecaller_sdk.dart'; 35 | import 'package:truecaller_sdk_example/customization/oauth_result_screen.dart'; 36 | import 'package:truecaller_sdk_example/non_tc_screen.dart'; 37 | import 'package:uuid/uuid.dart'; 38 | 39 | import 'config_options.dart'; 40 | 41 | // This screen shows different customization options available in Truecaller SDK 42 | 43 | void main() { 44 | runApp(OptionsConfiguration()); 45 | } 46 | 47 | class OptionsConfiguration extends StatefulWidget { 48 | @override 49 | _OptionsConfigurationState createState() => _OptionsConfigurationState(); 50 | } 51 | 52 | class _OptionsConfigurationState extends State { 53 | @override 54 | Widget build(BuildContext context) { 55 | return MaterialApp( 56 | title: "TC SDK Demo", 57 | debugShowCheckedModeBanner: false, 58 | home: HomePage()); 59 | } 60 | } 61 | 62 | class HomePage extends StatefulWidget { 63 | @override 64 | _HomePageState createState() => _HomePageState(); 65 | } 66 | 67 | class _HomePageState extends State { 68 | late int selectedFooter; 69 | late bool rectangularBtn, verifyAllUsers; 70 | late String? codeVerifier; 71 | List> colorMenuItemList = []; 72 | List> ctaPrefixMenuItemList = []; 73 | List> headingMenuItemList = []; 74 | late int ctaColor, ctaTextColor; 75 | late int ctaPrefixOption, headingOption; 76 | final TextEditingController localeController = TextEditingController(); 77 | late StreamSubscription? streamSubscription; 78 | 79 | @override 80 | void initState() { 81 | super.initState(); 82 | createStreamBuilder(); 83 | selectedFooter = FooterOption.getFooterOptionsMap().keys.first; 84 | rectangularBtn = false; 85 | verifyAllUsers = false; 86 | ctaColor = Colors.blue.value; 87 | ctaTextColor = Colors.white.value; 88 | ctaPrefixOption = 0; 89 | headingOption = 0; 90 | 91 | for (String key in ConfigOptions.getColorList().keys) { 92 | colorMenuItemList.add(DropdownMenuItem( 93 | value: ConfigOptions.getColorList()[key], 94 | child: Text("$key"), 95 | )); 96 | } 97 | 98 | for (int i = 0; i < ConfigOptions.getCtaPrefixOptions().length; i++) { 99 | ctaPrefixMenuItemList.add(DropdownMenuItem( 100 | value: i, 101 | child: Text("${ConfigOptions.getCtaPrefixOptions()[i]}"), 102 | )); 103 | } 104 | 105 | for (int i = 0; i < HeadingOption.getHeadingOptions().length; i++) { 106 | headingMenuItemList.add(DropdownMenuItem( 107 | value: i, 108 | child: Text("${HeadingOption.getHeadingOptions()[i]}"), 109 | )); 110 | } 111 | } 112 | 113 | List createRadioListFooterOptions() { 114 | List widgets = []; 115 | for (int key in FooterOption.getFooterOptionsMap().keys) { 116 | widgets.add( 117 | RadioListTile( 118 | value: key, 119 | groupValue: selectedFooter, 120 | title: Text("${FooterOption.getFooterOptionsMap()[key]}"), 121 | onChanged: (dynamic currentOption) { 122 | setSelectedFooter(currentOption); 123 | }, 124 | selected: selectedFooter == key, 125 | activeColor: Colors.green, 126 | ), 127 | ); 128 | } 129 | return widgets; 130 | } 131 | 132 | setSelectedFooter(int option) { 133 | setState(() { 134 | selectedFooter = option; 135 | }); 136 | } 137 | 138 | @override 139 | Widget build(BuildContext context) { 140 | return Scaffold( 141 | appBar: AppBar( 142 | title: Text("Configure SDK options"), 143 | ), 144 | body: SingleChildScrollView( 145 | child: Padding( 146 | padding: const EdgeInsets.all(16.0), 147 | child: Container( 148 | child: Column( 149 | children: [ 150 | Text( 151 | "Customization Options", 152 | style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0), 153 | ), 154 | Column( 155 | children: createConfigOptions(), 156 | ), 157 | Divider( 158 | color: Colors.transparent, 159 | height: 20.0, 160 | ), 161 | Text( 162 | "Footer Options", 163 | style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0), 164 | ), 165 | Divider( 166 | color: Colors.transparent, 167 | height: 20.0, 168 | ), 169 | Column( 170 | children: createRadioListFooterOptions(), 171 | ), 172 | Padding( 173 | padding: const EdgeInsets.only( 174 | left: 16.0, right: 16.0, top: 10.0, bottom: 10.0), 175 | child: TextField( 176 | controller: localeController, 177 | maxLength: 2, 178 | style: TextStyle( 179 | color: Colors.green, 180 | ), 181 | decoration: InputDecoration( 182 | labelText: "Enter Locale", 183 | labelStyle: 184 | TextStyle(color: Colors.black, fontSize: 16.0), 185 | hintText: 186 | "Example: en(default), hi, kn, ta, te, mr, etc.", 187 | hintStyle: TextStyle( 188 | fontStyle: FontStyle.italic, 189 | color: Colors.green, 190 | fontSize: 14.0)), 191 | ), 192 | ), 193 | SwitchListTile( 194 | title: Text("Verify all users"), 195 | value: verifyAllUsers, 196 | onChanged: (value) { 197 | setState(() { 198 | verifyAllUsers = value; 199 | }); 200 | }, 201 | selected: verifyAllUsers, 202 | activeColor: Colors.green, 203 | ), 204 | Divider( 205 | color: Colors.transparent, 206 | height: 20.0, 207 | ), 208 | MaterialButton( 209 | height: 45.0, 210 | child: Text( 211 | "LET'S GO", 212 | style: TextStyle( 213 | color: Colors.white, 214 | ), 215 | ), 216 | color: Colors.blue, 217 | onPressed: () { 218 | initializeSdk(); 219 | }, 220 | ) 221 | ], 222 | ), 223 | ), 224 | ), 225 | ), 226 | ); 227 | } 228 | 229 | createConfigOptions() { 230 | return [ 231 | Divider( 232 | color: Colors.transparent, 233 | height: 20.0, 234 | ), 235 | SwitchListTile( 236 | title: Text("Rectangular Button"), 237 | value: rectangularBtn, 238 | onChanged: (value) { 239 | setState(() { 240 | rectangularBtn = value; 241 | }); 242 | }, 243 | selected: rectangularBtn, 244 | activeColor: Colors.green, 245 | ), 246 | Divider( 247 | color: Colors.transparent, 248 | height: 10.0, 249 | ), 250 | Padding( 251 | padding: const EdgeInsets.only(left: 16.0, right: 16.0), 252 | child: DropdownButtonFormField( 253 | decoration: InputDecoration( 254 | labelText: "CTA color", 255 | labelStyle: TextStyle(color: Colors.black, fontSize: 16.0), 256 | ), 257 | style: TextStyle(color: Colors.green), 258 | value: ctaColor, 259 | isExpanded: true, 260 | items: colorMenuItemList, 261 | onChanged: (value) { 262 | setState(() { 263 | ctaColor = value!; 264 | }); 265 | }), 266 | ), 267 | Divider( 268 | color: Colors.transparent, 269 | height: 10.0, 270 | ), 271 | Padding( 272 | padding: const EdgeInsets.only(left: 16.0, right: 16.0), 273 | child: DropdownButtonFormField( 274 | decoration: InputDecoration( 275 | labelText: "CTA text color", 276 | labelStyle: TextStyle(color: Colors.black, fontSize: 16.0), 277 | ), 278 | style: TextStyle(color: Colors.green), 279 | value: ctaTextColor, 280 | isExpanded: true, 281 | items: colorMenuItemList, 282 | onChanged: (value) { 283 | setState(() { 284 | ctaTextColor = value!; 285 | }); 286 | }), 287 | ), 288 | Divider( 289 | color: Colors.transparent, 290 | height: 10.0, 291 | ), 292 | Padding( 293 | padding: const EdgeInsets.only(left: 16.0, right: 16.0), 294 | child: DropdownButtonFormField( 295 | decoration: InputDecoration( 296 | labelText: "CTA Prefix", 297 | labelStyle: TextStyle(color: Colors.black, fontSize: 16.0), 298 | ), 299 | style: TextStyle(color: Colors.green), 300 | value: ctaPrefixOption, 301 | isExpanded: true, 302 | items: ctaPrefixMenuItemList, 303 | onChanged: (value) { 304 | setState(() { 305 | ctaPrefixOption = value!; 306 | }); 307 | }), 308 | ), 309 | Divider( 310 | color: Colors.transparent, 311 | height: 10.0, 312 | ), 313 | Padding( 314 | padding: const EdgeInsets.only(left: 16.0, right: 16.0), 315 | child: DropdownButtonFormField( 316 | decoration: InputDecoration( 317 | labelText: "Heading options", 318 | labelStyle: TextStyle(color: Colors.black, fontSize: 16.0), 319 | ), 320 | style: TextStyle(color: Colors.green), 321 | value: headingOption, 322 | isExpanded: true, 323 | items: headingMenuItemList, 324 | onChanged: (value) { 325 | setState(() { 326 | headingOption = value!; 327 | }); 328 | }), 329 | ), 330 | Divider( 331 | color: Colors.transparent, 332 | height: 10.0, 333 | ), 334 | ]; 335 | } 336 | 337 | void initializeSdk() { 338 | _hideKeyboard(); 339 | TcSdk.initializeSDK( 340 | sdkOption: verifyAllUsers 341 | ? TcSdkOptions.OPTION_VERIFY_ALL_USERS 342 | : TcSdkOptions.OPTION_VERIFY_ONLY_TC_USERS, 343 | consentHeadingOption: headingOption, 344 | footerType: selectedFooter, 345 | ctaText: ctaPrefixOption, 346 | buttonShapeOption: rectangularBtn 347 | ? TcSdkOptions.BUTTON_SHAPE_RECTANGLE 348 | : TcSdkOptions.BUTTON_SHAPE_ROUNDED, 349 | buttonColor: ctaColor, 350 | buttonTextColor: ctaTextColor); 351 | 352 | TcSdk.isOAuthFlowUsable.then((isOAuthFlowUsable) { 353 | if (isOAuthFlowUsable) { 354 | TcSdk.setOAuthState(Uuid().v1()); 355 | TcSdk.setOAuthScopes(['profile', 'phone', 'openid', 'offline_access']); 356 | if (localeController.text.isNotEmpty) { 357 | TcSdk.setLocale(localeController.text); 358 | } 359 | TcSdk.generateRandomCodeVerifier.then((codeVerifier) { 360 | TcSdk.generateCodeChallenge(codeVerifier).then((codeChallenge) { 361 | if (codeChallenge != null) { 362 | this.codeVerifier = codeVerifier; 363 | TcSdk.setCodeChallenge(codeChallenge); 364 | TcSdk.getAuthorizationCode; 365 | } else { 366 | final snackBar = SnackBar(content: Text("Device not supported")); 367 | ScaffoldMessenger.of(context).showSnackBar(snackBar); 368 | print("***Code challenge NULL***"); 369 | } 370 | }); 371 | }); 372 | } else { 373 | print("****Not usable****"); 374 | } 375 | }); 376 | } 377 | 378 | void createStreamBuilder() { 379 | streamSubscription = 380 | TcSdk.streamCallbackData.listen((truecallerSdkCallback) { 381 | switch (truecallerSdkCallback.result) { 382 | case TcSdkCallbackResult.success: 383 | Navigator.push( 384 | context, 385 | MaterialPageRoute( 386 | builder: (context) => OAuthResultScreen(), 387 | settings: RouteSettings( 388 | arguments: AccessTokenHelper( 389 | truecallerSdkCallback.tcOAuthData!, codeVerifier!), 390 | ), 391 | )); 392 | break; 393 | case TcSdkCallbackResult.failure: 394 | final snackBar = SnackBar( 395 | content: Text("${truecallerSdkCallback.error!.code} : " 396 | "${truecallerSdkCallback.error!.message}")); 397 | ScaffoldMessenger.of(context).showSnackBar(snackBar); 398 | break; 399 | case TcSdkCallbackResult.verification: 400 | Navigator.push( 401 | context, 402 | MaterialPageRoute( 403 | builder: (context) => NonTcVerification(), 404 | )); 405 | break; 406 | default: 407 | print("Invalid result"); 408 | } 409 | }); 410 | } 411 | 412 | _hideKeyboard() { 413 | FocusManager.instance.primaryFocus!.unfocus(); 414 | } 415 | 416 | @override 417 | void dispose() { 418 | localeController.dispose(); 419 | streamSubscription?.cancel(); 420 | super.dispose(); 421 | } 422 | } 423 | -------------------------------------------------------------------------------- /example/lib/customization/oauth_result_screen.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | import 'package:dio/dio.dart'; 32 | import 'package:flutter/material.dart'; 33 | 34 | import 'config_options.dart'; 35 | 36 | class OAuthResultScreen extends StatefulWidget { 37 | @override 38 | State createState() { 39 | return _MyAppState(); 40 | } 41 | } 42 | 43 | class _MyAppState extends State { 44 | late final Dio dio = Dio(); 45 | late String accessToken = ""; 46 | late String accessTokenResponse = ""; 47 | late String userInfoResponse = ""; 48 | 49 | @override 50 | Widget build(BuildContext context) { 51 | final accessTokenHelper = 52 | ModalRoute.of(context)!.settings.arguments as AccessTokenHelper; 53 | return MaterialApp( 54 | home: Scaffold( 55 | appBar: AppBar( 56 | title: const Text('OAuth Result'), 57 | ), 58 | body: SingleChildScrollView( 59 | child: Container( 60 | child: Padding( 61 | padding: const EdgeInsets.all(16.0), 62 | child: Column( 63 | children: [ 64 | SelectableText( 65 | "Auth Code: ${accessTokenHelper.tcOAuthData.authorizationCode}", 66 | style: TextStyle(fontSize: 14.0), 67 | textAlign: TextAlign.center, 68 | ), 69 | Divider( 70 | color: Colors.transparent, 71 | height: 20.0, 72 | ), 73 | SelectableText( 74 | "OAuth State: ${accessTokenHelper.tcOAuthData.state}", 75 | style: TextStyle(fontSize: 14.0), 76 | textAlign: TextAlign.left, 77 | ), 78 | Divider( 79 | color: Colors.transparent, 80 | height: 20.0, 81 | ), 82 | SelectableText( 83 | "Scopes granted: ${accessTokenHelper.tcOAuthData.scopesGranted}", 84 | style: TextStyle(fontSize: 14.0), 85 | textAlign: TextAlign.left, 86 | ), 87 | Divider( 88 | color: Colors.transparent, 89 | height: 20.0, 90 | ), 91 | MaterialButton( 92 | height: 45.0, 93 | child: Text( 94 | "Fetch Access Token", 95 | style: TextStyle( 96 | color: Colors.white, 97 | ), 98 | ), 99 | color: Colors.blue, 100 | onPressed: () { 101 | fetchAccessToken(accessTokenHelper); 102 | }, 103 | ), 104 | Divider( 105 | color: Colors.transparent, 106 | height: 20.0, 107 | ), 108 | SelectableText( 109 | accessTokenResponse.isEmpty 110 | ? "" 111 | : "Access Token Response: $accessTokenResponse", 112 | style: TextStyle(fontSize: 12.0), 113 | textAlign: TextAlign.left, 114 | ), 115 | Divider( 116 | color: Colors.transparent, 117 | height: 20.0, 118 | ), 119 | Visibility( 120 | visible: accessToken.isNotEmpty, 121 | child: MaterialButton( 122 | height: 45.0, 123 | child: Text( 124 | "Fetch User Info", 125 | style: TextStyle( 126 | color: Colors.white, 127 | ), 128 | ), 129 | color: Colors.blue, 130 | onPressed: () { 131 | fetchUserInfo(); 132 | }, 133 | ), 134 | ), 135 | Divider( 136 | color: Colors.transparent, 137 | height: 20.0, 138 | ), 139 | SelectableText( 140 | userInfoResponse.isEmpty 141 | ? "" 142 | : "User Info Response: $userInfoResponse", 143 | style: TextStyle(fontSize: 14.0), 144 | textAlign: TextAlign.left, 145 | ), 146 | Divider( 147 | color: Colors.transparent, 148 | height: 20.0, 149 | ), 150 | ], 151 | ), 152 | ), 153 | ), 154 | ), 155 | )); 156 | } 157 | 158 | void fetchAccessToken(AccessTokenHelper accessTokenHelper) async { 159 | try { 160 | Response response; 161 | response = 162 | await dio.post('https://oauth-account-noneu.truecaller.com/v1/token', 163 | data: { 164 | 'grant_type': 'authorization_code', 165 | 'client_id': '1si1lk7rbbo_mtg29mw5yczekv2ripbbnwnaozhpz6o', 166 | 'code': '${accessTokenHelper.tcOAuthData.authorizationCode}', 167 | 'code_verifier': '${accessTokenHelper.codeVerifier}' 168 | }, 169 | options: Options(contentType: Headers.formUrlEncodedContentType)); 170 | if (response.statusCode == 200 && response.data != null) { 171 | Map result = response.data; 172 | accessToken = result['access_token']; 173 | setState(() { 174 | for (final e in result.entries) { 175 | accessTokenResponse = 176 | accessTokenResponse + "\n\n" + ('${e.key} = ${e.value}'); 177 | } 178 | }); 179 | } 180 | } on DioException catch (e) { 181 | print(e.toString()); 182 | setState(() { 183 | accessTokenResponse = e.toString(); 184 | }); 185 | } 186 | } 187 | 188 | void fetchUserInfo() async { 189 | try { 190 | userInfoResponse = ""; 191 | Response response; 192 | response = await dio.get( 193 | 'https://oauth-account-noneu.truecaller.com/v1/userinfo', 194 | options: Options(headers: {"Authorization": "Bearer $accessToken"})); 195 | if (response.statusCode == 200 && response.data != null) { 196 | Map result = response.data; 197 | setState(() { 198 | for (final e in result.entries) { 199 | userInfoResponse = 200 | userInfoResponse + "\n\n" + ('${e.key} = ${e.value}'); 201 | } 202 | }); 203 | } 204 | } on DioException catch (e) { 205 | print(e.toString()); 206 | setState(() { 207 | userInfoResponse = e.toString(); 208 | }); 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /example/lib/customization/result_screen.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | import 'package:flutter/material.dart'; 32 | 33 | class ResultScreen extends StatelessWidget { 34 | final String result; 35 | 36 | ResultScreen(this.result); 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return Scaffold( 41 | appBar: AppBar( 42 | title: Text("Result Page"), 43 | ), 44 | body: Center( 45 | child: Text( 46 | "$result!", 47 | style: TextStyle(fontSize: 20.0, letterSpacing: 5.0), 48 | ), 49 | ), 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | import 'package:flutter/material.dart'; 32 | import 'package:truecaller_sdk/truecaller_sdk.dart'; 33 | import 'package:truecaller_sdk_example/non_tc_screen.dart'; 34 | import 'package:uuid/uuid.dart'; 35 | 36 | import 'customization/config_options.dart'; 37 | import 'customization/oauth_result_screen.dart'; 38 | 39 | void main() { 40 | runApp(MyApp()); 41 | } 42 | 43 | class MyApp extends StatefulWidget { 44 | @override 45 | _MyAppState createState() => _MyAppState(); 46 | } 47 | 48 | class _MyAppState extends State { 49 | late Stream? _stream; 50 | late String? codeVerifier; 51 | 52 | @override 53 | void initState() { 54 | super.initState(); 55 | _stream = TcSdk.streamCallbackData; 56 | } 57 | 58 | @override 59 | Widget build(BuildContext context) { 60 | return MaterialApp( 61 | home: Scaffold( 62 | appBar: AppBar( 63 | title: const Text('Truecaller SDK example'), 64 | ), 65 | body: Center( 66 | child: Column( 67 | mainAxisSize: MainAxisSize.max, 68 | mainAxisAlignment: MainAxisAlignment.center, 69 | children: [ 70 | MaterialButton( 71 | onPressed: () { 72 | TcSdk.initializeSDK( 73 | sdkOption: TcSdkOptions.OPTION_VERIFY_ALL_USERS); 74 | TcSdk.isOAuthFlowUsable.then((isOAuthFlowUsable) { 75 | if (isOAuthFlowUsable) { 76 | TcSdk.setOAuthState(Uuid().v1()); 77 | TcSdk.setOAuthScopes( 78 | ['profile', 'phone', 'openid', 'offline_access']); 79 | TcSdk.generateRandomCodeVerifier.then((codeVerifier) { 80 | TcSdk.generateCodeChallenge(codeVerifier) 81 | .then((codeChallenge) { 82 | if (codeChallenge != null) { 83 | this.codeVerifier = codeVerifier; 84 | TcSdk.setCodeChallenge(codeChallenge); 85 | TcSdk.getAuthorizationCode; 86 | } else { 87 | final snackBar = SnackBar( 88 | content: Text("Device not supported")); 89 | ScaffoldMessenger.of(context) 90 | .showSnackBar(snackBar); 91 | print("***Code challenge NULL***"); 92 | } 93 | }); 94 | }); 95 | } else { 96 | final snackBar = SnackBar(content: Text("Not Usable")); 97 | ScaffoldMessenger.of(context).showSnackBar(snackBar); 98 | print("***Not usable***"); 99 | } 100 | }); 101 | }, 102 | child: Text( 103 | "Initialize SDK & Get Authorization Code", 104 | style: TextStyle(color: Colors.white), 105 | ), 106 | color: Colors.blue, 107 | ), 108 | Divider( 109 | color: Colors.transparent, 110 | height: 20.0, 111 | ), 112 | StreamBuilder( 113 | stream: _stream, 114 | builder: (context, snapshot) { 115 | if (snapshot.hasData) { 116 | switch (snapshot.data!.result) { 117 | case TcSdkCallbackResult.success: 118 | return MaterialButton( 119 | color: Colors.green, 120 | child: Text( 121 | "Go to OAuth Result", 122 | style: TextStyle(color: Colors.white), 123 | ), 124 | onPressed: () { 125 | Navigator.push( 126 | context, 127 | MaterialPageRoute( 128 | builder: (context) => 129 | OAuthResultScreen(), 130 | settings: RouteSettings( 131 | arguments: AccessTokenHelper( 132 | snapshot.data!.tcOAuthData!, 133 | codeVerifier!), 134 | ), 135 | )); 136 | }); 137 | case TcSdkCallbackResult.failure: 138 | return Text( 139 | "${snapshot.data!.error!.code} : ${snapshot.data!.error!.message}"); 140 | case TcSdkCallbackResult.verification: 141 | return Column( 142 | children: [ 143 | Text("Verification Required : " 144 | "${snapshot.data!.error != null ? snapshot.data!.error!.code : ""}"), 145 | MaterialButton( 146 | color: Colors.green, 147 | onPressed: () { 148 | Navigator.push( 149 | context, 150 | MaterialPageRoute( 151 | builder: (context) => 152 | NonTcVerification())); 153 | }, 154 | child: Text( 155 | "Do manual verification", 156 | style: TextStyle(color: Colors.white), 157 | ), 158 | ) 159 | ], 160 | ); 161 | default: 162 | return Text("Invalid result"); 163 | } 164 | } else 165 | return Text(""); 166 | }), 167 | ], 168 | ), 169 | )), 170 | ); 171 | } 172 | 173 | @override 174 | void dispose() { 175 | _stream = null; 176 | super.dispose(); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /example/lib/non_tc_screen.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | import 'dart:async'; 32 | 33 | import 'package:flutter/material.dart'; 34 | import 'package:flutter/services.dart'; 35 | import 'package:permission_handler/permission_handler.dart'; 36 | import 'package:truecaller_sdk/truecaller_sdk.dart'; 37 | 38 | import 'customization/result_screen.dart'; 39 | 40 | void main() { 41 | runApp(NonTcVerification()); 42 | } 43 | 44 | class NonTcVerification extends StatefulWidget { 45 | @override 46 | _NonTcVerificationState createState() => _NonTcVerificationState(); 47 | } 48 | 49 | class _NonTcVerificationState extends State { 50 | @override 51 | Widget build(BuildContext context) { 52 | return HomePage(); 53 | } 54 | } 55 | 56 | class HomePage extends StatefulWidget { 57 | @override 58 | _HomePageState createState() => _HomePageState(); 59 | } 60 | 61 | class _HomePageState extends State { 62 | bool invalidNumber = false; 63 | bool invalidFName = false; 64 | bool invalidOtp = false; 65 | bool showProgressBar = false; 66 | TextEditingController phoneController = TextEditingController(); 67 | TextEditingController fNameController = TextEditingController(); 68 | TextEditingController lNameController = TextEditingController(); 69 | TextEditingController otpController = TextEditingController(); 70 | late StreamSubscription? streamSubscription; 71 | TcSdkCallbackResult? tempResult; 72 | Timer? _timer; 73 | int? _ttl; 74 | 75 | @override 76 | void initState() { 77 | super.initState(); 78 | createStreamBuilder(); 79 | } 80 | 81 | bool showInputNumberView() { 82 | return tempResult == null; 83 | } 84 | 85 | bool showInputNameView() { 86 | return tempResult != null && 87 | (tempResult == TcSdkCallbackResult.missedCallReceived || 88 | showInputOtpView()); 89 | } 90 | 91 | bool showInputOtpView() { 92 | return tempResult != null && 93 | ((tempResult == TcSdkCallbackResult.otpInitiated) || 94 | (tempResult == TcSdkCallbackResult.otpReceived)); 95 | } 96 | 97 | bool showRetryTextView() { 98 | return _ttl != null && !showInputNumberView(); 99 | } 100 | 101 | @override 102 | Widget build(BuildContext context) { 103 | final double width = MediaQuery.of(context).size.width; 104 | const double fontSize = 18.0; 105 | return Scaffold( 106 | appBar: AppBar( 107 | title: Text("Verify User Manually"), 108 | ), 109 | body: Padding( 110 | padding: EdgeInsets.all(20.0), 111 | child: Column( 112 | mainAxisAlignment: MainAxisAlignment.center, 113 | children: [ 114 | Visibility( 115 | visible: showProgressBar, 116 | child: CircularProgressIndicator( 117 | strokeWidth: 6.0, 118 | backgroundColor: Colors.grey, 119 | valueColor: AlwaysStoppedAnimation(Colors.green), 120 | ), 121 | ), 122 | Visibility( 123 | visible: showInputNumberView(), 124 | child: TextField( 125 | controller: phoneController, 126 | maxLength: 10, 127 | keyboardType: TextInputType.number, 128 | inputFormatters: [FilteringTextInputFormatter.digitsOnly], 129 | style: TextStyle(color: Colors.green, fontSize: fontSize), 130 | decoration: InputDecoration( 131 | prefixText: "+91", 132 | prefixStyle: 133 | TextStyle(color: Colors.lightGreen, fontSize: fontSize), 134 | labelText: "Enter Phone number", 135 | labelStyle: 136 | TextStyle(color: Colors.black, fontSize: fontSize), 137 | hintText: "99999-99999", 138 | errorText: invalidNumber 139 | ? "Mobile Number must be of 10 digits" 140 | : null, 141 | hintStyle: TextStyle( 142 | fontStyle: FontStyle.italic, 143 | color: Colors.grey, 144 | fontSize: fontSize), 145 | ), 146 | ), 147 | ), 148 | Divider( 149 | color: Colors.transparent, 150 | height: 20.0, 151 | ), 152 | Visibility( 153 | visible: showInputNameView(), 154 | child: TextField( 155 | controller: fNameController, 156 | keyboardType: TextInputType.text, 157 | style: TextStyle(color: Colors.green, fontSize: fontSize), 158 | decoration: InputDecoration( 159 | prefixStyle: 160 | TextStyle(color: Colors.lightGreen, fontSize: fontSize), 161 | labelText: "Enter First Name", 162 | labelStyle: 163 | TextStyle(color: Colors.black, fontSize: fontSize), 164 | hintText: "John", 165 | errorText: invalidFName 166 | ? "Invalid first name. Enter min 2 characters" 167 | : null, 168 | hintStyle: TextStyle( 169 | fontStyle: FontStyle.italic, 170 | color: Colors.grey, 171 | fontSize: fontSize), 172 | ), 173 | ), 174 | ), 175 | Divider( 176 | color: Colors.transparent, 177 | height: 20.0, 178 | ), 179 | Visibility( 180 | visible: showInputNameView(), 181 | child: TextField( 182 | controller: lNameController, 183 | keyboardType: TextInputType.text, 184 | style: TextStyle(color: Colors.green, fontSize: fontSize), 185 | decoration: InputDecoration( 186 | prefixStyle: 187 | TextStyle(color: Colors.lightGreen, fontSize: fontSize), 188 | labelText: "Enter Last Name", 189 | labelStyle: 190 | TextStyle(color: Colors.black, fontSize: fontSize), 191 | hintText: "Doe", 192 | hintStyle: TextStyle( 193 | fontStyle: FontStyle.italic, 194 | color: Colors.grey, 195 | fontSize: fontSize), 196 | ), 197 | ), 198 | ), 199 | Divider( 200 | color: Colors.transparent, 201 | height: 20.0, 202 | ), 203 | Visibility( 204 | visible: showInputOtpView(), 205 | child: TextField( 206 | controller: otpController, 207 | maxLength: 6, 208 | keyboardType: TextInputType.number, 209 | inputFormatters: [FilteringTextInputFormatter.digitsOnly], 210 | style: TextStyle(color: Colors.green, fontSize: fontSize), 211 | decoration: InputDecoration( 212 | labelText: "Enter OTP", 213 | labelStyle: 214 | TextStyle(color: Colors.black, fontSize: fontSize), 215 | hintText: "123-456", 216 | errorText: invalidOtp ? "OTP must be 6 digits" : null, 217 | hintStyle: TextStyle( 218 | fontStyle: FontStyle.italic, 219 | color: Colors.grey, 220 | fontSize: fontSize), 221 | ), 222 | ), 223 | ), 224 | Divider( 225 | color: Colors.transparent, 226 | height: 20.0, 227 | ), 228 | Visibility( 229 | visible: showInputNumberView() || 230 | showInputNameView() || 231 | showInputOtpView(), 232 | child: MaterialButton( 233 | minWidth: width - 50.0, 234 | height: 45.0, 235 | onPressed: () => onProceedClick(), 236 | child: Text("Proceed", 237 | style: TextStyle( 238 | color: Colors.white, 239 | )), 240 | color: Colors.blue, 241 | ), 242 | ), 243 | Divider( 244 | color: Colors.transparent, 245 | height: 30.0, 246 | ), 247 | Visibility( 248 | visible: showRetryTextView(), 249 | child: _ttl == 0 250 | ? TextButton( 251 | child: Text( 252 | "verification timed out, retry again", 253 | style: TextStyle( 254 | decoration: TextDecoration.underline, 255 | color: Colors.blue), 256 | ), 257 | onPressed: () => setState(() => tempResult = null)) 258 | : Text("Retry again in $_ttl seconds"), 259 | ), 260 | ], 261 | ), 262 | ), 263 | ); 264 | } 265 | 266 | void startCountdownTimer(int ttl) { 267 | _ttl = ttl; 268 | const oneSec = const Duration(seconds: 1); 269 | _timer = new Timer.periodic( 270 | oneSec, 271 | (Timer timer) => setState( 272 | () { 273 | if (_ttl! < 1) { 274 | timer.cancel(); 275 | showProgressBar = false; 276 | } else { 277 | _ttl = _ttl! - 1; 278 | } 279 | }, 280 | ), 281 | ); 282 | } 283 | 284 | void createStreamBuilder() { 285 | streamSubscription = 286 | TcSdk.streamCallbackData.listen((truecallerUserCallback) { 287 | // make sure you're changing state only after number has been entered. there could be case 288 | // where user initiated missed call, pressed back, and came to this screen again after 289 | // which the call was received and hence it would directly open input name screen. 290 | if (phoneController.text.length == 10) { 291 | setState(() { 292 | if (truecallerUserCallback.result != TcSdkCallbackResult.exception) { 293 | tempResult = truecallerUserCallback.result; 294 | } 295 | showProgressBar = 296 | tempResult == TcSdkCallbackResult.missedCallInitiated; 297 | if (tempResult == TcSdkCallbackResult.otpReceived) { 298 | otpController.text = truecallerUserCallback.otp!; 299 | } 300 | }); 301 | } 302 | 303 | switch (truecallerUserCallback.result) { 304 | case TcSdkCallbackResult.missedCallInitiated: 305 | startCountdownTimer( 306 | double.parse(truecallerUserCallback.ttl!).floor()); 307 | showSnackBar( 308 | "Missed call Initiated with TTL : ${truecallerUserCallback.ttl} && " 309 | "requestNonce = ${truecallerUserCallback.requestNonce}"); 310 | break; 311 | case TcSdkCallbackResult.missedCallReceived: 312 | showSnackBar("Missed call Received"); 313 | break; 314 | case TcSdkCallbackResult.otpInitiated: 315 | startCountdownTimer( 316 | double.parse(truecallerUserCallback.ttl!).floor()); 317 | showSnackBar( 318 | "OTP Initiated with TTL : ${truecallerUserCallback.ttl} && " 319 | "requestNonce = ${truecallerUserCallback.requestNonce}"); 320 | break; 321 | case TcSdkCallbackResult.otpReceived: 322 | showSnackBar("OTP Received : ${truecallerUserCallback.otp}"); 323 | break; 324 | case TcSdkCallbackResult.verificationComplete: 325 | showSnackBar( 326 | "Verification Completed : ${truecallerUserCallback.accessToken} && " 327 | "requestNonce = ${truecallerUserCallback.requestNonce}"); 328 | _navigateToResult(fNameController.text); 329 | break; 330 | case TcSdkCallbackResult.verifiedBefore: 331 | showSnackBar( 332 | "Verified Before : ${truecallerUserCallback.profile!.accessToken} && " 333 | "requestNonce = ${truecallerUserCallback.profile!.requestNonce}"); 334 | _navigateToResult(truecallerUserCallback.profile!.firstName); 335 | break; 336 | case TcSdkCallbackResult.exception: 337 | showSnackBar("Exception : ${truecallerUserCallback.exception!.code}, " 338 | "${truecallerUserCallback.exception!.message}"); 339 | break; 340 | default: 341 | print(tempResult.toString()); 342 | break; 343 | } 344 | }); 345 | } 346 | 347 | void showSnackBar(String message) { 348 | final snackBar = SnackBar(content: Text(message)); 349 | ScaffoldMessenger.of(context).showSnackBar(snackBar); 350 | } 351 | 352 | _navigateToResult(String firstName) { 353 | Navigator.pushReplacement( 354 | context, 355 | MaterialPageRoute( 356 | builder: (context) => ResultScreen(firstName), 357 | )); 358 | } 359 | 360 | Future onProceedClick() async { 361 | if (showInputNumberView() && validateNumber()) { 362 | try { 363 | if (await Permission.phone.request().isGranted) { 364 | await TcSdk.requestVerification(phoneNumber: phoneController.text); 365 | setProgressBarToActive(); 366 | } else if (await Permission.phone.isPermanentlyDenied) { 367 | openAppSettings(); 368 | } else { 369 | showSnackBar("Please grant all the permissions to proceed"); 370 | } 371 | } on PlatformException catch (exception) { 372 | showSnackBar(exception.message.toString()); 373 | } catch (exception) { 374 | showSnackBar(exception.toString()); 375 | } 376 | } else if (tempResult == TcSdkCallbackResult.missedCallReceived && 377 | validateName()) { 378 | setProgressBarToActive(); 379 | TcSdk.verifyMissedCall( 380 | firstName: fNameController.text, lastName: lNameController.text); 381 | } else if ((tempResult == TcSdkCallbackResult.otpInitiated || 382 | tempResult == TcSdkCallbackResult.otpReceived) && 383 | validateName() && 384 | validateOtp()) { 385 | setProgressBarToActive(); 386 | TcSdk.verifyOtp( 387 | firstName: fNameController.text, 388 | lastName: lNameController.text, 389 | otp: otpController.text); 390 | } 391 | } 392 | 393 | void setProgressBarToActive() { 394 | setState(() { 395 | showProgressBar = true; 396 | }); 397 | } 398 | 399 | bool validateNumber() { 400 | String phoneNumber = phoneController.text; 401 | setState(() { 402 | phoneNumber.length != 10 ? invalidNumber = true : invalidNumber = false; 403 | }); 404 | return !invalidNumber; 405 | } 406 | 407 | bool validateOtp() { 408 | String otp = otpController.text; 409 | setState(() { 410 | otp.length != 6 ? invalidOtp = true : invalidOtp = false; 411 | }); 412 | return !invalidOtp; 413 | } 414 | 415 | bool validateName() { 416 | String fName = fNameController.text; 417 | setState(() { 418 | fName.length < 2 ? invalidFName = true : invalidFName = false; 419 | }); 420 | return !invalidFName; 421 | } 422 | 423 | @override 424 | void dispose() { 425 | phoneController.dispose(); 426 | fNameController.dispose(); 427 | lNameController.dispose(); 428 | otpController.dispose(); 429 | streamSubscription?.cancel(); 430 | _timer?.cancel(); 431 | super.dispose(); 432 | } 433 | } 434 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: truecaller_sdk_example 2 | description: Demonstrates how to use the truecaller_sdk plugin. 3 | 4 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 5 | 6 | environment: 7 | sdk: '>=2.12.0 <3.0.0' 8 | 9 | dependencies: 10 | dio: ^5.3.2 11 | permission_handler: ^11.0.1 12 | uuid: ^4.1.0 13 | flutter: 14 | sdk: flutter 15 | 16 | truecaller_sdk: 17 | # When depending on this package from a real application you should use: 18 | # truecaller_sdk: ^x.y.z 19 | # See https://dart.dev/tools/pub/dependencies#version-constraints 20 | # The example app is bundled with the plugin so we use a path dependency on 21 | # the parent directory to use the current plugin's version. 22 | path: ../ 23 | 24 | dev_dependencies: 25 | flutter_test: 26 | sdk: flutter 27 | 28 | flutter: 29 | uses-material-design: true 30 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | // This is a basic Flutter widget test. 32 | // 33 | // To perform an interaction with a widget in your test, use the WidgetTester 34 | // utility that Flutter provides. For example, you can send tap and scroll 35 | // gestures. You can also use WidgetTester to find child widgets in the widget 36 | // tree, read text, and verify that the values of widget properties are correct. 37 | 38 | import 'package:flutter/material.dart'; 39 | import 'package:flutter_test/flutter_test.dart'; 40 | import 'package:truecaller_sdk_example/main.dart'; 41 | 42 | void main() { 43 | testWidgets('Verify Platform version', (WidgetTester tester) async { 44 | // Build our app and trigger a frame. 45 | await tester.pumpWidget(MyApp()); 46 | 47 | // Verify that platform version is retrieved. 48 | expect( 49 | find.byWidgetPredicate( 50 | (Widget widget) => 51 | widget is Text && widget.data!.startsWith('Running on:'), 52 | ), 53 | findsOneWidget, 54 | ); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /images/main.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/images/main.jpg -------------------------------------------------------------------------------- /images/main_customization_screen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/images/main_customization_screen.jpg -------------------------------------------------------------------------------- /images/truecaller_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/images/truecaller_logo.png -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truecaller/flutter-sdk/77c6bce3bca56028295e6987f843e7d4ff5bbda9/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/Classes/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // truecaller_sdk 4 | // 5 | // Created by Sreedeepkesav M S on 02/03/22. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Constants { 11 | struct ChannelNames { 12 | static let methodChannel = "tc_method_channel" 13 | static let eventChannel = "tc_event_channel" 14 | } 15 | 16 | struct String { 17 | static let data = "data" 18 | static let result = "result" 19 | static let success = "success" 20 | static let failure = "failure" 21 | } 22 | 23 | struct Error { 24 | static let methodNotImplemented = "Method not implemented" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ios/Classes/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // truecaller_sdk 4 | // 5 | // Created by Sreedeepkesav M S on 02/03/22. 6 | // 7 | 8 | import Foundation 9 | import TrueSDK 10 | 11 | extension TCTrueProfileResponse { 12 | var toDict: [String: AnyHashable] { 13 | var dict = [String: AnyHashable]() 14 | dict["payload"] = payload 15 | dict["signature"] = signature 16 | dict["signatureAlgorithm"] = signatureAlgorithm 17 | dict["requestNonce"] = requestNonce 18 | return dict 19 | } 20 | } 21 | 22 | extension TCTrueProfile { 23 | var toDict: [String: AnyHashable] { 24 | var dict = [String: AnyHashable]() 25 | dict["firstName"] = firstName 26 | dict["lastName"] = lastName 27 | dict["isVerified"] = isVerified 28 | dict["isAmbassador"] = isAmbassador 29 | dict["phoneNumber"] = phoneNumber 30 | dict["countryCode"] = countryCode 31 | dict["street"] = street 32 | dict["city"] = city 33 | dict["facebookID"] = facebookID 34 | dict["twitterID"] = twitterID 35 | dict["email"] = email 36 | dict["url"] = url 37 | dict["avatarURL"] = avatarURL 38 | dict["jobTitle"] = jobTitle 39 | dict["companyName"] = companyName 40 | dict["requestTime"] = requestTime 41 | dict["genderValue"] = gender.rawValue 42 | return dict 43 | } 44 | } 45 | 46 | extension TCError { 47 | var toDict: [String: AnyHashable] { 48 | var dict = [String: AnyHashable]() 49 | dict["code"] = getCode() 50 | dict["message"] = description 51 | return dict 52 | } 53 | } 54 | 55 | extension Dictionary { 56 | var tojsonString: String? { 57 | guard let data = try? JSONSerialization.data(withJSONObject: self) else { 58 | return nil 59 | } 60 | 61 | return String(data: data, encoding: .utf8) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ios/Classes/SwiftTruecallerSdkPlugin.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import TrueSDK 4 | 5 | private enum MethodCalls: String { 6 | case initiateSDK 7 | case isUsable 8 | case setDarkTheme 9 | case setLocale 10 | case getProfile 11 | case requestVerification 12 | case verifyOtp 13 | case verifyMissedCall 14 | } 15 | 16 | public class SwiftTruecallerSdkPlugin: NSObject, 17 | FlutterPlugin { 18 | private var mainChannel: FlutterMethodChannel? 19 | private var eventChannel: FlutterEventChannel? 20 | private var eventSink: FlutterEventSink? 21 | 22 | private var trueSdk = TCTrueSDK.sharedManager() 23 | 24 | public static func register(with registrar: FlutterPluginRegistrar) { 25 | _ = SwiftTruecallerSdkPlugin(with: registrar) 26 | } 27 | 28 | private var trueProfileResponse: TCTrueProfileResponse? 29 | 30 | init(with registrar: FlutterPluginRegistrar) { 31 | super.init() 32 | 33 | addMainChannel(registrar: registrar) 34 | addEventChannel(registrar: registrar) 35 | registrar.addApplicationDelegate(self) 36 | } 37 | 38 | private func addMainChannel(registrar: FlutterPluginRegistrar) { 39 | mainChannel = FlutterMethodChannel(name: Constants.ChannelNames.methodChannel, 40 | binaryMessenger: registrar.messenger()) 41 | guard let mainChannel = mainChannel else { 42 | return 43 | } 44 | registrar.addMethodCallDelegate(self, channel: mainChannel) 45 | } 46 | 47 | private func addEventChannel(registrar: FlutterPluginRegistrar) { 48 | eventChannel = FlutterEventChannel(name: Constants.ChannelNames.eventChannel, 49 | binaryMessenger: registrar.messenger()) 50 | guard let eventChannel = eventChannel else { 51 | return 52 | } 53 | eventChannel.setStreamHandler(self) 54 | } 55 | 56 | public func handle(_ call: FlutterMethodCall, 57 | result: @escaping FlutterResult) { 58 | let method = MethodCalls(rawValue: call.method) 59 | switch method { 60 | case .initiateSDK: 61 | trueSdk.delegate = self 62 | result(true) 63 | case .isUsable: 64 | result(trueSdk.isSupported()) 65 | case .setDarkTheme, 66 | .setLocale, 67 | .requestVerification, 68 | .verifyOtp, 69 | .verifyMissedCall: 70 | result(Constants.Error.methodNotImplemented) 71 | case .getProfile: 72 | trueSdk.requestTrueProfile() 73 | case .none: 74 | result(Constants.Error.methodNotImplemented) 75 | } 76 | } 77 | } 78 | 79 | // MARK: - App delegate methods - 80 | 81 | extension SwiftTruecallerSdkPlugin { 82 | public func application(_ application: UIApplication, 83 | continue userActivity: NSUserActivity, 84 | restorationHandler: @escaping ([Any]) -> Void) -> Bool { 85 | return TCTrueSDK.sharedManager().application(application, 86 | continue: userActivity, 87 | restorationHandler: restorationHandler as? ([Any]?) -> Void) 88 | } 89 | 90 | public func application(_ app: UIApplication, 91 | open url: URL, 92 | options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { 93 | return TCTrueSDK.sharedManager().continue(withUrlScheme: url) 94 | } 95 | } 96 | 97 | // MARK: - FlutterStreamHandler - 98 | 99 | extension SwiftTruecallerSdkPlugin: FlutterStreamHandler { 100 | public func onListen(withArguments arguments: Any?, 101 | eventSink events: @escaping FlutterEventSink) -> FlutterError? { 102 | self.eventSink = events 103 | return nil 104 | } 105 | 106 | public func onCancel(withArguments arguments: Any?) -> FlutterError? { 107 | self.eventSink = nil 108 | return nil 109 | } 110 | } 111 | 112 | // MARK: - TCTrueSDKDelegate - 113 | 114 | extension SwiftTruecallerSdkPlugin: TCTrueSDKDelegate { 115 | public func didReceive(_ profile: TCTrueProfile) { 116 | var map = [String: Any]() 117 | map[Constants.String.result] = Constants.String.success 118 | var data = profile.toDict 119 | if let response = trueProfileResponse { 120 | data = data.merging(response.toDict) { $1 } 121 | trueProfileResponse = nil 122 | } 123 | map[Constants.String.data] = data.tojsonString 124 | eventSink?(map) 125 | } 126 | 127 | public func didReceive(_ profileResponse: TCTrueProfileResponse) { 128 | trueProfileResponse = profileResponse 129 | } 130 | 131 | public func didFailToReceiveTrueProfileWithError(_ error: TCError) { 132 | var map = [String: Any]() 133 | map[Constants.String.result] = Constants.String.failure 134 | map[Constants.String.data] = error.toDict.tojsonString 135 | trueProfileResponse = nil 136 | eventSink?(error) 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /ios/Classes/TruecallerSdkPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TruecallerSdkPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /ios/Classes/TruecallerSdkPlugin.m: -------------------------------------------------------------------------------- 1 | #import "TruecallerSdkPlugin.h" 2 | #if __has_include() 3 | #import 4 | #else 5 | // Support project import fallback if the generated compatibility header 6 | // is not copied when this plugin is created as a library. 7 | // https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816 8 | #import "truecaller_sdk-Swift.h" 9 | #endif 10 | 11 | @implementation TruecallerSdkPlugin 12 | + (void)registerWithRegistrar:(NSObject*)registrar { 13 | [SwiftTruecallerSdkPlugin registerWithRegistrar:registrar]; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /ios/truecaller_sdk.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint truecaller_sdk.podspec' to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'truecaller_sdk' 7 | s.version = '0.0.1' 8 | s.summary = 'A Flutter plugin that uses Truecaller Android SDK for signing in with Phone numbers' 9 | s.description = <<-DESC 10 | A Flutter plugin that uses Truecaller Android SDK for signing in with Phone numbers 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'Flutter' 18 | s.dependency 'TrueSDK' 19 | s.platform = :ios, '9.0' 20 | 21 | # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. 22 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } 23 | s.swift_version = '5.0' 24 | end 25 | -------------------------------------------------------------------------------- /lib/src/scope_options.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | /// scope options that are used to customize the consent screen UI 32 | class TcSdkOptions { 33 | /// secondary cta text options 34 | static const int FOOTER_TYPE_SKIP = 1; 35 | static const int FOOTER_TYPE_ANOTHER_MOBILE_NO = 2; 36 | static const int FOOTER_TYPE_ANOTHER_METHOD = 4; 37 | static const int FOOTER_TYPE_MANUALLY = 8; 38 | static const int FOOTER_TYPE_LATER = 16; 39 | 40 | /// sdk options 41 | static const int OPTION_VERIFY_ONLY_TC_USERS = 32; 42 | static const int OPTION_VERIFY_ALL_USERS = 64; 43 | 44 | /// button shape options 45 | static const int BUTTON_SHAPE_ROUNDED = 128; 46 | static const int BUTTON_SHAPE_RECTANGLE = 256; 47 | 48 | /// heading options 49 | static const int SDK_CONSENT_HEADING_LOG_IN_TO = 0; 50 | static const int SDK_CONSENT_HEADING_SIGN_UP_WITH = 1; 51 | static const int SDK_CONSENT_HEADING_SIGN_IN_TO = 2; 52 | static const int SDK_CONSENT_HEADING_VERIFY_NUMBER_WITH = 3; 53 | static const int SDK_CONSENT_HEADING_REGISTER_WITH = 4; 54 | static const int SDK_CONSENT_HEADING_GET_STARTED_WITH = 5; 55 | static const int SDK_CONSENT_HEADING_PROCEED_WITH = 6; 56 | static const int SDK_CONSENT_HEADING_VERIFY_WITH = 7; 57 | static const int SDK_CONSENT_HEADING_VERIFY_PROFILE_WITH = 8; 58 | static const int SDK_CONSENT_HEADING_VERIFY_YOUR_PROFILE_WITH = 9; 59 | static const int SDK_CONSENT_HEADING_VERIFY_PHONE_NO_WITH = 10; 60 | static const int SDK_CONSENT_HEADING_VERIFY_YOUR_NO_WITH = 11; 61 | static const int SDK_CONSENT_HEADING_CONTINUE_WITH = 12; 62 | static const int SDK_CONSENT_HEADING_COMPLETE_ORDER_WITH = 13; 63 | static const int SDK_CONSENT_HEADING_PLACE_ORDER_WITH = 14; 64 | static const int SDK_CONSENT_HEADING_COMPLETE_BOOKING_WITH = 15; 65 | static const int SDK_CONSENT_HEADING_CHECKOUT_WITH = 16; 66 | static const int SDK_CONSENT_HEADING_MANAGE_DETAILS_WITH = 17; 67 | static const int SDK_CONSENT_HEADING_MANAGE_YOUR_DETAILS_WITH = 18; 68 | static const int SDK_CONSENT_HEADING_LOGIN_TO_WITH_ONE_TAP = 19; 69 | static const int SDK_CONSENT_HEADING_SUBSCRIBE_TO = 20; 70 | static const int SDK_CONSENT_HEADING_GET_UPDATES_FROM = 21; 71 | static const int SDK_CONSENT_HEADING_CONTINUE_READING_ON = 22; 72 | static const int SDK_CONSENT_HEADING_GET_NEW_UPDATES_FROM = 23; 73 | static const int SDK_CONSENT_HEADING_LOGIN_SIGNUP_WITH = 24; 74 | 75 | /// login text prefix options 76 | static const int LOGIN_TEXT_PREFIX_TO_GET_STARTED = 0; 77 | static const int LOGIN_TEXT_PREFIX_TO_CONTINUE = 1; 78 | static const int LOGIN_TEXT_PREFIX_TO_PLACE_ORDER = 2; 79 | static const int LOGIN_TEXT_PREFIX_TO_COMPLETE_YOUR_PURCHASE = 3; 80 | static const int LOGIN_TEXT_PREFIX_TO_CHECKOUT = 4; 81 | static const int LOGIN_TEXT_PREFIX_TO_COMPLETE_YOUR_BOOKING = 5; 82 | static const int LOGIN_TEXT_PREFIX_TO_PROCEED_WITH_YOUR_BOOKING = 6; 83 | static const int LOGIN_TEXT_PREFIX_TO_CONTINUE_WITH_YOUR_BOOKING = 7; 84 | static const int LOGIN_TEXT_PREFIX_TO_GET_DETAILS = 8; 85 | static const int LOGIN_TEXT_PREFIX_TO_VIEW_MORE = 9; 86 | static const int LOGIN_TEXT_PREFIX_TO_CONTINUE_READING = 10; 87 | static const int LOGIN_TEXT_PREFIX_TO_PROCEED = 11; 88 | static const int LOGIN_TEXT_PREFIX_FOR_NEW_UPDATES = 12; 89 | static const int LOGIN_TEXT_PREFIX_TO_GET_UPDATES = 13; 90 | static const int LOGIN_TEXT_PREFIX_TO_SUBSCRIBE = 14; 91 | static const int LOGIN_TEXT_PREFIX_TO_SUBSCRIBE_AND_GET_UPDATES = 15; 92 | 93 | /// primary cta text prefix options 94 | static const int CTA_TEXT_PROCEED = 0; 95 | static const int CTA_TEXT_CONTINUE = 1; 96 | static const int CTA_TEXT_ACCEPT = 2; 97 | static const int CTA_TEXT_CONFIRM = 3; 98 | static const int CTA_TEXT_USE = 4; 99 | static const int CTA_TEXT_CONTINUE_WITH = 5; 100 | static const int CTA_TEXT_PROCEED_WITH = 6; 101 | } 102 | -------------------------------------------------------------------------------- /lib/src/truecaller.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | import 'dart:collection'; 32 | import 'dart:convert'; 33 | 34 | import 'package:flutter/services.dart'; 35 | 36 | import 'scope_options.dart'; 37 | import 'truecaller_callback.dart'; 38 | 39 | class TcSdk { 40 | static const MethodChannel _methodChannel = 41 | const MethodChannel('tc_method_channel'); 42 | static const EventChannel _eventChannel = 43 | const EventChannel('tc_event_channel'); 44 | static Stream? _callbackStream; 45 | 46 | /// This method has to be called before anything else. It initializes the SDK with the 47 | /// customizable options which are all optional and have default values as set below in the method 48 | /// 49 | /// [sdkOption] determines whether you want to use the SDK for verifying - 50 | /// 1. [TcSdkOptions.OPTION_VERIFY_ONLY_TC_USERS] i.e only Truecaller users 51 | /// 2. [TcSdkOptions.OPTION_VERIFY_ALL_USERS] i.e both Truecaller and Non-Truecaller users 52 | /// 53 | /// [consentHeadingOption] determines the heading of the consent screen. 54 | /// [ctaText] determines prefix text in login/primary button 55 | /// [footerType] determines the footer button/secondary button text. 56 | /// [buttonShapeOption] to set login button shape 57 | /// [buttonColor] to set login button color 58 | /// [buttonTextColor] to set login button text color 59 | static initializeSDK( 60 | {required int sdkOption, 61 | int consentHeadingOption = TcSdkOptions.SDK_CONSENT_HEADING_LOG_IN_TO, 62 | int footerType = TcSdkOptions.FOOTER_TYPE_ANOTHER_MOBILE_NO, 63 | int ctaText = TcSdkOptions.CTA_TEXT_PROCEED, 64 | int buttonShapeOption = TcSdkOptions.BUTTON_SHAPE_ROUNDED, 65 | int? buttonColor, 66 | int? buttonTextColor}) async => 67 | await _methodChannel.invokeMethod('initializeSDK', { 68 | "sdkOption": sdkOption, 69 | "consentHeadingOption": consentHeadingOption, 70 | "footerType": footerType, 71 | "ctaText": ctaText, 72 | "buttonShapeOption": buttonShapeOption, 73 | "buttonColor": buttonColor, 74 | "buttonTextColor": buttonTextColor, 75 | }); 76 | 77 | /// Once you initialise the Truecaller SDK using the [initializeSDK] method, and if you are using 78 | /// the SDK for verification of only Truecaller users ( by setting the sdkOptions scope as 79 | /// [TcSdkOptions.OPTION_VERIFY_ONLY_TC_USERS], you can check if the Truecaller app is 80 | /// present on the user's device and whether the user has a valid account state or not and 81 | /// whether the OAuth flow is supported or not using the following method 82 | static Future get isOAuthFlowUsable async => 83 | _methodChannel.invokeMethod('isOAuthFlowUsable'); 84 | 85 | /// After checking [isUsable], you can invoke Truecaller's OAuth consent screen dialog 86 | /// in your app flow by calling the following method 87 | /// The result will be returned asynchronously via [streamCallbackData] stream 88 | static get getAuthorizationCode async => 89 | await _methodChannel.invokeMethod('getAuthorizationCode'); 90 | 91 | /// Once you call [getAuthorizationCode], you can listen to this stream to determine the result of the 92 | /// action taken by the user. 93 | /// [TcSdkCallbackResult.success] means the result is successful and you can now fetch 94 | /// the user's access token using the authorization code from [TcSdkCallback.tcOAuthData] 95 | /// [TcSdkCallbackResult.failure] means the result is failure and you can now fetch 96 | /// the result of failure from [TcSdkCallback.error] 97 | /// [TcSdkCallbackResult.verification] will be returned only when using 98 | /// [TcSdkOptions.OPTION_VERIFY_ALL_USERS] which indicates to verify the user manually 99 | static Stream get streamCallbackData { 100 | if (_callbackStream == null) { 101 | _callbackStream = 102 | _eventChannel.receiveBroadcastStream().map((value) { 103 | TcSdkCallback callback = new TcSdkCallback(); 104 | var resultHashMap = HashMap.from(value); 105 | final String? result = resultHashMap["result"]; 106 | switch (result.enumValue()) { 107 | case TcSdkCallbackResult.success: 108 | callback.result = TcSdkCallbackResult.success; 109 | _insertOAuthData(callback, resultHashMap["data"]!); 110 | break; 111 | case TcSdkCallbackResult.failure: 112 | callback.result = TcSdkCallbackResult.failure; 113 | _insertError(callback, resultHashMap["data"]); 114 | break; 115 | case TcSdkCallbackResult.verification: 116 | callback.result = TcSdkCallbackResult.verification; 117 | _insertError(callback, resultHashMap["data"]); 118 | break; 119 | case TcSdkCallbackResult.missedCallInitiated: 120 | callback.result = TcSdkCallbackResult.missedCallInitiated; 121 | CallbackData data = _insertData(callback, resultHashMap["data"]!); 122 | callback.ttl = data.ttl; 123 | callback.requestNonce = data.requestNonce; 124 | break; 125 | case TcSdkCallbackResult.missedCallReceived: 126 | callback.result = TcSdkCallbackResult.missedCallReceived; 127 | break; 128 | case TcSdkCallbackResult.otpInitiated: 129 | callback.result = TcSdkCallbackResult.otpInitiated; 130 | CallbackData data = _insertData(callback, resultHashMap["data"]!); 131 | callback.ttl = data.ttl; 132 | callback.requestNonce = data.requestNonce; 133 | break; 134 | case TcSdkCallbackResult.otpReceived: 135 | callback.result = TcSdkCallbackResult.otpReceived; 136 | CallbackData data = _insertData(callback, resultHashMap["data"]!); 137 | callback.otp = data.otp; 138 | break; 139 | case TcSdkCallbackResult.verifiedBefore: 140 | callback.result = TcSdkCallbackResult.verifiedBefore; 141 | CallbackData data = _insertData(callback, resultHashMap["data"]!); 142 | _insertProfile(callback, data.profile!); 143 | break; 144 | case TcSdkCallbackResult.verificationComplete: 145 | callback.result = TcSdkCallbackResult.verificationComplete; 146 | CallbackData data = _insertData(callback, resultHashMap["data"]!); 147 | callback.accessToken = data.accessToken; 148 | callback.requestNonce = data.requestNonce; 149 | break; 150 | case TcSdkCallbackResult.exception: 151 | callback.result = TcSdkCallbackResult.exception; 152 | Map exceptionMap = jsonDecode(resultHashMap["data"]!); 153 | TruecallerException exception = TruecallerException.fromJson( 154 | exceptionMap as Map); 155 | callback.exception = exception; 156 | break; 157 | default: 158 | throw PlatformException( 159 | code: "1010", 160 | message: "${resultHashMap["result"]} is not a valid result"); 161 | } 162 | return callback; 163 | }); 164 | } 165 | return _callbackStream!; 166 | } 167 | 168 | static CallbackData _insertData(TcSdkCallback callback, String data) { 169 | Map dataMap = jsonDecode(data); 170 | return CallbackData.fromJson(dataMap as Map); 171 | } 172 | 173 | static _insertOAuthData(TcSdkCallback callback, String data) { 174 | Map oAuthDataMap = jsonDecode(data); 175 | TcOAuthData tcOAuthData = 176 | TcOAuthData.fromJson(oAuthDataMap as Map); 177 | callback.tcOAuthData = tcOAuthData; 178 | } 179 | 180 | static _insertProfile(TcSdkCallback callback, String data) { 181 | Map profileMap = jsonDecode(data); 182 | TruecallerUserProfile profile = 183 | TruecallerUserProfile.fromJson(profileMap as Map); 184 | callback.profile = profile; 185 | } 186 | 187 | static _insertError(TcSdkCallback callback, String? data) { 188 | // onVerificationRequired has nullable error, hence null check 189 | if (data != null && 190 | data.trim().isNotEmpty && 191 | data.trim().toLowerCase() != "null") { 192 | Map errorMap = jsonDecode(data); 193 | TcOAuthError tcOAuthError = 194 | TcOAuthError.fromJson(errorMap as Map); 195 | callback.error = tcOAuthError; 196 | } 197 | } 198 | 199 | /// This utility method generates a random code verifier string using SecureRandom as the 200 | /// source of entropy with 64 as the default entropy quantity. 201 | /// You can either generate your own code verifier or use this utility method to generate one 202 | /// for you. 203 | /// NOTE: Store the code verifier in the current session since it would be required later 204 | /// to generate the access token. 205 | static Future get generateRandomCodeVerifier async => 206 | _methodChannel.invokeMethod('generateRandomCodeVerifier'); 207 | 208 | /// This utility method produces a code challenge from the supplied code verifier[codeVerifier] 209 | /// using SHA-256 as the challenge method and Base64 as encoding if the system supports it. 210 | /// NOTE: All Android devices should ideally support SHA-256 and Base64, but in rare case if 211 | /// the doesn't, then this method would return null meaning that you can’t proceed further. 212 | /// Please ensure to have a null safe check for such cases. 213 | static Future generateCodeChallenge(String codeVerifier) async => 214 | _methodChannel.invokeMethod( 215 | 'generateCodeChallenge', {"codeVerifier": codeVerifier}); 216 | 217 | /// Set your own code challenge or use the utility method [generateRandomCodeVerifier] to generate 218 | /// one for you and set it via [codeChallenge] to this method 219 | /// Set it before calling [getAuthorizationCode] 220 | static setCodeChallenge(String codeChallenge) async => await _methodChannel 221 | .invokeMethod('setCodeChallenge', {"codeChallenge": codeChallenge}); 222 | 223 | /// Set the list of scopes to be requested using [scopes]. 224 | /// Set it before calling [getAuthorizationCode] 225 | static setOAuthScopes(List scopes) async => 226 | await _methodChannel.invokeMethod('setOAuthScopes', {"scopes": scopes}); 227 | 228 | /// Set a unique state parameter [oAuthState] & store it in the current session to use it later in the 229 | /// onSuccess() callback method of the [TcOAuthCallback] to match if the state received from the 230 | /// authorization server is the same as set here to prevent request forgery attacks. 231 | /// Set it before calling [getAuthorizationCode] 232 | static setOAuthState(String oAuthState) async => await _methodChannel 233 | .invokeMethod('setOAuthState', {"oAuthState": oAuthState}); 234 | 235 | /// Customise the consent screen dialog in any of the supported Indian languages by supplying 236 | /// [locale] to the method. 237 | /// NOTE: Default value is en 238 | /// Set it before calling [getAuthorizationCode] 239 | static setLocale(String locale) async => 240 | await _methodChannel.invokeMethod('setLocale', {"locale": locale}); 241 | 242 | /// This method will initiate manual verification of [phoneNumber] asynchronously for Indian 243 | /// numbers only so that's why default countryISO is set to "IN". 244 | /// The result will be returned asynchronously via [streamCallbackData] stream 245 | /// Check [TcSdkCallbackResult] to understand the different verifications states. 246 | /// This method may lead to verification with a SMS Code (OTP) or verification with a CALL, 247 | /// or if the user is already verified on the device, will get the call back as 248 | /// [TcSdkCallbackResult.verifiedBefore] in [streamCallbackData] 249 | static requestVerification( 250 | {required String phoneNumber, String countryISO = "IN"}) async => 251 | await _methodChannel.invokeMethod( 252 | 'requestVerification', {"ph": phoneNumber, "ci": countryISO}); 253 | 254 | /// Call this method after [requestVerification] to complete the verification if the number has 255 | /// to be verified with a missed call. 256 | /// i.e call this method only when you receive [TcSdkCallbackResult.missedCallReceived] 257 | /// in [streamCallbackData]. 258 | /// To complete verification, it is mandatory to pass [firstName] and [lastName] of the user 259 | static verifyMissedCall( 260 | {required String firstName, required String lastName}) async => 261 | await _methodChannel.invokeMethod( 262 | 'verifyMissedCall', {"fname": firstName, "lname": lastName}); 263 | 264 | /// Call this method after [requestVerification] to complete the verification if the number has 265 | /// to be verified with an OTP. 266 | /// i.e call this method when you receive either [TcSdkCallbackResult.otpInitiated] or 267 | /// [TcSdkCallbackResult.otpReceived] in [streamCallbackData]. 268 | /// To complete verification, it is mandatory to pass [firstName] and [lastName] of the user 269 | /// with the [otp] code received over SMS 270 | static verifyOtp( 271 | {required String firstName, 272 | required String lastName, 273 | required String otp}) async => 274 | await _methodChannel.invokeMethod( 275 | 'verifyOtp', {"fname": firstName, "lname": lastName, "otp": otp}); 276 | } 277 | -------------------------------------------------------------------------------- /lib/src/truecaller_callback.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | /// callback stream that gets returned from [TcSdk.streamCallbackData] 32 | class TcSdkCallback { 33 | late TcSdkCallbackResult result; 34 | 35 | //for tc-flow 36 | 37 | /// received when [result] equals [TcSdkCallbackResult.success] 38 | TcOAuthData? tcOAuthData; 39 | 40 | /// received when [result] equals [TcSdkCallbackResult.failure] or 41 | /// [result] equals [TcSdkCallbackResult.verification] 42 | /// It indicates reason why Truecaller user verification failed 43 | TcOAuthError? error; 44 | 45 | //for non-tc flow 46 | 47 | /// received when [result] equals [TcSdkCallbackResult.verifiedBefore] 48 | TruecallerUserProfile? profile; 49 | 50 | /// received when [result] equals [TcSdkCallbackResult.otpReceived] 51 | String? otp; 52 | 53 | /// received when [result] equals [TcSdkCallbackResult.verificationComplete] 54 | /// It can be used for server-side response validation 55 | String? accessToken; 56 | 57 | /// TTL(in sec) received when [result] equals either [TcSdkCallbackResult.otpInitiated] 58 | /// or [result] equals [TcSdkCallbackResult.missedCallInitiated] 59 | /// It indicates time left to complete the user verification process 60 | String? ttl; 61 | 62 | /// Request Nonce received when [result] equals either [TcSdkCallbackResult.otpInitiated] 63 | /// or [TcSdkCallbackResult.missedCallInitiated] 64 | /// or [TcSdkCallbackResult.verificationComplete] 65 | /// It can be used to verify whether the custom request identifier (if set) during SDK 66 | /// initialization is same as this one received in response which essentially assures a 67 | /// correlation between the request and the response 68 | String? requestNonce; 69 | 70 | /// received when [result] equals [TcSdkCallbackResult.exception] 71 | /// It indicates reason why non-truecaller user verification failed 72 | TruecallerException? exception; 73 | } 74 | 75 | /// enum with callback results that corresponds to the [TcSdkCallback.result] 76 | enum TcSdkCallbackResult { 77 | //tc user callback results 78 | success, 79 | failure, 80 | verification, 81 | 82 | //non-tc user callback results 83 | missedCallInitiated, 84 | missedCallReceived, 85 | otpInitiated, 86 | otpReceived, 87 | verifiedBefore, 88 | verificationComplete, 89 | exception 90 | } 91 | 92 | /// extension method that converts String to corresponding enum value 93 | extension EnumParser on String? { 94 | TcSdkCallbackResult? enumValue() { 95 | return TcSdkCallbackResult.values.firstWhere((element) => 96 | element.toString().split(".")[1].toLowerCase() == this!.toLowerCase()); 97 | } 98 | } 99 | 100 | /// OAuth data that corresponds to [TcSdkCallback.tcOAuthData] 101 | class TcOAuthData { 102 | late String authorizationCode; 103 | late String state; 104 | late List scopesGranted; 105 | 106 | /// get the [TcOAuthData] values from Json 107 | TcOAuthData.fromJson(Map map) { 108 | authorizationCode = map['authorizationCode']; 109 | state = map['state']; 110 | scopesGranted = map['scopesGranted']; 111 | } 112 | } 113 | 114 | /// user profile that corresponds to [TcSdkCallback.profile] 115 | class TruecallerUserProfile { 116 | String firstName; 117 | String? lastName; 118 | String phoneNumber; 119 | String? gender; 120 | String? street; 121 | String? city; 122 | String? zipcode; 123 | String? countryCode; 124 | String? facebookId; 125 | String? twitterId; 126 | String? email; 127 | String? url; 128 | String? avatarUrl; 129 | bool? isTrueName; 130 | bool? isAmbassador; 131 | String? companyName; 132 | String? jobTitle; 133 | String? payload; 134 | String? signature; 135 | String? signatureAlgorithm; 136 | String? requestNonce; 137 | bool? isSimChanged; 138 | String? verificationMode; 139 | int? verificationTimestamp; 140 | String? userLocale; 141 | String? accessToken; 142 | 143 | /// get the [TruecallerUserProfile] values from Json 144 | TruecallerUserProfile.fromJson(Map map) 145 | : firstName = map['firstName'], 146 | lastName = map['lastName'], 147 | phoneNumber = map['phoneNumber'], 148 | gender = map['gender'], 149 | street = map['street'], 150 | city = map['city'], 151 | zipcode = map['zipcode'], 152 | countryCode = map['countryCode'], 153 | facebookId = map['facebookId'], 154 | twitterId = map['twitterId'], 155 | email = map['email'], 156 | url = map['url'], 157 | avatarUrl = map['avatarUrl'], 158 | isTrueName = map['isTrueName'], 159 | isAmbassador = map['isAmbassador'], 160 | companyName = map['companyName'], 161 | jobTitle = map['jobTitle'], 162 | payload = map['payload'], 163 | signature = map['signature'], 164 | signatureAlgorithm = map['signatureAlgorithm'], 165 | requestNonce = map['requestNonce'], 166 | isSimChanged = map['isSimChanged'], 167 | verificationMode = map['verificationMode'], 168 | verificationTimestamp = map['verificationTimestamp'], 169 | userLocale = map['userLocale'], 170 | accessToken = map['accessToken']; 171 | } 172 | 173 | /// error that corresponds to [TcSdkCallback.error] 174 | class TcOAuthError { 175 | late int code; 176 | late String? message; 177 | 178 | /// get the [TruecallerError] values from Json 179 | TcOAuthError.fromJson(Map map) { 180 | code = map['errorCode']; 181 | message = map['errorMessage']; 182 | } 183 | } 184 | 185 | /// exception that corresponds to [TcSdkCallback.exception] 186 | class TruecallerException { 187 | late int code; 188 | late String message; 189 | 190 | /// get the [TruecallerException] values from Json 191 | TruecallerException.fromJson(Map map) { 192 | code = map['mExceptionType']; 193 | message = map['mExceptionMessage']; 194 | } 195 | 196 | @override 197 | String toString() { 198 | return "$code : $message"; 199 | } 200 | } 201 | 202 | class CallbackData { 203 | late String? otp; 204 | late String? ttl; 205 | late String? accessToken; 206 | late String? requestNonce; 207 | late String? profile; 208 | 209 | CallbackData.fromJson(Map map) { 210 | otp = map['otp']; 211 | ttl = map['ttl']; 212 | accessToken = map['accessToken']; 213 | requestNonce = map['requestNonce']; 214 | profile = map['profile']; 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /lib/truecaller_sdk.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | export 'src/scope_options.dart'; 32 | export 'src/truecaller.dart'; 33 | export 'src/truecaller_callback.dart'; 34 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: truecaller_sdk 2 | description: Flutter plugin that uses Truecaller's OAuth SDK for Android based on OAuth 2.0 which is the industry-standard protocol for authorization. 3 | version: 1.0.0 4 | homepage: https://github.com/truecaller/flutter-sdk 5 | 6 | environment: 7 | sdk: '>=2.12.0 <3.0.0' 8 | flutter: ">=2.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | flutter_test: 16 | sdk: flutter 17 | 18 | # The following section is specific to Flutter. 19 | flutter: 20 | # This section identifies this Flutter project as a plugin project. 21 | # The 'pluginClass' and Android 'package' identifiers should not ordinarily 22 | # be modified. They are used by the tooling to maintain consistency when 23 | # adding or updating assets for this project. 24 | plugin: 25 | platforms: 26 | android: 27 | package: com.truecallersdk 28 | pluginClass: TruecallerSdkPlugin -------------------------------------------------------------------------------- /test/truecaller_sdk_test.dart: -------------------------------------------------------------------------------- 1 | /* 2 | * TRUECALLER SDK COPYRIGHT, TRADEMARK AND LICENSE NOTICE 3 | * 4 | * Copyright © 2015-Present, True Software Scandinavia AB. All rights reserved. 5 | * 6 | * Truecaller and Truecaller SDK are registered trademark of True Software Scandinavia AB. 7 | * 8 | * In accordance with the Truecaller SDK Agreement available 9 | * here (https://developer.truecaller.com/Truecaller-sdk-product-license-agreement-RoW.pdf) 10 | * accepted and agreed between You and Your respective Truecaller entity, You are granted a 11 | * limited, non-exclusive, non-sublicensable, non-transferable, royalty-free, license to use the 12 | * Truecaller SDK Product in object code form only, solely for the purpose of using 13 | * the Truecaller SDK Product with the applications and APIs provided by Truecaller. 14 | * 15 | * THE TRUECALLER SDK PRODUCT IS PROVIDED BY THE COPYRIGHT HOLDER AND AUTHOR “AS IS”, 16 | * WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT LIMITED 17 | * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 18 | * SOFTWARE QUALITY,PERFORMANCE,DATA ACCURACY AND NON-INFRINGEMENT. IN NO 19 | * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, 20 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR 21 | * OTHER LIABILITY INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THE TRUECALLER SDK PRODUCT OR THE USE 26 | * OR OTHER DEALINGS IN THE TRUECALLER SDK PRODUCT, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. AS A RESULT, BY INTEGRATING THE TRUECALLER SDK 28 | * PRODUCT YOU ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. 29 | */ 30 | 31 | import 'package:flutter/services.dart'; 32 | import 'package:flutter_test/flutter_test.dart'; 33 | 34 | void main() { 35 | const MethodChannel channel = MethodChannel('tc_method_channel'); 36 | 37 | TestWidgetsFlutterBinding.ensureInitialized(); 38 | 39 | setUp(() { 40 | TestWidgetsFlutterBinding.instance.defaultBinaryMessenger 41 | .setMockMethodCallHandler(channel, (MethodCall methodCall) async { 42 | return '42'; 43 | }); 44 | }); 45 | 46 | tearDown(() { 47 | TestWidgetsFlutterBinding.instance.defaultBinaryMessenger 48 | .setMockMethodCallHandler(channel, null); 49 | }); 50 | 51 | /*test('getPlatformVersion', () async { 52 | expect(await TruecallerSdk.platformVersion, '42'); 53 | });*/ 54 | } 55 | --------------------------------------------------------------------------------