Flutter cannot call result in native ios code - ios

Good day, maybe someone can help me here. I have a SDK built into Flutter that I call via the ChannelMethod. There I enter a callback whose result I want to give back to flutter. The callback works but for some unknown reason the result function is not triggered.
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let testChannel = FlutterMethodChannel(name: "test",
binaryMessenger: controller.binaryMessenger)
testChannel.setMethodCallHandler({
[weak self] (call: FlutterMethodCall, result: #escaping FlutterResult) -> Void in
// This method is invoked on the UI thread.
guard call.method == "startProcess" else {
result(FlutterMethodNotImplemented)
return
}
let args = call.arguments as! Dictionary<String, Any>
let mainVC = ViewController()
mainVC.callBack = { (resultValue: String) in
print("Callback called:")
print(resultValue)
// <-------- this does not work -------->
result(resultValue)
result("test")
};
mainVC.caseId = args["caseId"] as! String
let navigationController = UINavigationController(rootViewController: mainVC)
self?.window.rootViewController = navigationController
self?.window.makeKeyAndVisible()
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

Related

Flutter iOS native navigation

I currently have the problem that I don't know how to give native a screen in iOS a callback function and a string.
It is currently implemented as follows:
import UIKit
import Flutter
import PostidentSDK
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let kycChannel = FlutterMethodChannel(name: "kyc",
binaryMessenger: controller.binaryMessenger)
kycChannel.setMethodCallHandler({
[weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
// This method is invoked on the UI thread.
guard call.method == "startProcess" else {
result(FlutterMethodNotImplemented)
return
}
let mainVC = ViewController() // Your viewController
let navigationController = UINavigationController(rootViewController: mainVC)
self?.window.rootViewController = navigationController
self?.window.makeKeyAndVisible()
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
someFunction()
}
}
The Screen ViewController is then called and on this I want to have the string caseId & then execute the Flutter result there and close the screen.

how to implement protocol delegate pattern in App Delegate when using Platform Specific code in Flutter?

I want to implement platform specific code for my Flutter app on iOS. I want to implement EventKit from native iOS. but now I am confused how to implement protocol delegate pattern in the app delegate when using Platform Channel in Flutter.
in native iOS, my code will be like this
import EventKitUI
class MyViewController : UIViewController, EKEventEditViewDelegate, UINavigationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func buttonPressed(_ sender: Any) {
// after pressing a button then show a VC
showEventKitViewController()
}
func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
// this is the method to conform the protocol
dismiss(animated: true, completion: nil)
}
func showEventKitViewController() {
let eventVC = EKEventEditViewController()
eventVC.editViewDelegate = self // I am confused in this line
eventVC.eventStore = EKEventStore()
let event = EKEvent(eventStore: eventVC.eventStore)
eventVC.event = event
present(eventVC, animated: true)
}
}
as you can see, I assign self ( MyViewController class as the delegate ) for editViewDelegate
now I am confused how to implement showEventKitViewController method above in Flutter app delegate below
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let channel = FlutterMethodChannel(name: "useOtherApp", binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({ (call: FlutterMethodCall, result: FlutterResult) -> Void in
if (call.method == "saveToEventKit") {
// what should I do in here to get the same result like my code above in native?
}
})
}
especially when I need to assign a class as the delegate for editViewDelegate like this
I can solve it by using the code like this by using extension. please scroll to the very bottom to see FlutterViewController extension
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
setUpMethodChannels(controller: controller) // set the method channel
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func setUpMethodChannels(controller: FlutterViewController) {
let channel = FlutterMethodChannel(name: "useOtherApp", binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({ (call: FlutterMethodCall, result: FlutterResult) -> Void in
guard let args = call.arguments as? [String : Any] else {return}
if (call.method == "saveToCalendar") {
let eventVC = EKEventEditViewController()
eventVC.editViewDelegate = controller // set FlutterViewController as the delegate
eventVC.eventStore = EKEventStore()
let event = EKEvent(eventStore: eventVC.eventStore)
eventVC.event = event
eventVC.title = "hallooooo"
controller.present(eventVC, animated: true)
} else {
result(FlutterMethodNotImplemented)
}
})
}
}
// set the extension like below OUTSIDE the AppDelegate class
extension FlutterViewController : EKEventEditViewDelegate, UINavigationControllerDelegate {
// conform to the EKEventEditViewDelegate protocol
public func eventEditViewController(_ controller: EKEventEditViewController, didCompleteWith action: EKEventEditViewAction) {
dismiss(animated: true, completion: nil)
}
}

Flutter - How to invoke channel in native Swift code?

I have written native Swift code in my AppDelegate, I am trying to invoke a third party sdk callback in my dart side of code, however the declaration of my method channel can only be done in application function. How do I invoke a channel in my delegate methods to make a dart callback?
import UIKit
import Flutter
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate, TJPlacementDelegate {
public func requestDidSucceed(_ placement: TJPlacement!) {
//Need to invoke methodChannel here
}
public func requestDidFail(_ placement: TJPlacement!, error: Error!) {
//Need to invoke methodChannel here
}
public func contentIsReady(_ placement: TJPlacement!) {
//Need to invoke methodChannel here
}
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let channelName = "ios_native"
let rootViewController : FlutterViewController = window?.rootViewController as! FlutterViewController
let methodChannel = FlutterMethodChannel(name: channelName, binaryMessenger: rootViewController as! FlutterBinaryMessenger)
methodChannel.setMethodCallHandler {(call: FlutterMethodCall, result: FlutterResult) -> Void in
switch(call.method) {
case "setDebugEnabled":
let isDebug = call.arguments as! Bool
Tapjoy.setDebugEnabled(isDebug)
break;
default: result(FlutterMethodNotImplemented)
}
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
I can't declare my methodChannel outside my application as the window doesn't get recognised.
Define the method channel in the AppDelegate:
var methodChannel: FlutterMethodChannel!
Initialize it:
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
...
methodChannel = FlutterMethodChannel(name: channelName, binaryMessenger: rootViewController as! FlutterBinaryMessenger)
}
Now you can call invokeMethod:
public func requestDidSucceed(_ placement: TJPlacement!) {
methodChannel.invokeMethod()
}

How to call a view controller via Quick Actions (3D touch) Swift

I'm trying to implement a 3D touch command where if the user presses "New scan", then the view controller ProcessedImageViewController is called. I have already set up the Info.plist to create the quick option, but I am having trouble actually calling the ProcessedImageViewController when "New scan" is pressed.
Here is my code from the AppDelegate.swift:
var launchedShortcutItem: UIApplicationShortcutItem?
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
if let shortcutItem = launchOptions?[UIApplication.LaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem{
launchedShortcutItem = shortcutItem
}
return true
}
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: #escaping (Bool) -> Void) {
completionHandler(handleShortcutItem(item: shortcutItem))
}
func applicationDidBecomeActive(_ application: UIApplication) {
guard let shortcutItem = launchedShortcutItem else { return }
//If there is any shortcutItem,that will be handled upon the app becomes active
_ = handleShortcutItem(item: shortcutItem)
//We make it nil after perfom/handle method call for that shortcutItem action
launchedShortcutItem = nil
}
func handleShortcutItem(item: UIApplicationShortcutItem) -> Bool {
var handled = false
// Verify that the provided shortcutItem's type is one handled by the application.
let mainStoryboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
var reqVC: UIViewController!
reqVC = mainStoryboard.instantiateViewController(withIdentifier: "ProcessedImageViewController") as! ProcessedImageViewController
handled = true
if let homeVC = self.window?.rootViewController as? UINavigationController {
homeVC.pushViewController(reqVC, animated: true)
} else {
return false
}
return handled
}
When I try to click on "New scan" in the Quick Actions menu, I only get taken to the Root View controller (not ProcessedImageViewController).

How to get Notificationcenter data from didFinishLaunchingWithOptions on swift 4

I'm working on an app that receives data from a remote notification, I'm trying to pass that data from didFinishLaunchingWithOptions to my ViewController using Notificationcenter when opening the app through tapping on the notification using launchOptions. The problem is that the observer on my viewDidAppear is not getting any data.
This is my code on the didFinishLaunchingWithOptions method:
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if let remoteNotification = launchOptions?[.remoteNotification] as? [AnyHashable : Any] {
let nameSchool = remoteNotification["name_school" as! String]
NotificationCenter.default.post(name: Notification.Name.nameSchool, object: nameSchool)
}
}
And the observer in the viewDidAppear method:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
NotificationCenter.default.addObserver(forName: Notification.Name.nameSchool, object: nil, queue: OperationQueue.main) { (nameSchool) in
let schoolName = nameSchool.object as! String
self.messagePopup(message: "Data received")
}
}
Since your application(,didFinishLaunchingWithOptions:) will be called before the viewDidAppear (as per your comment), then you will have to temporarily store the result you get from the function until your code can retrieve it later.
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var remoteNotificationAtLaunch: [AnyHashable: Any]?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.remoteNotificationAtLaunch = launchOptions?[.remoteNotification] as? [AnyHashable : Any]
}
...
}
Obviously keep the part you already have in your AppDelegate that generates the post to NotificationCenter when a remote notification is received. Then in your view controller, update your viewDidAppear...
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
observeNotifications()
checkForNotificationAtLaunch()
}
private func observeNotifications() {
NotificationCenter.default.addObserver(forName: Notification.Name.nameSchool, object: nil, queue: OperationQueue.main) { (nameSchool) in
let schoolName = nameSchool.object as! String
self.processNotification(schoolName: schoolName)
}
}
private func checkForNotificationAtLaunch() {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
if let notificationAtLaunch = appDelegate.remoteNotificationAtLaunch,
let schoolName = notificationAtLaunch["name_school"] as? String {
processNotification(schoolName: schoolName)
}
}
}
private func processNotification(schoolName: String) {
self.messagePopup(message: "data received")
// do something with schoolName....
}

Resources