CMMotionActivityManager authorization status - ios

I'm trying to figure out a way to handle the authorization statuses for Motion activity
Here's what I came up with so far :
manager = CMMotionActivityManager()
manager.queryActivityStartingFromDate(now, toDate: now, toQueue: NSOperationQueue.mainQueue(),
withHandler: { (activities: [CMMotionActivity]?, error: NSError?) -> Void in
if(error != nil){
if(error!.code != Int(CMErrorMotionActivityNotAuthorized.rawValue)){
print("CMErrorMotionActivityNotAuthorized")
}else if(error!.code != Int(CMErrorMotionActivityNotEntitled.rawValue)){
print("CMErrorMotionActivityNotEntitled")
}else if(error!.code != Int(CMErrorMotionActivityNotAvailable.rawValue)){
print("CMErrorMotionActivityNotAvailable")
}
}
})
One problem though :
When I deny the app permission to motion activity (via settings), I get CMErrorMotionActivityNotEntitled
(I believe I should be getting CMErrorMotionActivityNotAuthorized instead)
Any ideas why ? or at least what's the proper way of doing this ?

Perhaps you are getting CMErrorMotionActivityNotAuthorized. You'll never know, with your code, because your code does not ask what code you are getting. It asks what code you are not getting:
if(error!.code != Int(CMErrorMotionActivityNotAuthorized.rawValue)){
print("CMErrorMotionActivityNotAuthorized")
}else if(error!.code != Int(CMErrorMotionActivityNotEntitled.rawValue)){
print("CMErrorMotionActivityNotEntitled")
}else if(error!.code != Int(CMErrorMotionActivityNotAvailable.rawValue)){
print("CMErrorMotionActivityNotAvailable")
}
The != operator means is not. So you are doing a series of checks about what the code is not. It's hard to see how you can get any useful information by asking that question. It might make more sense to ask what the code is, which would involve using the == operator.

Related

Device not working with Firebase Authentication Phone Number

I have an iPhone that I'm trying to use with firebase authentication using phone numbers.
The project works and the emulator + device (without sim card) works using that phone number of the device that doesn't work (receives sms). But when I try to "login" on the device (with sim) I keep getting nil from verifyPhoneNumber. Is there something I'm missing that has to be active on the device?
This is the code that I'm trying to call with the text field as +1**********, along with FirebaseApp.configure() in the AppDelegate
PhoneAuthProvider.provider().verifyPhoneNumber(phoneTextField.text!, uiDelegate: nil) { (veri, error) in
if error != nil {
print(veri)
} else {
print(error)
}
}
There is likely an error, but it's not surfacing because the if statement is backwards. Instead, it should be
PhoneAuthProvider.provider().verifyPhoneNumber(phoneTextField.text!, uiDelegate: nil) { (veri, error) in
if error != nil {
print(error)
} else {
print(veri)
}
}
This will then print error instead of veri. It's likely printing nil because veri has no value if there's an error.

HKErrorDomain (HealthKit Error Domain) Constant in Xamarin

I am writing some error handling for when my HealthKit client requests permission to data in Xamarin iOS. I make the request like so:
public HKClient()
{
var HealthKitStore = new HKHealthStore();
HealthKitStore.RequestAuthorizationToShare (dataTypesToWrite, dataTypesToRead, OnHealthPermissionsCompleted);
}
void OnHealthPermissionsCompleted (bool success, NSError error)
{
//Parse error.Domain and error.Code herere
}
In my OnHealthPermissionsCompleted, I want to parse the NSError in order to debug why our request failed. The first thing to do is check error.Domain to make sure it is a HealthKit error and then compare error.Code to the constants in the HKErrorCode enum. The problem is, I cannot find any constant for what should be in error.Domain for HealthKit related errors. The Apple documentation says there should be a constant called "HKErrorDomain" for me to compare to, however it is not there in Xamarin.
https://developer.apple.com/library/prerelease/watchos/documentation/HealthKit/Reference/HealthKit_Constants/index.html#//apple_ref/doc/constant_group/Health_Kit_Error_Domain
https://developer.xamarin.com/api/namespace/HealthKit/
If I force an error and then check it in the debugger, I do see that error.Domain = "com.apple.healthkit". I could just compare to that string,
void OnHealthPermissionsCompleted (bool success, NSError error)
{
if(!success && error.Domain == "com.apple.healthkit")
{
//continue parsing...
}
}
but putting magic strings in these kinds of things makes me feel icky, especially when I know a constant for this exists in native iOS. Am I missing something here or is this my only option?
There is now a bug filed on Xamarin's Bugzilla to surface this constant:
https://bugzilla.xamarin.com/show_bug.cgi?id=34140

