banking_dcb_sdk_flutter 1.0.7 copy "banking_dcb_sdk_flutter: ^1.0.7" to clipboard
banking_dcb_sdk_flutter: ^1.0.7 copied to clipboard

Partner UI Integration Library for Flutter

example/lib/main.dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:app_links/app_links.dart';
import 'package:banking_dcb_sdk_flutter/banking_dcb_sdk_flutter.dart';
import 'package:banking_dcb_sdk_flutter_example/DeepLinkTest.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';

import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';

import 'DeepLinkTest2.dart';

class MyHttpOverrides extends HttpOverrides {
  @override
  HttpClient createHttpClient(SecurityContext? context) {
    return super.createHttpClient(context)
      ..badCertificateCallback =
          (X509Certificate cert, String host, int port) => true;
  }
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await dotenv.load(fileName: "lib/.env");
  HttpOverrides.global = MyHttpOverrides();
  await BankingDcbSdkFlutter.init(
    dotenv.env['BASE_URL']!,
    whitelistedDomains: [
      "razorpay.com",
      "m2pfintech.com",
      "https://capture.kyc.idfy.com"
    ],
    deviceBindingEnabled: false,
  );

  runApp(MyApp());
}

final GlobalKey<NavigatorState> navKey = GlobalKey<NavigatorState>();

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _appLinks = AppLinks();
  StreamSubscription<Uri>? _sub;

  Uri? _pendingUri; // for when navigator isn't ready yet

  @override
  void initState() {
    super.initState();
    _setupDeepLinks();
  }

  Future<void> _setupDeepLinks() async {
    // Cold start
    final initial = await _appLinks.getInitialLink();
    if (initial != null) {
      _handleDeepLink(initial);
    }

    // While running / in background
    _sub = _appLinks.uriLinkStream.listen(
          (uri) => _handleDeepLink(uri),
      onError: (e) => debugPrint("DeepLink error: $e"),
    );
  }

  void _handleDeepLink(Uri uri) {
    debugPrint("DeepLink received: $uri");

    if (uri.scheme == "dcbexample" && uri.host == "deeplink_test") {
      _pendingUri = uri;

      WidgetsBinding.instance.addPostFrameCallback((_) {
        final nav = navKey.currentState;
        if (nav == null) {
          debugPrint("Navigator not ready yet, keeping pendingUri");
          return;
        }

        // Clear pending uri
        final toOpen = _pendingUri;
        _pendingUri = null;

        if (toOpen != null) {
          debugPrint("Navigating to DeepLinkTest for $toOpen");
          nav.push(
            MaterialPageRoute(builder: (_) => DeepLinkTest()),
          );
        }
      });
    }
  }

  @override
  void dispose() {
    _sub?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: navKey,
      debugShowCheckedModeBanner: false,
      home: FirstPage(),
    );
  }
}
class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Welcome'),
      ),
      body: Column(children: [
        Center(
          child: ElevatedButton(
            child: Text('Go to Home'),
            onPressed: () {
              // If you don't want to come back to this screen on back press:
              Navigator.push(
                context,
                MaterialPageRoute(builder: (_) => MyHome()),
              );
            },
          ),
        ),
        ElevatedButton(
            onPressed: () {
              Navigator.of(context).push(MaterialPageRoute(
                builder: (context) => DeepLinkTest(),
              ));
            },
            child: Text('Deeplink Test'))
      ]),
    );
  }
}

class MyHome extends StatefulWidget {
  @override
  _MyHomeState createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {
  final _formKey = GlobalKey<FormState>();
  final _nameController = TextEditingController();
  final _emailController = TextEditingController();
  final _phoneController = TextEditingController();
  final _prospectIDController = TextEditingController();
  final _partnerUserIdController = TextEditingController();

  String name = '';
  String email = '';
  String phone = '';

  // final String? clientId = dotenv.env['KID'];
  String baseUrl = '';
  String token = '';

  @override
  void initState() {
    baseUrl = dotenv.env['BASE_URL']!;
    super.initState();
    // _setupDeepLinks();
    _checkSession((WebViewCallback action) {
      switch (action.type) {
        case WebViewCallbackType.redirect:
          print("Redirected with status: ${action.status}");
          break;
        case WebViewCallbackType.logout:
          print("User logged out");
          break;
      }
    });
  }

  Future<void> _checkSession(WebViewCallbackFunction callback) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();

    String? name = prefs.getString('name');
    String? email = prefs.getString('email');
    String? phone = prefs.getString('phone');
    setState(() {
      _nameController.text = name ?? '';
      _emailController.text = email ?? '';
      _phoneController.text = phone ?? '';
    });
  }

