flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
165.07k stars 27.21k forks source link

How do I trigger a ViewController from Flutter plugin Swift class? #25078

Closed rohitgupta1694 closed 5 years ago

rohitgupta1694 commented 5 years ago

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 requires 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": "username@emailprovider.com",
    "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) 

And an exception comes:

screenshot 2018-12-07 at 5 29 49 pm

Please help me out.

neiljaywarner commented 5 years ago

Can you give a mvce? I'm concerned that's a bit too much code to get help with.. https://stackoverflow.com/help/mcve

rohitgupta1694 commented 5 years ago

@neiljaywarner Sure.

I am only adding some part of the code only which is required.

The main Swift Plugin class, which is adding the Method Call delegate to the FlutterPluginRegistrar and before adding method call delegate, I am passing the registrar instance and a rootViewController to my custom made delegate named IDelegate:

public class SwiftFlutterPaytmPlugin: NSObject, FlutterPlugin {
    var delegate : IDelegate

    // Constructor to Initialize FlutterPaytmPluginDelegate which accepts registrar and a viewController reference.
    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 {
          //Calling specific delegates for specific method calls.
        }
    }
}
/*
 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?

    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)
        }
    }

// Delegate method to make Paytm Transactions
    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
            //This is the line in which I am having issue.            
            viewController?.present(paytmTransactionController, animated: true, completion: nil)

        }
    }

}

I hope now you can understand the code.

rohitgupta1694 commented 5 years ago

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.

Since this query is resolved now, I am closing this issue.

kishan2612 commented 4 years ago

This will work ! Got it from Square one SDK for flutter

` let rootViewController:UIViewController! = UIApplication.shared.keyWindow?.rootViewController

if (rootViewController is UINavigationController) {
                  (rootViewController as! UINavigationController).pushViewController(helpCenter,animated:true)
              } else {
                  let navigationController:UINavigationController! = UINavigationController(rootViewController:helpCenter)
                rootViewController.present(navigationController, animated:true, completion:nil)
              }

`

vcsDev commented 4 years ago

UIApplication.shared.delegate?.window??.rootViewController not working anymore

flutter doctor -v logs

[✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.1 19B88, locale en-IN) • Flutter version 1.12.13+hotfix.5 at /Users/VCS/flutter_install/flutter • Framework revision 27321ebbad (8 days ago), 2019-12-10 18:15:01 -0800 • Engine revision 2994f7e1e6 • Dart version 2.7.0

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2) • Android SDK at /Users/VCS/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 29.0.2 • Java binary at: /Applications/Android Studio 3.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405) • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.2.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 11.2.1, Build version 11B500 • CocoaPods version 1.8.4

[✓] Android Studio (version 3.5) • Android Studio at /Applications/Android Studio 3.app/Contents • Flutter plugin version 42.1.1 • Dart plugin version 191.8593 • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)

[✓] Connected device (1 available)

how to get rootViewController?? now?

iosparesh commented 4 years ago

Any update?

j796160836 commented 4 years ago

UIApplication.shared.delegate?.window??.rootViewController not working anymore

Maybe is new SceneDelegate take the wheel. You might use this in multi-scene.

let rootViewController = UIApplication.shared.windows.filter({ (w) -> Bool in
            return w.isHidden == false
 }).first?.rootViewController

Note that this is temporary solution. I'm also finding the right solutions.

braysonjohn148 commented 4 years ago

Am also facing the same problem. I had my running well on Android but trying to run for IOS am getting an error saying: Screenshot 2020-03-11 at 15 05 30

2020-03-11 15:02:56.263815+0300 Runner[86714:475546] Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Could not find a storyboard named 'Main' in bundle NSBundle </Users/mac/Library/Developer/CoreSimulator/Devices/67416226-A0FC-4381-8A0A-0380555122B8/data/Containers/Bundle/Application/167E6C1B-B602-4522-80C2-8A123D2F36BA/Runner.app> (loaded)' First throw call stack: ( 0 CoreFoundation 0x000000010814727e exceptionPreprocess + 350 1 libobjc.A.dylib 0x0000000107786b20 objc_exception_throw + 48 2 UIKitCore 0x000000011237a633 +[UIStoryboard storyboardWithName:bundle:] + 672 3 UIKitCore 0x0000000112213e64 -[UIApplication _loadMainStoryboardFileNamed:bundle:] + 76 4 UIKitCore 0x0000000112214473 -[UIApplication _loadMainInterfaceFile] + 274 5 UIKitCore 0x0000000112212dff -[UIApplication _runWithMainScene:transitionContext:completion:] + 964 6 UIKitCore 0x000000011194776d -[_UISceneLifecycleMultiplexer completeApplicationLaunchWithFBSScene:transitionContext:] + 122 7 UIKitCore 0x0000000111e364c1 _UIScenePerformActionsWithLifecycleActionMask + 83 8 UIKitCore 0x000000011194827f __101-[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]_block_invoke + 198 9 UIKitCore 0x0000000111947c8e -[_UISceneLifecycleMultiplexer _performBlock:withApplicationOfDeactivationReasons:fromReasons:] + 296 10 UIKitCore 0x00000001119480ac -[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:] + 818 11 UIKitCore 0x0000000111947941 -[_UISceneLifecycleMultiplexer uiScene:transitionedFromState:withTransitionContext:] + 345 12 UIKitCore 0x000000011194bf3f 186-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]_block_invoke_2 + 178 13 UIKitCore 0x0000000111d5ac83 +[BSAnimationSettings(UIKit) tryAnimatingWithSettings:actions:completion:] + 865 14 UIKitCore 0x0000000111e54dff _UISceneSettingsDiffActionPerformChangesWithTransitionContext + 240 15 UIKitCore 0x000000011194bc5a 186-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]_block_invoke + 153 16 UIKitCore 0x0000000111e54d02 _UISceneSettingsDiffActionPerformActionsWithDelayForTransitionContext + 84 17 UIKitCore 0x000000011194bac8 -[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:] + 381 18 UIKitCore 0x00000001117a26e7 64-[UIScene scene:didUpdateWithDiff:transitionContext:completion:]_block_invoke + 657 19 UIKitCore 0x00000001117a126c -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:] + 248 20 UIKitCore 0x00000001117a2411 -[UIScene scene:didUpdateWithDiff:transitionContext:completion:] + 210 21 UIKitCore 0x0000000112211599 -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 535 22 UIKitCore 0x0000000111d7c7f5 -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 361 23 FrontBoardServices 0x000000010f983165 -[FBSSceneImpl _callOutQueue_agent_didCreateWithTransitionContext:completion:] + 442 24 FrontBoardServices 0x000000010f9a94d8 86-[FBSWorkspaceScenesClient sceneID:createWithParameters:transitionContext:completion:]_block_invoke.154 + 102 25 FrontBoardServices 0x000000010f98dc45 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 220 26 FrontBoardServices 0x000000010f9a9169 __86-[FBSWorkspaceScenesClient sceneID:createWithParameters:transitionContext:completion:]_block_invoke + 355 27 libdispatch.dylib 0x000000010b70ed48 _dispatch_client_callout + 8 28 libdispatch.dylib 0x000000010b711cb9 _dispatch_block_invoke_direct + 300 29 FrontBoardServices 0x000000010f9cf37e FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 30 30 FrontBoardServices 0x000000010f9cf06c -[FBSSerialQueue _queue_performNextIfPossible] + 441 31 FrontBoardServices 0x000000010f9cf57b -[FBSSerialQueue _performNextFromRunLoopSource] + 22 32 CoreFoundation 0x00000001080aa471 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17 33 CoreFoundation 0x00000001080aa39c CFRunLoopDoSource0 + 76 34 CoreFoundation 0x00000001080a9b74 CFRunLoopDoSources0 + 180 35 CoreFoundation 0x00000001080a487f __CFRunLoopRun + 1263 36 CoreFoundation 0x00000001080a4066 CFRunLoopRunSpecific + 438 37 GraphicsServices 0x000000010ee14bb0 GSEventRunModal + 65 38 UIKitCore 0x0000000112214d4d UIApplicationMain + 1621 39 Runner 0x0000000100a3b2d0 main + 112 40 libdyld.dylib 0x000000010b796c25 start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)

lock[bot] commented 4 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.