requestAccessToEntityType - once or every time? - ios

EKEventStore *eventStore = [[UpdateManager sharedUpdateManager] eventStore];
if ([eventStore respondsToSelector:#selector(requestAccessToEntityType:completion:)])
{
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error)
{
if (granted)...
I want to ask the user for permission to add an event to his calendar. After it's granted do I need to ask for permission again when I want for example to remove an event (in another session after the app was closed and reopened) or is it just a want time thing?
If it's a one time thing, can I just put it in ViewDidLoad at first lunch just to "get rid of it" ?

You only need to call it once:
BOOL needsToRequestAccessToEventStore = NO; // iOS 5 behavior
EKAuthorizationStatus authorizationStatus = EKAuthorizationStatusAuthorized; // iOS 5 behavior
if ([[EKEventStore class] respondsToSelector:#selector(authorizationStatusForEntityType:)]) {
authorizationStatus = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
needsToRequestAccessToEventStore = (authorizationStatus == EKAuthorizationStatusNotDetermined);
}
if (needsToRequestAccessToEventStore) {
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted) {
dispatch_async(dispatch_get_main_queue(), ^{
// You can use the event store now
});
}
}];
} else if (authorizationStatus == EKAuthorizationStatusAuthorized) {
// You can use the event store now
} else {
// Access denied
}
You shouldn't do that on the first launch, though. Only request access when you need it and that isn't the case just until the user decides to add an event.

Related

IOS/Objective-C:EventKit EKReminders compared with EKEvents

I a experimenting with EventKit and am confused by how events compare with reminders.
Do you need to obtain separate permission to access reminders and events?
I know there is such a thing as self.eventStore requestAccessToEntityType:EKEntityTypeReminder and also requestAccessToEntityType:EKEntityTypeEvent
Here are methods for both. But it seems excessive to have to ask for permission for things that are so closely related twice.
-(void)requestAccessToEvents{
[self.eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (error == nil) {
// Store the returned granted value.
self.grantedEvents = granted;
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:granted] forKey:#"eventsAccessGranted"];
}
else{
// In case of error, just log its description to the debugger.
NSLog(#"%#", [error localizedDescription]);
}
}];
}
-(void) requestAccessToReminders
{
[self.eventStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error)
{
if (error == nil) {
// Store the returned granted value.
self.grantedReminders = granted;
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:granted] forKey:#"remindersAccessGranted"];
}
else{
// In case of error, just log its description to the debugger.
NSLog(#"%#", [error localizedDescription]);
}
if (granted)
{
importEvents * __weak weakSelf = self;
//ensure code will be executed from the main queue
dispatch_async(dispatch_get_main_queue(), ^{
// [weakSelf aMethodToUpdateUIFetchEvents];//method located in viewController
});
}
}];
}
Thanks for any suggestions.
EKEntityTypeEvent is for events that go to the user's calendar.
EKEntityTypeReminder is for reminders that go to the user's reminders.
Each requires its own request for permission. A user might allow access to one but not the other. Ignore that the APIs are similar and related. To the user, they are two completely different things.

How to set a prompt for second time when user has clicked Don't allow for permissions the first time?

I want to add a prompt when user access the calendar second time, when initially user has clicked Don't Allow for the first access permissions for calendar.
// For iOS 6.0 and later
EKEventStore *_eventStore [[EKEventStore alloc] init];
[_eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
// handle access here
}];
EKEventStore *_reminderStore [[EKEventStore alloc] init];
[_reminderStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
// handle access here
}];
This piece of code is for the first time when user is being asked for the permissions, can anyone please tell me, what to do when user has clicked Don't allow after this ?
You can put the second request inside the first request's block.
So it would look like this:
// For iOS 6.0 and later
EKEventStore *_eventStore [[EKEventStore alloc] init];
[_eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted) {
[_eventStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
// handle access here
}];
}
}];
Also keep in mind that initializing an EKEventStore is expensive. Try to only use one instance of it. That information and more can be found in the documentation

CMMotionActivityManager callback when user not allow the permisson

