Test Sim Binding APK

This commit is contained in:
2025-12-11 12:18:25 +05:30
parent 8149ef2a5b
commit 715162b713
5 changed files with 159 additions and 185 deletions

View File

@@ -8,73 +8,40 @@ class AuthService {
final Dio _dio; final Dio _dio;
AuthService(this._dio); AuthService(this._dio);
Future <void> simVerify(String uuid, String cifNo) async{ Future<void> simVerify(String uuid, String cifNo) async {
try {
final response = await _dio.post('/api/sim-details-verify', data: {
'uuid': uuid,
'cifNo': cifNo,
});
try{ if (response.statusCode == 200) {
final String message = response.data.toString().toUpperCase();
final response = await _dio.post(
'/api/sim-details-verify',
data: {
'uuid': uuid,
'cifNo': cifNo,
}
);
if (response.statusCode == 200) {
final String message = response.data.toString().toUpperCase();
if (message.contains("VERIFIED")) {
return; // Success
} else {
throw AuthException(message); // Throw message received
}
if (message.contains("VERIFIED")) {
return; // Success
} else { } else {
throw AuthException(message); // Throw message received
throw AuthException('Verification Failed');
} }
} else {
} on DioException catch (e) { throw AuthException('Verification Failed');
}
if (kDebugMode) { } on DioException catch (e) {
if (kDebugMode) {
print(e.toString()); print(e.toString());
}
if (e.response?.statusCode == 401) {
throw AuthException(
e.response?.data['error'] ?? 'SOMETHING WENT WRONG');
}
throw NetworkException('Network error during verification');
} }
catch (e) { if (e.response?.statusCode == 401) {
throw AuthException(
throw UnexpectedException( e.response?.data['error'] ?? 'SOMETHING WENT WRONG');
'Unexpected error during verification: ${e.toString()}');
} }
throw NetworkException('Network error during verification');
} catch (e) {
throw UnexpectedException(
'Unexpected error during verification: ${e.toString()}');
} }
}
Future<AuthToken> login(AuthCredentials credentials) async { Future<AuthToken> login(AuthCredentials credentials) async {
try { try {

View File

@@ -1,102 +1,102 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:send_message/send_message.dart' show sendSMS; import 'package:send_message/send_message.dart' show sendSMS;
import 'package:simcards/sim_card.dart'; import 'package:simcards/sim_card.dart';
import 'package:simcards/simcards.dart'; import 'package:simcards/simcards.dart';
// This enum provides detailed status back to the UI layer. // This enum provides detailed status back to the UI layer.
enum PermissionStatusResult { granted, denied, permanentlyDenied, restricted } enum PermissionStatusResult { granted, denied, permanentlyDenied, restricted }
class SmsService { class SmsService {
final Simcards _simcards = Simcards(); final Simcards _simcards = Simcards();
/// Handles the requesting of SMS and Phone permissions. /// Handles the requesting of SMS and Phone permissions.
/// Returns a detailed status: granted, denied, or permanentlyDenied. /// Returns a detailed status: granted, denied, or permanentlyDenied.
Future<PermissionStatusResult> handleSmsPermission() async { Future<PermissionStatusResult> handleSmsPermission() async {
var smsStatus = await Permission.sms.status; var smsStatus = await Permission.sms.status;
var phoneStatus = await Permission.phone.status; var phoneStatus = await Permission.phone.status;
// Check initial status // Check initial status
if (smsStatus.isGranted && phoneStatus.isGranted) { if (smsStatus.isGranted && phoneStatus.isGranted) {
return PermissionStatusResult.granted; return PermissionStatusResult.granted;
} }
if (smsStatus.isPermanentlyDenied || phoneStatus.isPermanentlyDenied) { if (smsStatus.isPermanentlyDenied || phoneStatus.isPermanentlyDenied) {
return PermissionStatusResult.permanentlyDenied; return PermissionStatusResult.permanentlyDenied;
} }
if (smsStatus.isRestricted || phoneStatus.isRestricted) { if (smsStatus.isRestricted || phoneStatus.isRestricted) {
return PermissionStatusResult.restricted; return PermissionStatusResult.restricted;
} }
// Request permissions if not granted // Request permissions if not granted
print("Requesting SMS and Phone permissions..."); print("Requesting SMS and Phone permissions...");
await [Permission.phone, Permission.sms].request(); await [Permission.phone, Permission.sms].request();
// Re-check status after request // Re-check status after request
smsStatus = await Permission.sms.status; smsStatus = await Permission.sms.status;
phoneStatus = await Permission.phone.status; phoneStatus = await Permission.phone.status;
if (smsStatus.isGranted && phoneStatus.isGranted) { if (smsStatus.isGranted && phoneStatus.isGranted) {
return PermissionStatusResult.granted; return PermissionStatusResult.granted;
} }
if (smsStatus.isPermanentlyDenied || phoneStatus.isPermanentlyDenied) { if (smsStatus.isPermanentlyDenied || phoneStatus.isPermanentlyDenied) {
return PermissionStatusResult.permanentlyDenied; return PermissionStatusResult.permanentlyDenied;
} }
if (smsStatus.isRestricted || phoneStatus.isRestricted) { if (smsStatus.isRestricted || phoneStatus.isRestricted) {
return PermissionStatusResult.restricted; return PermissionStatusResult.restricted;
} }
// If none of the above, it's denied // If none of the above, it's denied
return PermissionStatusResult.denied; return PermissionStatusResult.denied;
} }
/// Tries to send a single verification SMS. /// Tries to send a single verification SMS.
/// This should only be called AFTER permissions have been granted. /// This should only be called AFTER permissions have been granted.
Future<bool> sendVerificationSms({ Future<bool> sendVerificationSms({
required BuildContext context, required BuildContext context,
required String destinationNumber, required String destinationNumber,
required String message, required String message,
}) async { }) async {
try { try {
List<SimCard> simCardList = await _simcards.getSimCards(); List<SimCard> simCardList = await _simcards.getSimCards();
if (simCardList.isEmpty) { if (simCardList.isEmpty) {
print("No SIM card detected."); print("No SIM card detected.");
return false; return false;
} }
return await _sendSms(destinationNumber, message, simCardList.first); return await _sendSms(destinationNumber, message, simCardList.first);
} catch (e) { } catch (e) {
print("An error occurred in the SMS process: $e"); print("An error occurred in the SMS process: $e");
return false; return false;
} }
} }
/// Private function to perform the SMS sending action. /// Private function to perform the SMS sending action.
Future<bool> _sendSms( Future<bool> _sendSms(
String destinationNumber, String message, SimCard selectedSim) async { String destinationNumber, String message, SimCard selectedSim) async {
if (Platform.isAndroid) { if (Platform.isAndroid) {
try { try {
String smsMessage = message; String smsMessage = message;
String result = await sendSMS( String result = await sendSMS(
message: smsMessage, message: smsMessage,
recipients: [destinationNumber], recipients: [destinationNumber],
sendDirect: true, sendDirect: true,
); );
print("Background SMS send attempt result: $result"); print("Background SMS send attempt result: $result");
if (result.toLowerCase().contains('sent')) { if (result.toLowerCase().contains('sent')) {
print("Success: SMS appears to have been sent."); print("Success: SMS appears to have been sent.");
return true; return true;
} else { } else {
print("Failure: SMS was not sent. Result: $result"); print("Failure: SMS was not sent. Result: $result");
return false; return false;
} }
} catch (e) { } catch (e) {
print("Error attempting to send SMS directly: $e"); print("Error attempting to send SMS directly: $e");
return false; return false;
} }
} else { } else {
print("SMS sending is only supported on Android."); print("SMS sending is only supported on Android.");
return false; return false;
} }
} }
} }

View File

@@ -75,8 +75,8 @@ Dio _createDioClient() {
BaseOptions( BaseOptions(
baseUrl: baseUrl:
'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com:8080', //test 'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com:8080', //test
//'http://lb-kccb-mobile-banking-app-848675342.ap-south-1.elb.amazonaws.com', //prod //'http://lb-kccb-mobile-banking-app-848675342.ap-south-1.elb.amazonaws.com', //prod
//'https://kccbmbnk.net', //prod small //'https://kccbmbnk.net', //prod small
connectTimeout: const Duration(seconds: 60), connectTimeout: const Duration(seconds: 60),
receiveTimeout: const Duration(seconds: 60), receiveTimeout: const Duration(seconds: 60),
headers: { headers: {

View File

@@ -1,4 +1,3 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/api/services/send_sms_service.dart'; import 'package:kmobile/api/services/send_sms_service.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
@@ -12,7 +11,8 @@ class SmsVerificationHelper {
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
title: const Text("Permission Required"), title: const Text("Permission Required"),
content: const Text("SMS and Phone permissions are required for device verification. Please enable them in your app settings to continue."), content: const Text(
"SMS and Phone permissions are required for device verification. Please enable them in your app settings to continue."),
actions: [ actions: [
TextButton( TextButton(
child: const Text("Cancel"), child: const Text("Cancel"),
@@ -39,17 +39,24 @@ class SmsVerificationHelper {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text("It seems your device is restricting this app from sending SMS messages, which is required for verification. Please follow these steps to enable it:\n"), Text(
Text("1. Open your device Settings.", style: TextStyle(fontWeight: FontWeight.bold)), "It seems your device is restricting this app from sending SMS messages, which is required for verification. Please follow these steps to enable it:\n"),
Text("1. Open your device Settings.",
style: TextStyle(fontWeight: FontWeight.bold)),
Text("2. Go to 'Apps' or 'Apps & notifications'."), Text("2. Go to 'Apps' or 'Apps & notifications'."),
Text("3. Find and tap on this app ('KMobile')."), Text("3. Find and tap on this app ('KMobile')."),
Text("4. Tap on the three dots (⋮) in the top right corner."), Text("4. Tap on the three dots (⋮) in the top right corner."),
Text("5. Select 'Allow restricted settings' and confirm. This is crucial to allow SMS permission."), Text(
"5. Select 'Allow restricted settings' and confirm. This is crucial to allow SMS permission."),
Text("6. Now you have two options to allow SMS permission:"), Text("6. Now you have two options to allow SMS permission:"),
Text(" a. Tap on 'Permissions', then find 'SMS' is set to 'Allow'."), Text(
Text(" b. Alternatively, you can return to the KMobile app, and the SMS permission pop-up should appear again, allowing you to grant it directly."), " a. Tap on 'Permissions', then find 'SMS' is set to 'Allow'."),
Text("\nSome devices have an additional setting for 'Premium SMS'. If the above doesn't work, look for a 'Premium SMS access' setting (you can search for it in your Settings app) and set it to 'Always Allow' for this app.\n"), Text(
Text("After you've enabled the permission, please come back to the app."), " b. Alternatively, you can return to the KMobile app, and the SMS permission pop-up should appear again, allowing you to grant it directly."),
Text(
"\nSome devices have an additional setting for 'Premium SMS'. If the above doesn't work, look for a 'Premium SMS access' setting (you can search for it in your Settings app) and set it to 'Always Allow' for this app.\n"),
Text(
"After you've enabled the permission, please come back to the app."),
], ],
), ),
), ),
@@ -63,15 +70,6 @@ class SmsVerificationHelper {
); );
} }
void _showSnackBar(BuildContext context, String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
duration: const Duration(seconds: 3),
),
);
}
Future<String?> initiateSmsSequence({ Future<String?> initiateSmsSequence({
required BuildContext context, required BuildContext context,
}) async { }) async {
@@ -85,7 +83,9 @@ class SmsVerificationHelper {
switch (status) { switch (status) {
case PermissionStatusResult.granted: case PermissionStatusResult.granted:
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Permissions Granted! Proceeding..."), duration: Duration(seconds: 2)), const SnackBar(
content: Text("Permissions Granted! Proceeding..."),
duration: Duration(seconds: 2)),
); );
hasPermission = true; // This will break the loop hasPermission = true; // This will break the loop
break; break;
@@ -96,7 +96,8 @@ class SmsVerificationHelper {
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
title: const Text("Permission Required"), title: const Text("Permission Required"),
content: const Text("This app requires SMS and Phone permissions to verify your device. Please grant the permissions to continue."), content: const Text(
"This app requires SMS and Phone permissions to verify your device. Please grant the permissions to continue."),
actions: [ actions: [
TextButton( TextButton(
child: const Text("Cancel"), child: const Text("Cancel"),
@@ -136,9 +137,12 @@ class SmsVerificationHelper {
var uuid = const Uuid(); var uuid = const Uuid();
String uniqueId = uuid.v4(); String uniqueId = uuid.v4();
String smsMessage = uniqueId; String smsMessage = uniqueId;
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Attempting to send verification SMS... (${4 - retries})"), duration: const Duration(seconds: 2)), SnackBar(
content:
Text("Attempting to send verification SMS... (${4 - retries})"),
duration: const Duration(seconds: 2)),
); );
bool isSmsSent = await _smsService.sendVerificationSms( bool isSmsSent = await _smsService.sendVerificationSms(
@@ -148,21 +152,25 @@ class SmsVerificationHelper {
); );
if (isSmsSent) { if (isSmsSent) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("SMS sent successfully!"), duration: Duration(seconds: 2)), const SnackBar(
content: Text("SMS sent successfully!"),
duration: Duration(seconds: 2)),
); );
return uniqueId; return uniqueId;
} else { } else {
retries--; retries--;
if (retries > 0) { if (retries > 0) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("SMS failed to send. Retrying in 5 seconds..."), duration: Duration(seconds: 4)), const SnackBar(
content: Text("SMS failed to send. Retrying in 5 seconds..."),
duration: Duration(seconds: 4)),
); );
await Future.delayed(const Duration(seconds: 5)); await Future.delayed(const Duration(seconds: 5));
} }
} }
} }
// If all retries fail // If all retries fail
return null; return null;
} }