  Future<void> createToken(
      //SBM
      String module,
      String photo,
      WebViewCallbackFunction callback,
      {String? nameInput,
      String? emailInput,
      String? phoneInput}) async {
    setState(() {
      name = nameInput?.isNotEmpty == true ? nameInput! : _nameController.text;
      email =
          emailInput?.isNotEmpty == true ? emailInput! : _emailController.text;
      phone =
          phoneInput?.isNotEmpty == true ? phoneInput! : _phoneController.text;
    });
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString('name', name);
    await prefs.setString('email', email);
    await prefs.setString('phone', phone);
    final String clientId = dotenv.env['KID']!;
    print("clientId  $clientId");
    final Map<String, Object> headers = {
      'kid': clientId,
      'typ': 'JWT',
      'alg': 'HS256',
    };

    final Map<String, String> attributes = {
      'name': name.trim(),
      'photo': photo,
      "partner_user_id": _partnerUserIdController.text.trim() ?? "1234"
    };
    const Duration expirationDuration = Duration(milliseconds: 300000);
    final clientSecret = dotenv.env['CLIENT_SECRET'];
    print("clientSecret $clientSecret");
    final jwt = JWT(
      {
        'attributes': attributes,
        // 'module': '/banking/dcb/credit_card/CRE',
        // "redirect_url": "https://credilio.in",
        "prospect_id": _prospectIDController.text.trim(),
        "device_binded": true,
      },
      header: headers,
    );

    token = await jwt.sign(
      SecretKey(clientSecret!),
      expiresIn: expirationDuration,
    );

    print("Token generated FROM client side is: $token  for module $module");
    final sdkLoginResponse = await BankingDcbSdkFlutter.instance
        .sdkLogin(context, token: token, partner: 'dcb');
    print("sdkLoginResponse $sdkLoginResponse");
    //do some activity

    final publicApiResponse = await BankingDcbSdkFlutter.instance.publicCallAPI(
      '',
      'POST',
      body: {'token': token},
    );

    print("Public API response: ${publicApiResponse}");
    //do some activity

    await BankingDcbSdkFlutter.instance.open(context, module, token, callback);
  }

  @override
  void dispose() {
    _nameController.dispose();
    _emailController.dispose();
    _phoneController.dispose();
    _prospectIDController.dispose();
    _partnerUserIdController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Form(
            key: _formKey,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Row(
                  children: [
                    Spacer(),
                    SizedBox(
                      height: 48,
                      child: TextButton(
                        style: TextButton.styleFrom(
                          foregroundColor: Colors.black,
                        ),
                        onPressed: () {
                          if (_formKey.currentState!.validate()) {
                            createToken(dotenv.env['SPENSE_MODULE']!, '',
                                (WebViewCallback action) {
                              switch (action.type) {
                                case WebViewCallbackType.redirect:
                                  print(
                                      "Redirected with status: ${action.status}");
                                  break;
                                case WebViewCallbackType.logout:
                                  print("User logged out");
                                  break;
                              }
                            });
                          }
                        },
                        child: const Text(
                          'Dashboard',
                          style: TextStyle(
                            fontWeight: FontWeight.bold,
                            fontSize: 20,
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
                SizedBox(height: MediaQuery.of(context).size.height * 0.02),
                const Text(
                  'User Details',
                  style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
                ),
                SizedBox(height: MediaQuery.of(context).size.height * 0.02),
                TextFormField(
                  controller: _prospectIDController,
                  decoration: const InputDecoration(
                    fillColor: Colors.grey,
                    labelText: 'Prospect ID',
                    border: OutlineInputBorder(),
                  ),
                  validator: (value) {
                    if (value == null || value.isEmpty) {
                      return 'Please enter your prospect ID';
                    }
                    return null;
                  },
                ),
                SizedBox(
                  height: 48,
                  child: TextButton(
                    style: TextButton.styleFrom(
                      foregroundColor: Colors.black,
                    ),
                    onPressed: () {
                      if (_formKey.currentState!.validate()) {
                        createToken('${dotenv.env['MODULE']!}/pay_bill', '',
                            (WebViewCallback action) {
                          switch (action.type) {
                            case WebViewCallbackType.redirect:
                              print("Redirected with status: ${action.status}");
                              break;
                            case WebViewCallbackType.logout:
                              print("User logged out");
                              break;
                          }
                        });
                      }
                    },
                    child: const Text(
                      'Pay Bill',
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 20,
                      ),
                    ),
                  ),
                ),
                SizedBox(
                  height: 48,
                  child: TextButton(
                    style: TextButton.styleFrom(
                      foregroundColor: Colors.black,
                    ),
                    onPressed: () {
                      createToken(
                          '/banking/dcb/credit_card/ZET/card_limits', '',
                          (WebViewCallback action) {
                        switch (action.type) {
                          case WebViewCallbackType.redirect:
                            print("Redirected with status: ${action.status}");
                            break;
                          case WebViewCallbackType.logout:
                            print("User logged out");
                            break;
                        }
                      });
                    },
                    child: const Text(
                      'Manage Card',
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 20,
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}