I am using the following code from the Privacy Prompts project to get the Motion Permission.
- (void)requestMotionAccessData {
self.cmManager = [[CMMotionActivityManager alloc] init];
self.motionActivityQueue = [[NSOperationQueue alloc] init];
[self.cmManager startActivityUpdatesToQueue:self.motionActivityQueue withHandler:^(CMMotionActivity *activity) {
/*
* Do something with the activity reported
*/
NSLog(#"requestMotionAccessData");
[self alertViewWithDataClass:Motion status:NSLocalizedString(#"ALLOWED", #"")];
[self.cmManager stopActivityUpdates];
}];
}
What if user not allow the motion permission. Do i get some callback?
If not is there an alternative way to get the this. I want the callback when user selects Allow or Don't Allow
you just can ... picking the error:
[stepCounter queryStepCountStartingFrom:[NSDate date]
to:[NSDate date]
toQueue:[NSOperationQueue mainQueue]
withHandler:^(NSInteger numberOfSteps, NSError *error) {
if (error != nil && error.code == CMErrorMotionActivityNotAuthorized) {
// The app isn't authorized to use motion activity support.
}
from here: iOS - is Motion Activity Enabled in Settings > Privacy > Motion Activity

Opening Reminder application within iOS application?

Is it possible to use iOS Reminder Built in Application within the App I develop?
I dont want to use OPEN URL concept, because it will quit my app an open Reminder App?
Can I please any Custom Reminder App deveoped by iOS SDk , which will create Reminder
in iOS's Reminder Application
There is a reminders API that allows you to create and retrieve reminders.
You'll first have to ask for user permission to do so:
EKEventStore *store = [[EKEventStore alloc] initWithAccessToEntityTypes:EKEntityMaskReminder];
[store requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
if (granted) {
[self createReminder:store];
}
else {
// :(
}
}];
To create a reminder you could:
- (void)createReminder:(EKEventStore *)store {
//Create a reminder instance
EKReminder *aReminder = [EKReminder reminderWithEventStore:store];
// Set the properties
aReminder.title = #"Remember to do X";
...
// Then save the reminder to the store
NSError *error = nil;
[store saveReminder:aReminder commit:YES error:&error];
// Be responsible
if (error) {
[self rememberToHandleYourErrors:error];
}
}

Expired access token after openActiveSession for Facebook iOS SDK

I'm using the 3.1 Facebook SDK with iOS 6 Facebook set up in Settings and my app authorized.
This executes flawlessly:
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession *fbSession, FBSessionState fbState, NSError *error) { ... }
However now when I try to get 'me' information I'm getting an error:
com.facebook.sdk:ParsedJSONResponseKey = {
body = {
error = {
code = 190;
"error_subcode" = 463;
message = "Error validating access token: Session has expired at unix time 1348704000. The current unix time is 1348706984.";
type = OAuthException;
};
};
code = 400;
}
If I look at [error code] it's equal to 5. Shouldn't I have a valid access token after just logging in? Do I need to call reauthorize?
UPDATE: Reauthorizing doesn't help. Oddly the accessToken for my activeSession is always coming back the same. This despite calling closeAndClearToken.
UPDATE:
This issue has been addressed in Facebook iOS SDK 3.1.1.
I synched the code off of github and found that they weren't calling accountStore renewCredentialsForAccount:completion: anywhere. I changed the following code in authorizeUsingSystemAccountStore and it seems to have resolved the issue.
// we will attempt an iOS integrated facebook login
[accountStore requestAccessToAccountsWithType:accountType
options:options
completion:^(BOOL granted, NSError *error) {
// this means the user has not signed-on to Facebook via the OS
BOOL isUntosedDevice = (!granted && error.code == ACErrorAccountNotFound);
dispatch_block_t postReauthorizeBlock = ^{
NSString *oauthToken = nil;
if (granted) {
NSArray *fbAccounts = [accountStore accountsWithAccountType:accountType];
id account = [fbAccounts objectAtIndex:0];
id credential = [account credential];
oauthToken = [credential oauthToken];
}
// initial auth case
if (!isReauthorize) {
if (oauthToken) {
_isFacebookLoginToken = YES;
_isOSIntegratedFacebookLoginToken = YES;
// we received a token just now
self.refreshDate = [NSDate date];
// set token and date, state transition, and call the handler if there is one
[self transitionAndCallHandlerWithState:FBSessionStateOpen
error:nil
token:oauthToken
// BUG: we need a means for fetching the expiration date of the token
expirationDate:[NSDate distantFuture]
shouldCache:YES
loginType:FBSessionLoginTypeSystemAccount];
} else if (isUntosedDevice) {
// even when OS integrated auth is possible we use native-app/safari
// login if the user has not signed on to Facebook via the OS
[self authorizeWithPermissions:permissions
defaultAudience:defaultAudience
integratedAuth:NO
FBAppAuth:YES
safariAuth:YES
fallback:YES
isReauthorize:NO];
} else {
// create an error object with additional info regarding failed login
NSError *err = [FBSession errorLoginFailedWithReason:nil
errorCode:nil
innerError:error];
// state transition, and call the handler if there is one
[self transitionAndCallHandlerWithState:FBSessionStateClosedLoginFailed
error:err
token:nil
expirationDate:nil
shouldCache:NO
loginType:FBSessionLoginTypeNone];
}
} else { // reauth case
if (oauthToken) {
// union the requested permissions with the already granted permissions
NSMutableSet *set = [NSMutableSet setWithArray:self.permissions];
[set addObjectsFromArray:permissions];
// complete the operation: success
[self completeReauthorizeWithAccessToken:oauthToken
expirationDate:[NSDate distantFuture]
permissions:[set allObjects]];
} else {
// no token in this case implies that the user cancelled the permissions upgrade
NSError *error = [FBSession errorLoginFailedWithReason:FBErrorReauthorizeFailedReasonUserCancelled
errorCode:nil
innerError:nil];
// complete the operation: failed
[self callReauthorizeHandlerAndClearState:error];
// if we made it this far into the reauth case with an untosed device, then
// it is time to invalidate the session
if (isUntosedDevice) {
[self closeAndClearTokenInformation];
}
}
}
};
if (granted) {
[accountStore renewCredentialsForAccount:[[accountStore accountsWithAccountType:accountType] lastObject] completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) {
dispatch_async(dispatch_get_main_queue(), postReauthorizeBlock);
}];
} else {
// requestAccessToAccountsWithType:options:completion: completes on an
// arbitrary thread; let's process this back on our main thread
dispatch_async(dispatch_get_main_queue(), postReauthorizeBlock);
}
}];
}
So it's addressed, but I've been calling /me from our backend to verify since you can't trust the device.
So I make a call to FBSession's + (void)renewSystemAuthorization when the backend comes back with an authorization error.

Resources