Can method_exchangeImplementations work between objective-c and swift? - swift

I'm trying to get a Cordova plugin to work with a Capacitor project.
Capacitor is in Swift and the plugin is in Obj-c.
The plugin runs this bit of code to swizzle itself in the app start flow.
+ (void)load {
Method original = class_getInstanceMethod(self, #selector(application:didFinishLaunchingWithOptions:));
Method swizzled = class_getInstanceMethod(self, #selector(application:swizzledDidFinishLaunchingWithOptions:));
method_exchangeImplementations(original, swizzled);
}
original (application:didFinishLaunchingWithOptions) is in the Swift AppDelegate and swizzled (application:swizzledDidFinishLaunchingWithOptions) is in the plugin's obj-c code.
This doesn't work.
When the app starts, this bit of code runs, but the result of class_getInstanceMethod for original is always nil.
The swift delegate has
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
And the obj-c plugin has
- (BOOL)application:(UIApplication *)application swizzledDidFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// ...
}
I've tried adding #objc and dynamic to the swift func but that didn't help.
Is there a way to make this work?

Related

How to use react-native-config with a react native app build with Swift

I am trying to use the react-native-config with react-native configured with Swift.
Following the usage guide, it tells me to import #import "ReactNativeConfig.h".
I imported this inside of the bridging header, but it can't find it.
Does anyone know how to use this library with a react native app build with Swift?
you just need to add #import "ReactNativeConfig.h" in bridging header. If you did that you can use it in your swift code without any additional import.
Here is some article I found helpful.
https://medium.com/#subhangdxt/bridging-objective-c-and-swift-classes-5cb4139d9c80
And here is my code:
My app-Bridging-Header.h:
...
#import "ReactNativeConfig.h"
...
My AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
if let gmsApiKey = ReactNativeConfig.env(for: "GOOGLE_MAPS_API_KEY") {
GMSServices.provideAPIKey(gmsApiKey)
} else {
print("ERROR: No goole maps api key provided!")
}
bridge = RCTBridge(delegate: self, launchOptions: launchOptions)
...
return true
}

BackgroundTask iOS 13 Swift with Scenes

I am trying to implement the new iOS 13 background tasks functionality with a new app that is utilizing Scenes (also new). There are not a lot of examples, but the ones I have found were not using SceneDelegates, instead all the logic was contained in the AppDelegate. This causes issues since the event for the app going into the background is now raised in the SceneDelegate, not the AppDelegate.
This method does not fire in AppDelegate when using scenes
func applicationDidEnterBackground(_ application: UIApplication) {
}
This method does fire in SceneDelegate
func sceneDidEnterBackground(_ scene: UIScene) {
}
I am not able to find a corresponding SceneDelegate method for the following method in AppDelegate where all the examples show BGTaskScheduler registering tasks
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
BGTaskScheduler.shared.register(forTaskWithIdentifier: "UNIQUE_ID", using: DispatchQueue.global()) { task in
refreshMethod(task: task as! BGAppRefreshTask)
}
}
My question is whether there is some event in the SceneDelegate where I can register the task and if not what is the recommended pattern to follow for scene based apps.
AppDelegate.didFinishLaunchingWithOptions is still called at app launch, even when you have a SceneDelegate. So you should continue to register your background tasks in that method.

Multiple inheritance from classes 'UIApplication' and 'FBSDKApplicationDelegate'

I'm using iOS SDK from facebook website https://developers.facebook.com/docs/ios , but when I add FBSDKApplicationDelegate into App delegate I receive an error
Multiple inheritance from classes 'UIApplication' and 'FBSDKApplicationDelegate'.
I can't use Swift SDK, because my project is on XCode 8.2.1, Swift SDK for Facebook requires 8.3
Seem like you are using FBSDKApplicationDelegate by this way or something like this
class AppDelegate: UIResponder, UIApplicationDelegate, FBSDKApplicationDelegate
Please take a look at FBSDKApplicationDelegate carefully.
Discussion:
The methods in this class are designed to mirror those in UIApplicationDelegate, and you should call them in the respective methods in your AppDelegate implementation.
It isn't used that way. Don't make AppDelegate inheritance from FBSDKApplicationDelegate. Let use FBSDKApplicationDelegate's methods inside AppDelegate's methods
You can learn how to use FBSDKApplicationDelegate by following answer in this question Integration new facebook SDK by swift
func applicationDidBecomeActive(application: UIApplication!) {
FBSDKAppEvents.activateApp()
}
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
}
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String, annotation: AnyObject?) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}
For more detail and easy understanding, i create a demo project with Facebook iOS SDK IntegrateFBSDK. You can try it.

swift 3 error xcode 8.1 while assigning rootviewcontroller says it is a get-only property

I was migrating my project from swift 2.2 to 3.0, when I reached a point where I get this strange error, which does not allow me to set rootviewcontroller in the app delegate didfinishlaunching.
self.window?.rootViewController = self.container.resolve(DPSlideMenuController.self)!
I guess you're using this library SlideMenuControllerSwift . It would be great if you show the whole code inside the DidFinishLaunching function.
Anyway, try to do the following :
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// create viewController code...
let slideMenuController = SlideMenuController(mainViewController: mainViewController, leftMenuViewController: leftViewController, rightMenuViewController: rightViewController)
self.window?.rootViewController = slideMenuController
self.window?.makeKeyAndVisible()
return true
}
Finally fixed it. The issue was there was a var named rootViewController in one of the protocol extension.
var rootViewController: UIViewController {
return (UIApplication.shared.keyWindow?.rootViewController)!
}
Was working fine with Swift 2.2, but on swift 3 was confusing the compiler. Changed the name and the code got compiled.

UrbanAirship Swift

I am trying to integrate UrbanAirship into my project but I am getting the following error:
2016-08-25 16:26:23.898 Fibre[7758:368753] [E] __52+[UAirship handleAppDidFinishLaunchingNotification:]_block_invoke [Line 320] Please ensure that [UAirship takeOff] is called synchronously before application:didFinishLaunchingWithOptions: returns
Any help resolving this would be much appreciated!
My application delegate is as as below:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
let configuration = ParseClientConfiguration { (configuration) -> Void in
configuration.applicationId = "******"
configuration.clientKey = "*****"
configuration.server = "https://*****.herokuapp.com/parse"
}
Parse.initializeWithConfiguration(configuration)
let config: UAConfig = UAConfig.defaultConfig()
UAirship.takeOff(config)
return true
}
I haven't used the Urban Airship SDK before myself but going off of the error message that you posted the key bit seems to be "is called Synchronously before application:didFinishLaunchingWithOptions: returns".
What I would guess is happening is that you're calling the takeOff method on UAirship but didFinishLaunchingMethod is returning before that method completes; More than likely because it's being handled in another thread).
Try forcing the takeOff method to be run on the main thread with "dispatch_async" and then passing in the main queue such as:
dispatch_async(dispatch_get_main_queue(), {
UAirship.takeOff(config)
})
Try that out, hopefully that will fix the issue.