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.
Related
I want to use Facebook graph API to share on Facebook through my app, without presenting share dialog.But on reading various threads on internet i'm really confused about how to achieve this. i found this post on stack overflow but didn't able to find out how to make it works.
Can anyone give me step by step guideline or source code. any help would be highly appreciated.
Edit: code i used so far-
- (IBAction)StatusUpdateWithAPICalls:(id)sender {
[self openSessionForReadPermissions];
}
- (void)openSessionForReadPermissions
{
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
//this is called even from the reauthorizeWithPublishPermissions
if (state == FBSessionStateOpen && !error)
{
//[self openSessionForPublishPermissions];
//dispatch_async(dispatch_get_current_queue(), ^{
[self openSessionForPublishPermissions];
//});
}
else if (state == FBSessionStateClosedLoginFailed)
{
[FBSession.activeSession closeAndClearTokenInformation];
// [[NSNotificationCenter defaultCenter] postNotificationName:FBLoginErrorNotification object:session];
}
}];
}
-(void)openSessionForPublishPermissions
{
// We will post on behalf of the user, these are the permissions we need:
NSArray *permissionsNeeded = #[#"publish_actions"];
// Request the permissions the user currently has
[FBRequestConnection startWithGraphPath:#"/me/permissions"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error){
// Parse the list of existing permissions and extract them for easier use
NSMutableArray *currentPermissions = [[NSMutableArray alloc] init];
NSArray *returnedPermissions = (NSArray *)[result data];
for (NSDictionary *perm in returnedPermissions) {
if ([[perm objectForKey:#"status"] isEqualToString:#"granted"]) {
[currentPermissions addObject:[perm objectForKey:#"permission"]];
}
}
// Build the list of requested permissions by starting with the permissions
// needed and then removing any current permissions
NSMutableArray *requestPermissions = [[NSMutableArray alloc] initWithArray:permissionsNeeded copyItems:YES];
[requestPermissions removeObjectsInArray:currentPermissions];
NSLog(#"Asking: %#", requestPermissions);
// If we have permissions to request
if ([requestPermissions count] > 0){
// Ask for the missing permissions
[FBSession.activeSession requestNewPublishPermissions:requestPermissions
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
if (!error) {
// Permission granted, we can request the user information
[self makeRequestToUpdateStatus];
} else {
// An error occurred, handle the error
NSLog(#"%#", error.description);
}
}];
} else {
// Permissions are present, we can request the user information
[self makeRequestToUpdateStatus];
}
} else {
// There was an error requesting the permission information
// See our Handling Errors guide: https://developers.facebook.com/docs/ios/errors/
NSLog(#"%#", error.description);
}
}];
}
- (void)makeRequestToUpdateStatus {
// NOTE: pre-filling fields associated with Facebook posts,
// unless the user manually generated the content earlier in the workflow of your app,
// can be against the Platform policies: https://developers.facebook.com/policy
[FBRequestConnection startForPostStatusUpdate:#"User-generated status update."
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
// Status update posted successfully to Facebook
NSLog(#"result: %#", result);
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
NSLog(#"%#", error.description);
}
}];
}
but i getting this error-
Error Domain=com.facebook.sdk Code=2 "The operation couldn’t be completed. com.facebook.sdk:ErrorReauthorizeFailedReasonUserCancelled" UserInfo=0x78788e60 {com.facebook.sdk:ErrorLoginFailedReason=com.facebook.sdk:ErrorReauthorizeFailedReasonUserCancelled, NSLocalizedFailureReason=com.facebook.sdk:ErrorReauthorizeFailedReasonUserCancelled, com.facebook.sdk:ErrorSessionKey=<FBSession: 0x787ac750, state: FBSessionStateOpen, loginHandler: 0x787ac710, appID: 4201XXXXXXXXXXX, urlSchemeSuffix: , tokenCachingStrategy:<FBSessionTokenCachingStrategy: 0x7a1c1b50>, expirationDate: 2015-04-20 06:48:00 +0000, refreshDate: 2015-02-19 09:39:47 +0000, attemptedRefreshDate: 0000-12-30 00:00:00 +0000, permissions:(
"public_profile"
)
And i'm not sure if i'm doing it right. please suggest me.
Use fallbacks.
Upload a photo via an app. FB logged in account
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
I want to delete all HKQuantitySamples that my app has saved in the Health App for a certain HKQuantityType, how would I do that?
I can see the function
deleteObject:withCompletion:
in the Apple Documentation, but I do not really understand how to use it. Can somebody show an example maybe?
EDIT: I now use the following code for deleting:
I have saved my food information as a HKCorrelation and set my Local Food ID in the Correlations metadata HKMetadataKeyExternalUUID key.
For deletion I am fetching all the HKCorrelation objects between startDate and endDate and then if one of these fetched objects matches the Local Food ID I am looking for:
- I delete every object in that Correlation,
- Followed by deleting the Correlation itself
HKCorrelationType *foodType = [HKObjectType correlationTypeForIdentifier:HKCorrelationTypeIdentifierFood];
NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionNone];
HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:foodType predicate:predicate limit:HKObjectQueryNoLimit sortDescriptors:nil resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
if (!results) {
NSLog(#"An error occured fetching the user's tracked food. In your app, try to handle this gracefully. The error was: %#.", error);
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
for (HKCorrelation *foodCorrelation in results) {
if([[foodCorrelation.metadata valueForKey:HKMetadataKeyExternalUUID] isEqualToString:food_id_I_want_to_delete]) {
NSSet *objs = foodCorrelation.objects;
for (HKQuantitySample *sample in objs) {
[self.healthStore deleteObject:sample withCompletion:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"Success. delete sample");
}
else {
NSLog(#"delete: An error occured deleting the sample. In your app, try to handle this gracefully. The error was: %#.", error);
}
}];
}
[self.healthStore deleteObject:foodCorrelation withCompletion:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"Success. delete %#", [foodCorrelation.metadata valueForKey:HKMetadataKeyExternalUUID]);
}
else {
NSLog(#"delete: An error occured deleting the Correlation. In your app, try to handle this gracefully. The error was: %#.", error);
}
}];
return;
}
}
});
}];
[self.healthStore executeQuery:query];
I am not able to get the permissions for user_birthday and user_hometown.
I tried it with this code before but it only asks for the public profile and ignores others.
[FBSession openActiveSessionWithReadPermissions:#[#"public_profile",#"user_birthday",#"user_hometown"]
allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (error) {
NBAppDelegate* appDel = (NBAppDelegate*)`[UIApplication sharedApplication].delegate;
[appDel sessionStateChanged:session state:status error:error];
}
if ([session isOpen]) {
[self loginWithFBToken:session name:sender];
}
}];
Then someone suggested to ask for additional permissions after getting the public profile, so i even tried that to no good.
Here is the code for that
- (void)loadFbDetails
{
NSArray *permissionsNeeded = #[#"user_hometown", #"user_birthday"];
// Request the permissions the user currently has
[FBRequestConnection startWithGraphPath:#"/me/permissions"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error){
// These are the current permissions the user has:
NSDictionary *currentPermissions= [(NSArray *)[result data] objectAtIndex:0];
// We will store here the missing permissions that we will have to request
NSMutableArray *requestPermissions = [[NSMutableArray alloc] initWithArray:#[]];
// Check if all the permissions we need are present in the user's current permissions
// If they are not present add them to the permissions to be requested
for (NSString *permission in permissionsNeeded){
if (![currentPermissions objectForKey:permission]){
[requestPermissions addObject:permission];
}
}
// If we have permissions to request
if ([requestPermissions count] > 0){
// Ask for the missing permissions
[FBSession.activeSession
requestNewReadPermissions:requestPermissions
completionHandler:^(FBSession *session, NSError *error) {
if (!error) {
// Permission granted
NSLog(#"new permissions %#", [FBSession.activeSession permissions]);
// We can request the user information
[self makeRequestForUserData];
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
}
}];
} else {
// Permissions are present
// We can request the user information
[self makeRequestForUserData];
}
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
}
}];
}
-(void)makeRequestForUserData
{
[FBRequestConnection startWithGraphPath:#"me?fields=birthday,hometown"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
// Sucess! Include your code to handle the results here
NSLog(#"user events: %#", result);
} else {
NSLog(#"error: %#" , error);
}
}];
}
All it does is recursively go between my ios app and the fb native app, returning only with the public_profile in the permissions array.
Looks like i am missing something?
It should work if you're using an admin user of the app. Once you want to use the extended permissions with other users, you have to get your app reviewed by Facebook first.
See my answer here: facebook extended permission
Facebook does not allow apps to access that information by default. You have to ask permission to Facebook for you to be able to use that information. Add a video and instructions for a Facebook employee review how you're using birthday and hometown intel.
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.