sms_insights_flutter 0.0.1-dev.1
sms_insights_flutter: ^0.0.1-dev.1 copied to clipboard
Flutter plugin wrapping the PayU SMS Insights Android SDK (core + optional logger). Reads transactional SMS for credit assessment with consent-based permission flow.
sms_insights_flutter #
Flutter plugin that wraps the PayU SMS Insights Android SDKs. Reads transactional SMS for credit-assessment with a consent-based permission flow, and exposes optional logging / analytics hooks.
Android only (
minSdk 21). Calling the plugin on iOS raisesMissingPluginException.
What it wraps #
| Native artifact | Maven coordinate | Required? |
|---|---|---|
| Core SDK | in.payuinnovations:payuinnovations-smsinsights-core-sdk:1.0.0 |
Yes (declared by the plugin) |
| Logger SDK | in.payuinnovations:payuinnovations-smsinsights-logger-sdk:1.0.0 |
No (you add it in your app's build.gradle if you want logging) |
The plugin exposes two customer-facing Dart classes:
SmsSdkWrapper— full lifecycle for the SMS Insights core SDK (init,startSync,setDeviceMatch,forgetUser) plus aStream<SdkEvent>for callbacks.LoggerWrapper—setLog,setIdentity,logEvent. ThrowsLoggerNotInstalledExceptionif the optional logger artifact is missing from the consumer app.
Getting Started #
Step 1: Add the plugin to your app #
In your Flutter app's pubspec.yaml:
dependencies:
sms_insights_flutter: ^0.0.1
Then:
flutter pub get
Step 2: Permissions #
All seven required permissions are declared in the plugin's own
AndroidManifest.xml and are automatically merged into your app
via Android's manifest merger — you do not need to add anything to
your app's manifest.
| Permission | Type |
|---|---|
INTERNET |
normal |
READ_SMS |
dangerous |
ACCESS_COARSE_LOCATION |
dangerous |
ACCESS_FINE_LOCATION |
dangerous |
READ_PHONE_STATE |
dangerous |
READ_PHONE_NUMBERS |
dangerous |
QUERY_ALL_PACKAGES |
dangerous |
Use a runtime-permission package (e.g. permission_handler) to
prompt the user for dangerous permissions — the SDK asks for them
via the RequestPermissionsEvent / startSyncAndHandlePermissions
flow described in Step 5.
Step 3 (optional): Enable logging #
If you want OpenTelemetry traces and CleverTap analytics, add the
optional logger artifact to your app's android/app/build.gradle:
dependencies {
implementation "in.payuinnovations:payuinnovations-smsinsights-logger-sdk:1.0.0"
}
Skip this step if you don't need logging — LoggerWrapper will simply
throw LoggerNotInstalledException and SmsSdkWrapper will continue to
work normally.
Step 4: Initialise the SDK #
import 'package:sms_insights_flutter/sms_insights_flutter.dart';
await SmsSdkWrapper.instance.init(
const SdkClientConfig(
clientEmail: 'you@yourcompany.com',
accessId: 'your-access-key',
customerId: 'end-user-id',
// optional fields:
upperLimit: 180,
fcmToken: null,
salaryInRs: 50000,
companyName: 'Acme Corp',
),
);
init returns once the native call returns. Auth result arrives via the
events stream:
SmsSdkWrapper.instance.events.listen((event) {
switch (event) {
case InitSuccessEvent():
print('SDK ready');
case InitFailureEvent(:final code, :final message):
print('init failed ($code): $message');
default:
// handle other events
}
});
Step 5: Start sync (with permission handshake) #
import 'package:permission_handler/permission_handler.dart';
await SmsSdkWrapper.instance.startSyncAndHandlePermissions(
onPermissionsRequested: _requestPermissions,
);
/// Maps the SDK's Android permission strings to permission_handler objects,
/// then requests them all in a single system dialog (same as Kotlin's
/// requestPermissionsLauncher.launch(permissions.toTypedArray())).
Future<List<String>> _requestPermissions(List<String> requested) async {
// Build Permission → [android name, ...] map.
// ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION both map to
// Permission.location; when location is granted both strings are returned.
final mapping = <Permission, List<String>>{};
for (final p in requested) {
final handler = switch (p) {
'android.permission.READ_SMS' => Permission.sms,
'android.permission.ACCESS_FINE_LOCATION' => Permission.location,
'android.permission.ACCESS_COARSE_LOCATION' => Permission.location,
'android.permission.READ_PHONE_STATE' => Permission.phone,
'android.permission.READ_PHONE_NUMBERS' => Permission.phone,
_ => null,
};
if (handler != null) (mapping[handler] ??= []).add(p);
}
if (mapping.isEmpty) return [];
final statuses = await mapping.keys.toList().request();
return [
for (final entry in statuses.entries)
if (entry.value.isGranted) ...?mapping[entry.key],
];
}
If you'd rather drive the handshake yourself, listen for
RequestPermissionsEvent on events and call
SmsSdkWrapper.instance.grantPermissions(...) manually.
Running the bundled example #
cd example
# create dart_defines.json and fill in CLIENT_EMAIL and ACCESS_KEY
flutter run --dart-define-from-file=dart_defines.json
VS Code users: open example/ as the workspace and press F5 —
launch.json passes the file automatically.
Step 6: Optional logging #
final available = await LoggerWrapper.instance.isAvailable;
if (available) {
await LoggerWrapper.instance.setIdentity(
customerId: 'end-user-id',
clientEmail: 'you@yourcompany.com',
);
await LoggerWrapper.instance.setLog('SDK initialised');
await LoggerWrapper.instance.logEvent(
'SDK_INIT_SUCCESS',
data: {'source': 'flutter'},
);
}
Step 7: Forget user / cleanup #
await SmsSdkWrapper.instance.forgetUser();
Cancels all background sync workers and purges persisted state.
API Reference #
SmsSdkWrapper #
Future<void> init(SdkClientConfig config)Future<void> startSync()Future<void> startSyncAndHandlePermissions({required PermissionRequestHandler onPermissionsRequested})Future<bool> grantPermissions({required String requestId, required List<String> grantedPermissions})Future<void> setDeviceMatch(DeviceMatch match)Future<void> forgetUser()Future<void> dispose()Stream<SdkEvent> get events
LoggerWrapper #
Future<bool> get isAvailableFuture<void> setLog(String message, {List<Object?> args = const []})Future<void> setIdentity({String? customerId, String? androidId, String? clientEmail})Future<void> logEvent(String eventName, {Map<String, Object> data = const {}})
Models #
SdkClientConfig({required clientEmail, required accessId, required customerId, upperLimit?, fcmToken?, salaryInRs?, companyName?})DeviceMatch({email?, name?, phoneNo?})
Events (sealed SdkEvent) #
InitSuccessEvent, InitFailureEvent, RequestPermissionsEvent,
SmsSyncSuccessEvent, NoMessagesToSyncEvent, AuthFailureEvent,
UploadFailureEvent, ConfigFailureEvent, ForgetUserFailureEvent,
MatchDeviceFailureEvent, PermissionNotAvailableEvent,
SdkConfigFailureEvent, InitNotCalledEvent, UnknownSdkEvent.
Error handling #
All synchronous failures surface as SmsInsightsException:
INVALID_ARGUMENT— a required field was empty or the wrong type.NATIVE_ERROR— the native SDK threw; checkdetailsfor the Kotlin stack trace.loggerNotInstalled— the consumer app did not add the optional logger Maven artifact (raised asLoggerNotInstalledException, which is a subclass ofSmsInsightsException).
Asynchronous failures from the native SDK arrive on the events
stream — handle InitFailureEvent, AuthFailureEvent,
UploadFailureEvent, etc.
Permissions reference #
android.permission.INTERNETandroid.permission.READ_SMSandroid.permission.ACCESS_COARSE_LOCATIONandroid.permission.ACCESS_FINE_LOCATIONandroid.permission.READ_PHONE_STATEandroid.permission.READ_PHONE_NUMBERSandroid.permission.QUERY_ALL_PACKAGES
Troubleshooting #
LoggerNotInstalledException— addimplementation "in.payuinnovations:payuinnovations-smsinsights-logger-sdk:1.0.0"to your app'sandroid/app/build.gradleand rebuild. Or callLoggerWrapper.instance.isAvailablefirst to skip logger calls gracefully.InitNotCalledEventafterstartSync— callinitand wait forInitSuccessEventbefore invokingstartSync.PermissionNotAvailableEvent— the user denied one or more required permissions; the SDK falls back to whatever it can do with the granted subset. Re-request viastartSynconce permissions are available.
License #
Apache-2.0. See LICENSE.