When it comes to iPhone devices, and using the map iPhone four can not handle
manager.requestAlwaysAuthorization()
But anything post iPhone4 requires that. How can I make it so the software will run successfully on both device types?
This worked
func triggerLocationServices() {
if CLLocationManager.locationServicesEnabled() {
if self.manager.respondsToSelector("requestWhenInUseAuthorization") {
manager.requestWhenInUseAuthorization()
} else {
startUpdatingLocation()
}
}
}
func startUpdatingLocation() {
manager.startUpdatingLocation()
}
// MARK: - CLLocationManagerDelegate
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .AuthorizedWhenInUse || status == .Authorized {
startUpdatingLocation()
}
}
Related
Where to call NotificationCenter.default.addObserver() ? in my Xcode Game Project
I successfully call the following from my func application (AppDelegate), but when I toggle the Gamepad on/off, my selectors are not being called.
class GameScene: SKScene {
func ObserveForGameControllers() {
// print("ObserveForGameControllers")
NotificationCenter.default.addObserver(
self,
selector: #selector(connectControllers),
name: NSNotification.Name.GCControllerDidConnect,
object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(disconnectControllers),
name: NSNotification.Name.GCControllerDidDisconnect,
object: nil)
} // ObserveForGameControllers
}
My selectors look like this:
#objc func connectControllers() {}
#objc func disconnectControllers() {}
One last thing:
Here are my Gamepad settings in my Project
It seems I really need some suggestions here.
Appreciate it.
EDIT
I have been in contact with a very talented jrturton on trying to discover why I am unable to detect the presence of my Gamepad as documented above.
He has asked for a more complete presentation of my Swift code. I initially thought of Dropbox, but he has asked for this EDIT .. so here goes:
I began with a iOS Game Project which presented me with AppDelegate, GameScene, GameViewController + Storyboard.
I’ve already covered AppDelegate above, which per jrturton’s recommendation is now reduced to the standard AppDelegate func’s which essentially are empty, such as:
func application(_ application: UIApplication,
didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// currently empty
}
Next, the GameScene ..
import SwiftUI
import WebKit
import SpriteKit
import GameplayKit
import GameController
class GameScene: SKScene {
override func sceneDidLoad() {
super.sceneDidLoad()
// print("sceneDidLoad")
ObserveForGameControllers()
} // sceneDidLoad
func ObserveForGameControllers() {
// print("ObserveForGameControllers")
NotificationCenter.default.addObserver(
self,
selector: #selector(connectControllers),
name: NSNotification.Name.GCControllerDidConnect,
object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(disconnectControllers),
name: NSNotification.Name.GCControllerDidDisconnect,
object: nil)
} // ObserveForGameControllers
#objc func connectControllers() {
// print("CONNECT")
self.isPaused = false
var indexNumber = 0
for controller in GCController.controllers() {
if controller.extendedGamepad != nil {
controller.playerIndex = GCControllerPlayerIndex.init(rawValue: indexNumber)!
indexNumber += 1
setupControllerControls(controller: controller)
}
}
} // connectControllers
#objc func disconnectControllers() {
// print("DIS-CONNECT")
self.isPaused = true
} // disconnectControllers
func setupControllerControls(controller: GCController) {
controller.extendedGamepad?.valueChangedHandler = {
(gamepad: GCExtendedGamepad, element: GCControllerElement) in
self.controllerInputDetected(gamepad: gamepad,
element: element,
index: controller.playerIndex.rawValue)
}
} // setupControllerControls
func controllerInputDetected(gamepad: GCExtendedGamepad,
element: GCControllerElement,
index: Int) {
// A-Button
if (gamepad.buttonA == element)
{
if (gamepad.buttonA.value != 0)
{
// These print(..) statements will be replaced later
// by code to access my Javascript methods.
print("movePaddleDown")
}
}
// B-Button
else if (gamepad.buttonB == element)
{
if (gamepad.buttonB.value != 0)
{
print("movePaddleRight")
}
}
// Y-Button
else if (gamepad.buttonY == element)
{
if (gamepad.buttonY.value != 0)
{
print("movePaddleUp")
}
}
// X-Button
else if (gamepad.buttonX == element)
{
if (gamepad.buttonX.value != 0)
{
print("movePaddleLeft")
}
}
// leftShoulder
else if (gamepad.leftShoulder == element)
{
if (gamepad.leftShoulder.value != 0)
{
print("cyclePages")
}
}
// rightShoulder
else if (gamepad.rightShoulder == element)
{
if (gamepad.rightShoulder.value != 0)
{
print("newGame")
}
}
// leftTrigger
else if (gamepad.leftTrigger == element)
{
if (gamepad.leftTrigger.value != 0)
{
print("pauseGame")
}
}
// rightTrigger
else if (gamepad.rightTrigger == element)
{
if (gamepad.rightTrigger.value != 0)
{
print("resumeGame")
}
}
// Left Thumbstick
else if (gamepad.leftThumbstick == element)
{
if (gamepad.leftThumbstick.xAxis.value > 0)
{
print("movePaddleRight")
}
else if (gamepad.leftThumbstick.xAxis.value < 0)
{
print("movePaddleLeft")
}
else if (gamepad.leftThumbstick.xAxis.value == 0)
{
print("decreaseSpeed")
}
else if (gamepad.leftThumbstick.yAxis.value > 0)
{
print("movePaddleDown")
}
else if (gamepad.leftThumbstick.yAxis.value < 0)
{
print("movePaddleUp")
}
else if (gamepad.leftThumbstick.yAxis.value == 0)
{
print("decreaseSpeed")
}
}
// Right Thumbstick
if (gamepad.rightThumbstick == element)
{
if (gamepad.rightThumbstick.xAxis.value > 0)
{
print("movePaddleRight")
}
else if (gamepad.rightThumbstick.xAxis.value < 0)
{
print("movePaddleLeft")
}
else if (gamepad.rightThumbstick.xAxis.value == 0)
{
print("decreaseSpeed")
}
else if (gamepad.rightThumbstick.yAxis.value > 0)
{
print("movePaddleDown")
}
else if (gamepad.rightThumbstick.yAxis.value < 0)
{
print("movePaddleUp")
}
else if (gamepad.rightThumbstick.yAxis.value == 0)
{
print("decreaseSpeed")
}
}
// D-Pad
else if (gamepad.dpad == element)
{
if (gamepad.dpad.xAxis.value > 0)
{
print("scrollWindowRight")
}
else if (gamepad.dpad.xAxis.value < 0)
{
print("scrollWindowLeft")
}
else if (gamepad.dpad.yAxis.value > 0)
{
print("scrollWindowDown")
}
else if (gamepad.dpad.yAxis.value < 0)
{
print("scrollWindowUp")
}
}
} // controllerInputDetected
} // class GameScene: SKScene
Now, the GameViewController ..
import UIKit
import SpriteKit
import GameplayKit
import WebKit
// This is now available across Classes
var theWebView: WKWebView!
class GameViewController: UIViewController, WKNavigationDelegate {
override func loadView() {
// print("loadView")
let webConfiguration = WKWebViewConfiguration()
theWebView = WKWebView(frame: .zero, configuration: webConfiguration)
theWebView.navigationDelegate = self
view = theWebView
} // loadView
override func viewDidLoad() {
super.viewDidLoad()
// print("viewDidLoad")
loadURL(webAddress: "https://www.lovesongforever.com/firstgame")
} // viewDidLoad
func loadURL(webAddress: String) {
let theURL = URL(string: webAddress)
let theRequest = URLRequest(url: theURL!)
theWebView.load(theRequest)
theWebView.allowsBackForwardNavigationGestures = false
} // loadURL
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
}
else {
return .all
}
} // supportedInterfaceOrientations
override var prefersStatusBarHidden: Bool {
return true
} // prefersStatusBarHidden
} // class GameViewController
Note that when I RUN my iOS App, thanks to the overridden loadView() above, it presents the following in the Simulator:
Simulator presentation
But, that’s is as far as it goes, because pressing all the buttons on my Gamepad does not result in detection of my Gamepad, as evidenced when I UN-comment all the above print(..) statements. In particular, those within:
#objc func connectControllers() and
#objc func disconnectControllers() and
func controllerInputDetected( .. )
So, hopefully that is all there currently is ..
You are doing this in your app delegate:
let itsGameScene = GameScene()
itsGameScene.ObserveForGameControllers()
You're creating an instance of GameScene, making it listen for notifications (adding self as the observer)... and then probably throwing that instance away.
Your game isn't actually using SpriteKit, and SpriteKit isn't needed to deal with game controllers, you just need GameController.
You have no need to create this scene at all. The best place to observe the game controller notifications would be in your GameViewController in viewDidLoad. Move the code (the observation method and the controller-related ones) you had in your scene into the view controller, and delete the scene file.
I'm trying to create in app purchases on an SKScene in my game. The scene is called coinShop. Basically, an IAP that gives the user 300 coins. When I tried copying code, it said SKScene can not conform to the delegates I tried adding. If anybody knows how do in app purchases with a scene instead of a viewcontroller, I would love to know. Here is all the code relating to in app purchases
in the didMoveToView(), i have
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
requestProductInfo()
productIDs.append("com.ClearRockTechnologies.alien-anarchy.300Coins")
and then i have the following functions
func requestProductInfo() {
if SKPaymentQueue.canMakePayments() {
let productIdentifiers = NSSet(array: productIDs)
let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers as Set<NSObject> )
productRequest.delegate = self
productRequest.start()
}
else {
print("Cannot perform In App Purchases.")
}
}
func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
if response.products.count != 0 {
for product in response.products {
productsArray.append(product)
}
}
else {
print("There are no products.")
}
if response.invalidProductIdentifiers.count != 0 {
print(response.invalidProductIdentifiers.description)
}
}
func showActions() {
let payment = SKPayment(product: self.productsArray[0] as SKProduct)
SKPaymentQueue.defaultQueue().addPayment(payment)
//self.transactionInProgress = true
}
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
for transaction in transactions as! [SKPaymentTransaction] {
switch transaction.transactionState {
case SKPaymentTransactionState.Purchased:
print("Transaction completed successfully.")
SKPaymentQueue.defaultQueue().finishTransaction(transaction)
coins+=300
NSUserDefaults.standardUserDefaults().setInteger(coins, forKey: "coins")
case SKPaymentTransactionState.Failed:
print("Transaction Failed");
SKPaymentQueue.defaultQueue().finishTransaction(transaction)
default:
print(transaction.transactionState.rawValue)
}
}
}
and here are my two errors,
Type 'coinShop' does not conform to protocol 'SKPaymentTransactionObserver'
'NSSet' is not implicitly convertible to 'Set'; did you mean to use 'as' to explicitly convert?
Error 1 has no suggestion, and error 2 tells me to add as "Set< NSObject >" to this line
let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers as Set<NSObject> )
but I clearly already have that. Any help would be appreciated.
I am putting together a simple estimote test using swift and coreLocation. However I am not getting didEnterRegion, didExitRegion
I read following answers already but it still didn't end my problem.
startMonitoringForRegion never calls didEnterRegion/didExitRegion
locationManager:didEnterRegion not called when a beacon is detected
I added Background modes (Location updates)
I get the "didStartMonitoringForRegion" log in the output but then don't get any didenter or exit. I tried to walk out of house with beacon and back in but no luck. Ranging however works.
var locManager: CLLocationManager = CLLocationManager()
let iceRegion: CLBeaconRegion = CLBeaconRegion(proximityUUID: BEACON_PROXIMITY_UUID, major: BEACON_ICE_MAJOR, identifier: "ice")
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if locManager.respondsToSelector("requestAlwaysAuthorization") {
locManager.requestAlwaysAuthorization()
}
if (self.deviceSettingsAreCorrect())
{
iceRegion.notifyOnEntry = true
iceRegion.notifyOnExit = true
iceRegion.notifyEntryStateOnDisplay = true
locManager.delegate = self
locManager.startMonitoringForRegion(iceRegion)
locManager.startRangingBeaconsInRegion(iceRegion)
}
}
func locationManager(manager: CLLocationManager!, didStartMonitoringForRegion region: CLRegion!) {
println("didStartMonitoringForRegion");
locManager.requestStateForRegion(region);
}
func locationManager(manager: CLLocationManager!, didEnterRegion region: CLRegion!) {
println("did Enter Region")
}
func locationManager(manager: CLLocationManager!, didExitRegion region: CLRegion!) {
println("did Exit Region")
}
func locationManager(manager: CLLocationManager!, didDetermineState state: CLRegionState, forRegion region: CLRegion!) {
println("didDetermineState \(state)");
switch state {
case .Inside:
println("BeaconManager:didDetermineState CLRegionState.Inside");
case .Outside:
println("BeaconManager:didDetermineState CLRegionState.Outside");
case .Unknown:
println("BeaconManager:didDetermineState CLRegionState.Unknown");
default:
println("BeaconManager:didDetermineState default");
}
}
func locationManager(manager: CLLocationManager!, didRangeBeacons beacons: [CLBeacon]!, inRegion region: CLBeaconRegion!) {
println("BM didRangeBeacons");
for beacon: CLBeacon in beacons {
// TODO: better way to unwrap optionals?
if let major: String = beacon.major?.stringValue {
if let minor: String = beacon.minor?.stringValue {
println(major)
}
}
}
}
func deviceSettingsAreCorrect() -> Bool {
var errorMessage = ""
if !CLLocationManager.locationServicesEnabled()
|| (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.Denied) {
errorMessage += "Location services are turned off! Please turn them on!\n"
}
if !CLLocationManager.isRangingAvailable() {
errorMessage += "Ranging not available!\n"
}
if !CLLocationManager.isMonitoringAvailableForClass(CLBeaconRegion) {
errorMessage += "Beacon monitoring not supported!\n"
}
let errorLen = countElements(errorMessage)
if errorLen > 0 {
println(errorMessage)
}
return errorLen == 0
}
I am setting up an iOS 8 app to request Heath Kit Store authorization to share types. The request Read/Write screen shows fine and on selecting Done, I see the completion callback immediately after. In this callback, I am pushing a new view controller. I set a breakpoint for the code that is programmatically pushing the next view controller and this is called immediately, but the transition doesn't occur until about 10 seconds later.
Some code:
#IBAction func enable(sender: AnyObject) {
let hkManager = HealthKitManager()
hkManager.setupHealthStoreIfPossible { (success, error) -> Void in
if let error = error {
println("error = \(error)")
} else {
println("enable HK success = \(success)")
self.nextStep()
}
}
}
func nextStep() {
self.nav!.pushViewController(nextController, animated: true)
}
class HealthKitManager: NSObject {
let healthStore: HKHealthStore!
override init() {
super.init()
healthStore = HKHealthStore()
}
class func isHealthKitAvailable() -> Bool {
return HKHealthStore.isHealthDataAvailable()
}
func setupHealthStoreIfPossible(completion: ((Bool, NSError!) -> Void)!) {
if HealthKitManager.isHealthKitAvailable()
{
healthStore.requestAuthorizationToShareTypes(dataTypesToWrite(), readTypes: dataTypesToRead(), completion: { (success, error) -> Void in
completion(success, error)
})
}
}
func dataTypesToWrite() -> NSSet {
let runningType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)
let stepType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)
return NSSet(objects: runningType, stepType)
}
func dataTypesToRead() -> NSSet {
let runningType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)
let stepType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)
let climbedType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierFlightsClimbed)
return NSSet(objects: runningType, stepType, climbedType)
}
}
Any thoughts on what is causing the time delay for the transition?
The problem was that the completion block is returned in the background queue. I just put the transition call back onto the main queue as follows:
hkManager.setupHealthStoreIfPossible { (success, error) -> Void in
if let error = error {
println("error = \(error)")
} else {
dispatch_async(dispatch_get_main_queue(), {
println("enable HK success = \(success)")
self.nextStep()
});
}
}
}
I am having a problem with adding homes with HMHomeManager. I can call the function add well, but HMHomeManager does not return
func homeManager(manager: HMHomeManager!, didAddHome home: HMHome!) {
println("\(__FUNCTION__)")
}
I am sure I already assigned the delegate of homeManager. Below is my code:
class ViewController: UIViewController, HMHomeManagerDelegate {
var manager: HMHomeManager
required init(coder aDecoder: NSCoder) {
manager = HMHomeManager()
super.init(coder: aDecoder)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
manager.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Actions
#IBAction func home1Pressed(sender: UIButton) {
manager.addHomeWithName("Home12", completionHandler: {
(home:HMHome!, error:NSError!) -> Void in
if error != nil {
println("error: \(error)")
}
else {
println("no error")
}
})
}
#IBAction func home2Pressed(sender: UIButton) {
manager.addHomeWithName("Home23", completionHandler: {
(home:HMHome!, error:NSError!) -> Void in
if error != nil {
println("error: \(error)")
}
else {
println("no error")
}
})
}
// MARK: - HMHomeManagerDelegate
func homeManagerDidUpdateHomes(manager: HMHomeManager!) {
println("\(__FUNCTION__)")
}
func homeManagerDidUpdatePrimaryHome(manager: HMHomeManager!) {
println("\(__FUNCTION__)")
}
func homeManager(manager: HMHomeManager!, didAddHome home: HMHome!) {
println("\(__FUNCTION__)")
}
func homeManager(manager: HMHomeManager!, didRemoveHome home: HMHome!) {
println("\(__FUNCTION__)")
}
}
Note that: when I first run this code, homeManagerDidUpdateHomes is called which proves to me that homeManager.delegate=self is correct
In this code, after I pressed button1 (home1Pressed triggered) and button2 (home1Pressed triggered), home12 and home23 are created. I know this because next time I run this code, the output is:
homeManagerDidUpdateHomes
homes: [[ name = Home1, primary : Yes ], [ name = Home12, primary : No ], [ name = Home23, primary : No ]]
But Why homeManager(manager: HMHomeManager!, didAddHome home: HMHome! is not called when I pressed button1 and button2? I cannot figure it out, for 2 days.
Thanks,
Did you remember to enable HomeKit in Capabilities?
Quoting from Apple Dev Forum discussions:
This is not a bug but yeah, it should be better documented.
All HomeKit's delegates will only get invoked when there are changes in HomeKit database that are not caused by the app or doesn't have a direct connection to your completion handler (Like Synced from iCloud, another HomeKit app added a room then user switched to your app)
I get the same error. As a workaround, I am getting the homeManagerDidUpdatePrimaryHome callback. I filed a bug for this during the beta, which was closed as a duplicate, but I guess it needs to be refiled.
homeManagerDidUpdatePrimaryHome is working, but that really only helps with the first home.
I re-reported this to Apple.
This is an iOS bug (tested with 8.3).
21097472 HomeKit API - HMHomeManagerDelegate didAddHome is not called