How to launch a ViewController from Flutter Platform Specific code written in Swift?
One of my friends @virander helped me with this issue. He has written the code to open the view controller from the swift plugin file.
if let navigationController = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController {
navigationController.pushViewController(self.paytmTransactionController!, animated: true)
}
let storyboard : UIStoryboard? = UIStoryboard.init(name: "Main", bundle: nil);
let window: UIWindow = ((UIApplication.shared.delegate?.window)!)!
let objVC: UIViewController? = storyboard!.instantiateViewController(withIdentifier: "FlutterViewController")
let aObjNavi = UINavigationController(rootViewController: objVC!)
window.rootViewController = aObjNavi
aObjNavi.pushViewController(self.paytmTransactionController!, animated: true)
Using this code, I am able to trigger the PayTM View Controller from the Swift Plugin class.
Rohit Gupta
Updated on December 08, 2022Comments
-
Rohit Gupta over 1 year
I am creating a plugin for Paytm and written platform specific code for both Android and iOS.
Paytm is payment gateway service in India and super easy to configure and integrate it in the app. It required some configurations and the last step is to start the payment transaction which internally opens its own Activity on Android and ViewController on iOS platform.
I tested the Android part of the plugin. It's working fine.
But I don't know how to fire a viewController in iOS. I am using swift for iOS coding part.
func beginPayment() { serv = serv.createProductionEnvironment() let type :ServerType = .eServerTypeProduction let order = PGOrder(orderID: "", customerID: "", amount: "", eMail: "", mobile: "") order.params = [ "MID": "rxazcv89315285244163", "ORDER_ID": "order1", "CUST_ID": "cust123", "MOBILE_NO": "7777777777", "EMAIL": "[email protected]", "CHANNEL_ID": "WAP", "WEBSITE": "WEBSTAGING", "TXN_AMOUNT": "100.12", "INDUSTRY_TYPE_ID": "Retail", "CHECKSUMHASH": "oCDBVF+hvVb68JvzbKI40TOtcxlNjMdixi9FnRSh80Ub7XfjvgNr9NrfrOCPLmt65UhStCkrDnlYkclz1qE0uBMOrmuKLGlybuErulbLYSQ=", "CALLBACK_URL": "https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=order1" ] self.txnController = self.txnController.initTransaction(for: order) as?PGTransactionViewController self.txnController.title = "Paytm Payments" self.txnController.setLoggingEnabled(true) if(type != ServerType.eServerTypeNone) { self.txnController.serverType = type; } else { return } self.txnController.merchant = PGMerchantConfiguration.defaultConfiguration() self.txnController.delegate = self self.navigationController?.pushViewController(self.txnController, animated: true) }
This is the demonstration on how to trigger a Paytm transaction controller written in the PayTM iOS SDK documentation page.
This is the code which I have written to attain the above process.
import Flutter import PaymentSDK import UIKit /* A delegate interface that exposes all of the PayTM Payment Gateway functionality for other plugins to use. The below [Delegate] implementation should be used by any clients unless they need to override some of these functions, such as for testing. */ protocol IDelegate { // Initializes this delegate so that it can perform transaction operation func initializePaytmService(result: @escaping FlutterResult, buildVariant: String?) // Returns the PayTM transaction status without displaying any user interface. func startPaymentTransaction(result: @escaping FlutterResult, checkSumRequestObject: Dictionary<String, String>?) } /* Delegate class will have the code for making PayTM Transactions. */ class FlutterPaytmPluginDelegate : IDelegate, PGTransactionDelegate { private let flutterRegistrar: FlutterPluginRegistrar private var viewController: UIViewController private var serverType: ServerType? private var pendingOperation: PendingOperation? private var paytmTransactionController: PGTransactionViewController? let release = "BuildVariant.release" let debug = "BuildVariant.debug" //Method Constants let methodInitPaytmService = "initialize_paytm_service" let methodStartPaymentTransaction = "start_payment_transaction" //PayTM Success Response Constants let paytmStatus = "STATUS" let paytmChecksumHash = "CHECKSUMHASH" let paytmBankName = "BANKNAME" let paytmOrderId = "ORDERID" let paytmTransactionAmount = "TXNAMOUNT" let paytmTransactionDate = "TXNDATE" let paytmMerchantId = "MID" let paytmTransactionId = "TXNID" let paytmResponseCode = "RESPCODE" let paytmPaymentMode = "PAYMENTMODE" let paytmBankTransactionId = "BANKTXNID" let paytmCurrency = "CURRENCY" let paytmGatewayName = "GATEWAYNAME" let paytmResponseMessage = "RESPMSG" //Error Constants let errorReasonBuildVariantNotPassed = "build_variant_not_passed" let errorReasonChecksumObjectNotPassed = "checksum_request_object_not_passed" // These error codes must match with ones declared on iOS and Dart sides. let errorReasonPaytmTransactionResponseNull = "paytm_transaction_response_null" let errorReasonPaytmTransactionCancelled = "paytm_transaction_cancelled" let errorReasonPaytmMissingParameters = "paytm_missing_parameters" init(registrar: FlutterPluginRegistrar, viewController: UIViewController) { self.flutterRegistrar = registrar self.viewController = viewController } /* Initializes this delegate so that it is ready to perform other operations. The Dart code guarantees that this will be called and completed before any other methods are invoked. */ func initializePaytmService(result: @escaping FlutterResult, buildVariant: String?) { if buildVariant?.isEmpty ?? true { result(FlutterError(code: errorReasonBuildVariantNotPassed, message: "Need a build variant", details: nil)) } else { serverType = buildVariant == release ? .eServerTypeProduction : .eServerTypeStaging result(nil) } } func startPaymentTransaction(result: @escaping FlutterResult, checkSumRequestObject: Dictionary<String, String>?) { if checkSumRequestObject?.isEmpty ?? true { result(FlutterError(code: errorReasonChecksumObjectNotPassed, message: "Need a build variant", details: nil)) } else { checkAndSetPendingOperation(method: methodStartPaymentTransaction, result: result) let order = PGOrder(orderID: "", customerID: "", amount: "", eMail: "", mobile: "") order.params = checkSumRequestObject! self.paytmTransactionController = paytmTransactionController?.initTransaction(for: order) as? PGTransactionViewController ?? PGTransactionViewController() self.paytmTransactionController?.title = "Paytm Payments" if(serverType != .eServerTypeNone) { self.paytmTransactionController?.serverType = serverType; } else { return } self.paytmTransactionController?.setLoggingEnabled(serverType == .eServerTypeStaging) self.paytmTransactionController?.merchant = PGMerchantConfiguration.defaultConfiguration() self.paytmTransactionController?.delegate = self UIApplication.shared.delegate?.window??.rootViewController?.present(paytmTransactionController, animated: true, completion: nil) } } private func checkAndSetPendingOperation(method: String, result: @escaping FlutterResult) { if (pendingOperation != nil) { return; // throw IllegalStateException("Concurrent operations detected: " + pendingOperation!!.method + ", " + method) } pendingOperation = PendingOperation(method: method, result: result) } private func finishWithSuccess(data: Dictionary<String, String>?) { pendingOperation!.result(data) pendingOperation = nil paytmTransactionController = nil } private func finishWithError(errorCode: String, errorMessage: String) { pendingOperation!.result(FlutterError(code: errorCode, message: errorMessage, details: nil)) pendingOperation = nil } /* PayTM Transaction Delegates */ func didFinishedResponse(_ controller: PGTransactionViewController, response responseString: String) { var paytmSuccessResponse = Dictionary<String, String>() if let data = responseString.data(using: String.Encoding.utf8) { do { if let jsonresponse = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:String] , jsonresponse.count > 0{ paytmSuccessResponse[paytmStatus] = jsonresponse[paytmStatus] ?? "" paytmSuccessResponse[paytmChecksumHash] = jsonresponse[paytmChecksumHash] ?? "" paytmSuccessResponse[paytmBankName] = jsonresponse[paytmBankName] ?? "" paytmSuccessResponse[paytmOrderId] = jsonresponse[paytmOrderId] ?? "" paytmSuccessResponse[paytmTransactionAmount] = jsonresponse[paytmTransactionAmount] ?? "" paytmSuccessResponse[paytmTransactionDate] = jsonresponse[paytmTransactionDate] ?? "" paytmSuccessResponse[paytmTransactionId] = jsonresponse[paytmTransactionId] ?? "" paytmSuccessResponse[paytmMerchantId] = jsonresponse[paytmMerchantId] ?? "" paytmSuccessResponse[paytmResponseCode] = jsonresponse[paytmResponseCode] ?? "" paytmSuccessResponse[paytmPaymentMode] = jsonresponse[paytmPaymentMode] ?? "" paytmSuccessResponse[paytmBankTransactionId] = jsonresponse[paytmBankTransactionId] ?? "" paytmSuccessResponse[paytmCurrency] = jsonresponse[paytmCurrency] ?? "" paytmSuccessResponse[paytmGatewayName] = jsonresponse[paytmGatewayName] ?? "" paytmSuccessResponse[paytmResponseMessage] = jsonresponse[paytmResponseMessage] ?? "" finishWithSuccess(data: paytmSuccessResponse) } } catch { finishWithError(errorCode: errorReasonPaytmTransactionResponseNull, errorMessage: "Paytm transaction response in null") } } } func didCancelTrasaction(_ controller: PGTransactionViewController) { finishWithError(errorCode: errorReasonPaytmTransactionCancelled, errorMessage: "Transaction cancelled.") } func errorMisssingParameter(_ controller: PGTransactionViewController, error: NSError?) { finishWithError(errorCode: errorReasonPaytmMissingParameters, errorMessage: "There are some missing parameters.") } private class PendingOperation { let method: String let result: FlutterResult init(method: String, result: @escaping FlutterResult) { self.method = method self.result = result } } } public class SwiftFlutterPaytmPlugin: NSObject, FlutterPlugin { //Channel Name Constant static let channelName = "flutterpaytmplugin.flutter.com/flutter_paytm_plugin" //Argument Constants let buildVariant = "build_variant" let checksumRequestObject = "checksum_request_object" //Method Constants let methodInitPaytmService = "initialize_paytm_service" let methodStartPaymentTransaction = "start_payment_transaction" var delegate : IDelegate init(pluginRegistrar: FlutterPluginRegistrar, uiViewController: UIViewController) { delegate = FlutterPaytmPluginDelegate(registrar: pluginRegistrar, viewController: uiViewController) } public static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel(name: channelName, binaryMessenger: registrar.messenger()) let viewController: UIViewController = (UIApplication.shared.delegate?.window??.rootViewController)!; let instance = SwiftFlutterPaytmPlugin(pluginRegistrar: registrar, uiViewController: viewController) registrar.addMethodCallDelegate(instance, channel: channel) } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { let arguments = call.arguments as? Dictionary<String, Any> switch call.method { case methodInitPaytmService: delegate.initializePaytmService(result: result, buildVariant: (arguments?[buildVariant] as? String)) case methodStartPaymentTransaction: delegate.startPaymentTransaction(result: result, checkSumRequestObject: (arguments?[checksumRequestObject] as? Dictionary<String, String>)) default: result(FlutterMethodNotImplemented) } } }
I am following some of the suggestions from this closed issue https://github.com/flutter/flutter/issues/9961.
But couldn't find success.
This is the logtrace which I am getting:
2018-12-07 17:27:39.510397+0530 Runner[56634:1432738] You've implemented -[<UIApplicationDelegate> application:performFetchWithCompletionHandler:], but you still need to add "fetch" to the list of your supported UIBackgroundModes in your Info.plist. 2018-12-07 17:27:39.510615+0530 Runner[56634:1432738] You've implemented -[<UIApplicationDelegate> application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need to add "remote-notification" to the list of your supported UIBackgroundModes in your Info.plist. 2018-12-07 17:27:39.610121+0530 Runner[56634:1432850] flutter: Observatory listening on http://127.0.0.1:56923/ PGTransactionViewController:loadView PGTransactionViewController::viewDidLoad PGTransactionViewController::viewWillAppear (lldb)
with an exception: Exception showcased in the image
Please help me out.