View File

@@ -78,7 +78,7 @@ class _VerificationScreenState extends State<VerificationScreen> {
setState(() { setState(() {
_statusMessage = "SMS sent. Waiting for network delivery..."; _statusMessage = "SMS sent. Waiting for network delivery...";
}); });
// Adding a 10-second delay to account for SMS network latency. // Adding a 10-second delay to account for SMS network latency.
await Future.delayed(const Duration(seconds: 10)); await Future.delayed(const Duration(seconds: 10));
@@ -101,7 +101,6 @@ class _VerificationScreenState extends State<VerificationScreen> {
// Pop with success result // Pop with success result
Navigator.of(context).pop(true); Navigator.of(context).pop(true);
} catch (e) { } catch (e) {
setState(() { setState(() {
_statusMessage = e.toString(); _statusMessage = e.toString();
@@ -111,7 +110,8 @@ class _VerificationScreenState extends State<VerificationScreen> {
} }
} else if (mounted) { } else if (mounted) {
setState(() { setState(() {
_statusMessage = "SMS sending failed. Please check permissions and try again."; _statusMessage =
"SMS sending failed. Please check permissions and try again.";
_isVerifying = false; _isVerifying = false;
_verificationFailed = true; _verificationFailed = true;
}); });
@@ -131,13 +131,12 @@ class _VerificationScreenState extends State<VerificationScreen> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
if (_isVerifying) if (_isVerifying) const CircularProgressIndicator(),
const CircularProgressIndicator(),
if (!_isVerifying && _verificationFailed) if (!_isVerifying && _verificationFailed)
const Icon(Icons.error_outline, color: Colors.red, size: 50), const Icon(Icons.error_outline, color: Colors.red, size: 50),
if (!_isVerifying && !_verificationFailed) if (!_isVerifying && !_verificationFailed)
const Icon(Icons.check_circle_outline, color: Colors.green, size: 50), const Icon(Icons.check_circle_outline,
color: Colors.green, size: 50),
const SizedBox(height: 32), const SizedBox(height: 32),
Text( Text(
_statusMessage, _statusMessage,
@@ -163,4 +162,4 @@ class _VerificationScreenState extends State<VerificationScreen> {
), ),
); );
} }
} }