how to correctly make cloud code request with parse?

I am attempting to make all my user sessions with Parse exclusive, meaning if a user is already logged in on a certain device in a certain location, if another device logs in with the same credentials, I want the previous session(s) to be terminated, with a message of an alert view of course. Sort of like the old AOL Instant Messaging format. I figured the code for this action should be written in the login logic, so I wrote this within my login "succession" code :
PFUser.logInWithUsernameInBackground(userName, password: passWord) {
(user, error: NSError?) -> Void in
if user != nil || error == nil {
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("loginSuccess", sender: self)
PFCloud.callFunctionInBackground("currentUser", withParameters: ["PFUser":"currentUser"])
//..... Get other currentUser session tokens and destroy them
}
} else {
Thats probably not the correct cloud code call, but you get the point. When the user logs in once again on another device, I want to grab the other sessions and terminate them. Does anyone know the correct way to go about making this request in swift?
I speak swift with a stutter, but I think I can answer adequately in almost-swift. The key idea is to start the success segue only after the cloud says it's okay. Here's what I think you want:
PFUser.logInWithUsernameInBackground(userName, password: passWord) {
(user, error: NSError?) -> Void in
if (user != nil) {
// don't do the segue until we know it's unique login
// pass no params to the cloud in swift (not sure if [] is the way to say that)
PFCloud.callFunctionInBackground("isLoginRedundant", withParameters: []) {
(response: AnyObject?, error: NSError?) -> Void in
let dictionary = response as! [String:Bool]
var isRedundant : Bool
isRedundant = dictionary["isRedundant"]!
if (isRedundant) {
// I think you can adequately undo everything about the login by logging out
PFUser.logOutInBackgroundWithBlock() { (error: NSError?) -> Void in
// update the UI to say, login rejected because you're logged in elsewhere
// maybe do a segue here?
}
} else {
// good login and non-redundant, do the segue
self.performSegueWithIdentifier("loginSuccess", sender: self)
}
}
} else {
// login failed for typical reasons, update the UI
}
}
Please don't take me too seriously on swift syntax. The idea is to nest the segue in the completion handlers to know that you need to do it before starting it. Also, please note that the explicit placement on the main_queue within the completion handler is unnecessary. The SDK runs those blocks on the main.
A simple check to determine if a user's session is redundant (not unique) looks like this...
Parse.Cloud.define("isLoginRedundant", function(request, response) {
var sessionQuery = new Parse.Query(Parse.Session);
sessionQuery.equalTo("user", request.user);
sessionQuery.find().then(function(sessions) {
response.success( { isRedundant: sessions.length>1 } );
}, function(error) {
response.error(error);
});
});

Parse + Swift + Anonymous

In an effort to create the easiest user experience possible, I am on a mission to accept a user as an anonymous user using Parse + Swift. I had thought to use the Anonymous user functions in Parse to accomplish that. As a result, I created the following code:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
self.setupParse()
// self.setupAppAppearance()
This first section is to create a user and see if at this point in the process - I have a nil objectId (typically true for the user when first they attempt to open the application).
var player = PFUser.currentUser()
if player?.objectId == nil {
}
else
{
println(player!.objectId)
}
If I have an objectId (indicating that I've been down this road before and saved an anonymous user object) - throw that to the console so I can see what it is and check it in the Parse user object. Cool - good so far.
Next - Check to see if the Object is nil again - this time to decide whether or not to attempt to perform an anonymous login - there's not a thing to use to generate an anonymous user other than this anonymous login action.
if player?.objectId == nil {
PFAnonymousUtils.logInWithBlock({
(success, error) -> Void in
if (error != nil)
{
println("Anonymous login failed.")
}
else
{
println("Anonymous login succeeded.")
If anonymous Login succeeded (still considering doing a network available check before trying to run these bits...but assuming network is valid) save a Bool to "isAnonymous" on the server to make sure that we have identified this user as anonymous - I may want that information later, so it seemed worth throwing this action.
Question 1: Do I need to re-query PFUser.currentUser() (known as player) to make sure that I have a valid anon user object that is connected to the server, or will the player object that I allocated earlier recognize that I've logged in and thereby recognize that I can throw other info into the associated record online? I think this is working as is - but I've been getting weird session token errors:
[Error]: invalid session token (Code: 209, Version: 1.7.5)
player!["isAnonymous"] = true as AnyObject
player!.saveInBackgroundWithBlock {
(success, error) -> Void in
if (error != nil)
{
println("error updating user record with isAnonymous true")
}
else
{
println("successfully updated user record with isAnonymous true")
}
}
}
})
}
else
{
}
return true
}
func setupParse()
{
Parse.setApplicationId("dW1UugqmsKkQCoqlKR3hX8dISjvOuApcffGAWR2a", clientKey: "BtXxjTjBRZVnCZbJODhd3UBUU8zuoPU1HBckXh4t")
enableAutomaticUserCreateInParse()
This next bit is just about trying to figure out some way to deal with those token problems. No idea whether it's doing me any good at all or not. It said to turn this on right after instantiating the Parse connection.
PFUser.enableRevocableSessionInBackgroundWithBlock({
(error) -> Void in
if (error != nil) {
println(error?.localizedDescription)
}
})
Next - just throwing around objects because I keep struggling with being connected and storing stuff or not being connected or losing session tokens. So - til I get this worked out - I'm creating more test objects than I can shake a stick at.
var testObject = PFObject(className: "TestObject")
testObject["foo"] = "barnone"
testObject.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
println("Object has been saved.")
}
}
Question2: it appears to me that PFUser.enableAutomaticUser() while very handy - causes some headaches when trying to figure out whether I'm logged in/online/whatever. Anyone have any solid experience with this and able to guide me on how you'd check whether you were connected or not - I need to know that later to be able to decide whether to save more things to the user object or not.
func enableAutomaticUserCreateInParse() {
if PFUser.currentUser()?.objectId == nil
{
myHumanGamePlayer.playerDisplayName = "Anonymous Player"
PFUser.enableAutomaticUser()
}
}
Anyone out there who's an expert on using anonymous users in Parse with Swift, let's get in touch and post a tutorial - because this has cost me more hours than I'd like to think about.
Thank you!
Xylus
For player!["isAnonymous"] = true as AnyObject, don't save it as any object. Save it as a bool and look at your parse to see if it's a bool object. Try querying for current user in a different view controller and print to the command line. I hope this helped

