I'm currently developing a game using Swift 3, SpriteKit, and Xcode 8 beta. I'm trying to implement static 3D Touch Quick Actions from the home screen through the info.plist. Currently, the actions appear fine from the home screen, but don't go to the right SKScene - goes to the initial scene or last opened scene (if app is still open) which means that the scene is not being changed. I've tried various ways of setting the scene inside the switch statement, but none seem to work properly for presenting an SKScene as the line window!.rootViewController?.present(gameViewController, animated: true, completion: nil)
only works on UIViewController.
Various parts of this code are from various tutorials, but I'm fairly sure through my investigation that the broken part is the scene being presented (unless I'm wrong), because it shouldn't even load any scene if a part is broken.
Are there any ways I can present an SKScene from the AppDelegate or set the opening scene based of the switch statement?
AppDelegate
import UIKit
import SpriteKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
guard !handledShortcutItemPress(forLaunchOptions: launchOptions) else { return false } // ADD THIS LINE
return true
}
}
extension AppDelegate: ShortcutItem {
/// Perform action for shortcut item. This gets called when app is active
func application(_ application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) {
completionHandler(handledShortcutItemPress(forItem: shortcutItem))
}
}
extension AppDelegate: ShortcutItemDelegate {
func shortcutItem1Pressed() {
Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(loadShopScene), userInfo: nil, repeats: false)
}
@objc private func loadShopScene() {
let scene = ShopScene(size: CGSize(width: 768, height: 1024))
loadScene(scene: scene, view: window?.rootViewController?.view)
}
func shortcutItem2Pressed() {
Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(loadGameScene), userInfo: nil, repeats: false)
}
@objc private func loadGameScene() {
let scene = GameScene(size: CGSize(width: 768, height: 1024))
loadScene(scene: scene, view: window?.rootViewController?.view)
}
func shortcutItem3Pressed() {
// do something else
}
func shortcutItem4Pressed() {
// do something else
}
func loadScene(scene: SKScene?, view: UIView?, scaleMode: SKSceneScaleMode = .aspectFill) {
guard let scene = scene else { return }
guard let skView = view as? SKView else { return }
skView.ignoresSiblingOrder = true
#if os(iOS)
skView.isMultipleTouchEnabled = true
#endif
scene.scaleMode = scaleMode
skView.presentScene(scene)
}
}
3DTouchQuickActions.swift
import Foundation
import UIKit
/// Shortcut item delegate
protocol ShortcutItemDelegate: class {
func shortcutItem1Pressed()
func shortcutItem2Pressed()
func shortcutItem3Pressed()
func shortcutItem4Pressed()
}
/// Shortcut item identifier
enum ShortcutItemIdentifier: String {
case first // I use swift 3 small letters so you have to change your spelling in the info.plist
case second
case third
case fourth
init?(fullType: String) {
guard let last = fullType.components(separatedBy: ".").last else { return nil }
self.init(rawValue: last)
}
public var type: String {
return Bundle.main.bundleIdentifier! + ".\(self.rawValue)"
}
}
/// Shortcut item protocol
protocol ShortcutItem { }
extension ShortcutItem {
// MARK: - Properties
/// Delegate
private weak var delegate: ShortcutItemDelegate? {
return self as? ShortcutItemDelegate
}
// MARK: - Methods
/// Handled shortcut item press first app launch (needed to avoid double presses on first launch)
/// Call this in app Delegate did launch with options and exit early (return false) in app delegate if this method returns true
///
/// - parameter forLaunchOptions: The [NSObject: AnyObject]? launch options to pass in
/// - returns: Bool
func handledShortcutItemPress(forLaunchOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
guard let launchOptions = launchOptions, let shortcutItem = launchOptions[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem else { return false }
handledShortcutItemPress(forItem: shortcutItem)
return true
}
/// Handle shortcut item press
/// Call this in the completion handler in AppDelegate perform action for shortcut item method
///
/// - parameter forItem: The UIApplicationShortcutItem the press was handled for.
/// - returns: Bool
func handledShortcutItemPress(forItem shortcutItem: UIApplicationShortcutItem) -> Bool {
guard let _ = ShortcutItemIdentifier(fullType: shortcutItem.type) else { return false }
guard let shortcutType = shortcutItem.type as String? else { return false }
switch shortcutType {
case ShortcutItemIdentifier.first.type:
delegate?.shortcutItem1Pressed()
case ShortcutItemIdentifier.second.type:
delegate?.shortcutItem2Pressed()
case ShortcutItemIdentifier.third.type:
delegate?.shortcutItem3Pressed()
case ShortcutItemIdentifier.fourth.type:
delegate?.shortcutItem4Pressed()
default:
return false
}
return true
}
}