XCode11 error open(_:options:completionHandler:) is unavailable in application extensions
As documented in the (sole) issue on that sample, this was an intentional change in iOS 13 as confirmed by DTS. My belief is this was part of a crackdown on abusive behaviour in keyboard extensions, which picked up iMessage extensions as a side-effect.
I'd already come up with a workaround, which is the same as they recommend.
- Forward the URL to your parent app using
self.extensionContext?.open
- Have the parent app then launch the external app or URL on your
behalf.
Here's the complete working extension from Touchgram
// UIViewController+iMessageContext.swift
// applied to class MessagesViewController: MSMessagesAppViewController, UrlOpeningInIMessage
protocol UrlOpeningInIMessage {
func openFromiMessageContext(url:URL)
}
extension UrlOpeningInIMessage where Self:UIViewController {
func openFromiMessageContext(url:URL) {
let handler = { (success:Bool) -> () in
if success {
os_log("Finished opening URL", log:tgEnv.logImUI, type:.debug)
} else {
os_log("Failed to open URL", log:tgEnv.logImUI, type:.debug)
}
}
// logic same as onLaunchMainPressed, since XCode11 unable to compile extension using UIApplication.open
// so we pass the URL through to the parent app to launch on our behalf
let appName = Bundle.appName()
let encodedUrl = url.dataRepresentation.base64EncodedString()
guard let appUrl: URL = URL(string: "\(appName)://?url=\(encodedUrl)") else { return }
// can only open our app, not generalised URLs
self.extensionContext?.open(appUrl, completionHandler: handler)
}
}
iOS 13 Schedule iOS background tasks
The solution is to run on a device. I was running on a simulator. However, It was showing the Background App Refresh has been enabled in Settings while running on the simulator.
There may be some other reasons. Please visit
https://developer.apple.com/documentation/backgroundtasks/bgtaskschedulererrorcode/bgtaskschedulererrorcodeunavailable?language=objc
How to resolve: 'keyWindow' was deprecated in iOS 13.0
This is my solution:
let keyWindow = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.compactMap({$0 as? UIWindowScene})
.first?.windows
.filter({$0.isKeyWindow}).first
Usage e.g.:
keyWindow?.endEditing(true)
UIApplication.shared.delegate equivalent for SceneDelegate xcode11?
As of iOS 13, UIApplication
has the connectedScenes
property which is Set<UIScene>
. Each of those scenes has a delegate
which is a UISceneDelegate
. So you could access all of the delegates that way.
A scene can manage one or more windows (UIWindow
) and you can get a window's UIScene
from its windowScene
property.
If you want the scene delegate for a specific view controller then note the following. From a UIViewController
you can get its window from its view. From the window you can get its scene and of course from the scene you can get its delegate.
In short, from a view controller, you can do:
let mySceneDelegate = self.view.window.windowScene.delegate
However, there are plenty of times where a view controller has no window. This happens when a view controller presents another full screen view controller. This can happened when the view controller is in a navigation controller and the view controller is not the top, visible view controller.
This requires a different approach to finding the view controller's scene. Ultimately you need to use a combination of walking the responder chain and the view controller hierarchy until you find a path that leads to the scene.
The following extension will (may) get you a UIScene from a view or view controller. Once you have the scene, you can access its delegate.
Add UIResponder+Scene.swift:
import UIKit
@available(iOS 13.0, *)
extension UIResponder {
@objc var scene: UIScene? {
return nil
}
}
@available(iOS 13.0, *)
extension UIScene {
@objc override var scene: UIScene? {
return self
}
}
@available(iOS 13.0, *)
extension UIView {
@objc override var scene: UIScene? {
if let window = self.window {
return window.windowScene
} else {
return self.next?.scene
}
}
}
@available(iOS 13.0, *)
extension UIViewController {
@objc override var scene: UIScene? {
// Try walking the responder chain
var res = self.next?.scene
if (res == nil) {
// That didn't work. Try asking my parent view controller
res = self.parent?.scene
}
if (res == nil) {
// That didn't work. Try asking my presenting view controller
res = self.presentingViewController?.scene
}
return res
}
}
This can be called from any view or view controller to get its scene. But note that you can only get the scene from a view controller only after viewDidAppear
has been called at least once. If you try any sooner then the view controller may not yet be part of the view controller hierarchy.
This will work even if the window of the view of the view controller is nil as long as the view controller is part of a view controller hierarchy and somewhere up that hierarchy, it is attached to a window.
Here is an Objective-C implementation of the UIResponder extension:
UIResponder+Scene.h:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIResponder (Scene)
@property (nonatomic, readonly, nullable) UIScene *scene API_AVAILABLE(ios(13.0));
@end
NS_ASSUME_NONNULL_END
UIResponder+Scene.m:
#import "ViewController+Scene.h"
@implementation UIResponder (Scene)
- (UIScene *)scene {
return nil;
}
@end
@implementation UIScene (Scene)
- (UIScene *)scene {
return self;
}
@end
@implementation UIView (Scene)
- (UIScene *)scene {
if (self.window) {
return self.window.windowScene;
} else {
return self.nextResponder.scene;
}
}
@end
@implementation UIViewController (Scene)
- (UIScene *)scene {
UIScene *res = self.nextResponder.scene;
if (!res) {
res = self.parentViewController.scene;
}
if (!res) {
res = self.presentingViewController.scene;
}
return res;
}
@end
Related Topics
Avaudiosinknode with Non-Default, But Still Device-Native Sample Rates
How to Create Apple Watchos5 Complication
Swiftui: How to Find the Height of an Image and Use It to Set the Size of a Frame
Swiftui Editbutton Action on Done
Using Nil-Coalescing Operator with Try? for Function That Throws and Returns Optional
Swiftui - Unwrap Optional Image Data to Create Image Based on Uiimage(Data)
Swiftui Sheet Gets Dismissed the First Time It Is Presented
Hex String to Text Conversion - Swift 3
Swift: Generics and Type Constraints, Strange Behavior
Dictionary of String:Any Does Not Conform to Protocol 'Decodable'
Realmswift Initialize List:Cannot Specialize a Non-Generic Definition
Xcode Generated Coredata Files Cannot Be Processed by Copy Bundle Resources Build Phase
How to Apply Animation for One Specific Modifier Change Only
How to Decode the Body of an Error in Alamofire 5
How to Correctly Do Up an Adjustable Split View in Swiftui
How to Use Multiple Mtlrenderpipelinestates in One Mtlrendercommandencoder