CMMotionactivitymanager authorizationstatus

I want to get the authorization status for CMMotionActivityManager. For other services like calendar and location we have some property in the API that gives us the user authorization status for these classes. How i can get the authorization status for CMMotionActivityManager class?
CMMotionActivityManager does not currently offer a way to check authorisation status directly like other frameworks.
iOS - is Motion Activity Enabled in Settings > Privacy > Motion Activity
However, as the comments in the above question mention, if you attempt a query using
queryActivityStartingFromDate:toDate:toQueue:withHandler
and the user has not authorised your application, the handler (CMMotionActivityQueryHandler) will return this error.
CMErrorMotionActivityNotAuthorized
With introduction of IOS 11.* there is the possibility to call CMMotionActivityManager.authorizationStatus() which gives you a detailed status.
Here's how I'm doing it :
manager = CMMotionActivityManager()
let today = NSDate()
manager.queryActivityStartingFromDate(today, toDate: today, toQueue: NSOperationQueue.mainQueue(),
withHandler: { (activities: [CMMotionActivity]?, error: NSError?) -> Void in
if let error = error where error.code == Int(CMErrorMotionActivityNotAuthorized.rawValue){
print("NotAuthorized")
}else {
print("Authorized")
}
})
I had to adjust Zakaria's answer a bit for Swift 3.0 and also the new Error made problems, so I had to convert it back to NSError to get the code but this is how my function looks now. Thanks!
func triggerActivityPermissionRequest() {
let manager = CMMotionActivityManager()
let today = Date()
manager.queryActivityStarting(from: today, to: today, to: OperationQueue.main, withHandler: { (activities: [CMMotionActivity]?, error: Error?) -> () in
if error != nil {
let errorCode = (error! as NSError).code
if errorCode == Int(CMErrorMotionActivityNotAuthorized.rawValue) {
print("NotAuthorized")
}
} else {
print("Authorized")
}
manager.stopActivityUpdates()
})
}

Resources