wmcmahan / react-native-calendar-events

📆 React Native Module for iOS and Android Calendar Events
MIT License
901 stars 289 forks source link

iOS 17 issues: unable to request permissions #440

Open RhysTowey opened 1 year ago

RhysTowey commented 1 year ago

I am running iOS 17 beta with XCode 15 beta and i'm getting issues when requesting permissions using this library. Works fine with iOS 16. Seems as if Apple have changed the Calendar permissions API on iOS 17: https://developer.apple.com/documentation/eventkit/accessing_calendar_using_eventkit_and_eventkitui#4250785

Environment

react: 17.0.2 react-native: 0.67.2 react-native-calendar-events: 2.2.0

Steps to Reproduce

Added the following to Info.plist

  <key>NSCalendarsUsageDescription</key>
  <string>This app requires access to the calendar</string>
  <key>NSCalendarsFullAccessUsageDescription</key>
  <string>This app requires access to the calendar</string>

(I've tried using just either one but same result)

import RNCalendarEvents from "react-native-calendar-events";

Requesting permissions:

 RNCalendarEvents.requestPermissions((readOnly = false)).then(response => {
            console.log(response);
 });

Checking permissions:

RNCalendarEvents.checkPermissions(false).then(async (response) => {
            console.log(response);
});

Actual Behavior

Requesting permissions response:

Error: authorization request error

Checking permissions response:

undetermined
andrejguran commented 1 year ago

if the library is not updated until new iOS is released (probably 12th Sept) you can use this commit that fixes calendar and gives full permission on request: https://github.com/andrejguran/react-native-calendar-events/commit/f8765674d966a623dc99ccab2e263171ff61155e

RhysTowey commented 1 year ago

if the library is not updated until new iOS is released (probably 12th Sept) you can use this commit that fixes calendar and gives full permission on request: andrejguran@f876567

This works perfectly, thank you!

taschik commented 1 year ago

@RhysTowey any plans to release something before the official release on 9/18 so we can get this shipped before users start updating?

RhysTowey commented 1 year ago

@andrejguran could you please submit a pull request for your fix? I'm hoping @wmcmahan can approve it soon.

andrejguran commented 1 year ago

@RhysTowey it's more complicated than that. New apple logic has 2 modes fullAccess / writeOnly while Android has fullAccess / readOnly. This lib was written to support both Android modes so adding 3rd writeOnly mode would need some thinking and design changes to the library which I think the maintainer should address.

Since for our needs we never need writeOnly mode we just quickly patched the lib and for the same reason we don't plan to implement the writeOnly mode and submit a PR.

mysport12 commented 11 months ago

@andrejguran thank you for the iOS17 permission changes!! @RhysTowey I ran with those and went a bit further to implement the writeOnly functionality on my fork. I too only need full access so I have not tested it out, but could provide a starting point. Note though that I made a number of other changes including some breaking ones to unify the API across iOS and Android for our use case so its not a direct plug and play. mysport12/react-native-calendar-events

jakehasler commented 11 months ago

I've tried working off of both the aforementioned branches, and I'm still having an issue where It's not prompting me for permissions and I'm always getting 'denied' returned from the requestPermissions function. My device doesn't have my app denied in the iOS privacy settings, and I've deleted/re-installed and even restarted my phone. Are any of y'all seeing this too?

mysport12 commented 11 months ago

@jakehasler Have you added the new NSCalendarsFullAccessUsageDescription permission to your Info.plist?

jakehasler commented 11 months ago

Welp, that was it. I had the original permission but had neglected to add the new one. All is good. Thanks so much @mysport12.

malwatte commented 11 months ago

Appreciate if a new version can be released with the fix

ziarno commented 11 months ago

is this going to be fixed? the last commit was a year ago, is this library maintained?

ziarno commented 11 months ago

if the library is not updated until new iOS is released (probably 12th Sept) you can use this commit that fixes calendar and gives full permission on request: andrejguran@f876567

how can I use this?

David-upTor commented 11 months ago

Same issue , i got this error :

{ "code":"error", "message":"authorization request error", "domain":"EKErrorDomain", "userInfo":{ "NSLocalizedDescription":"-requestAccessToEntityType:completion: has been deprecated-calling this method is no longer allowed. Instead, use -requestFullAccessToEventsWithCompletion:, -requestWriteOnlyAccessToEventsWithCompletion:, or -requestFullAccessToRemindersWithCompletion:." }

voslartomas commented 10 months ago

if the library is not updated until new iOS is released (probably 12th Sept) you can use this commit that fixes calendar and gives full permission on request: andrejguran@f876567

how can I use this?

You should be able to use it like this in your package.json

"react-native-calendar-events": "git://github.com/andrejguran/react-native-calendar-events.git#f8765674d966a623dc99ccab2e263171ff61155e",
ElicaInc commented 10 months ago

if the library is not updated until new iOS is released (probably 12th Sept) you can use this commit that fixes calendar and gives full permission on request: andrejguran@f876567

Thanks!

LaikaTheSpaceDog commented 10 months ago

I've tried implementing this fix, but I'm getting these errors on detox build:


 1 warning generated.
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:99:27: error: use of undeclared identifier 'EKAuthorizationStatusFullAccess'
        return (status == EKAuthorizationStatusFullAccess || status == EKAuthorizationStatusAuthorized);
                          ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:127:17: warning: unused variable 'futureEvents' [-Wunused-variable]
        Boolean futureEvents = [RCTConvert BOOL:options[@"futureEvents"]];
                ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:336:27: warning: incompatible pointer to integer conversion initializing 'EKRecurrenceFrequency' (aka 'enum EKRecurrenceFrequency') with an expression of type 'void *' [-Wint-conversion]
    EKRecurrenceFrequency recurrence = nil;
                          ^            ~~~
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:794:18: error: use of undeclared identifier 'EKAuthorizationStatusFullAccess'
            case EKAuthorizationStatusFullAccess:
                 ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:797:18: error: use of undeclared identifier 'EKAuthorizationStatusWriteOnly'; did you mean 'EKAuthorizationStatusDenied'?
            case EKAuthorizationStatusWriteOnly:
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 EKAuthorizationStatusDenied
In module 'EventKit' imported from /Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:4:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.5.sdk/System/Library/Frameworks/EventKit.framework/Headers/EKTypes.h:27:5: note: 'EKAuthorizationStatusDenied' declared here
    EKAuthorizationStatusDenied,
    ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:797:18: error: duplicate case value 'EKAuthorizationStatusDenied'
            case EKAuthorizationStatusWriteOnly:
                 ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:788:18: note: previous case defined here
            case EKAuthorizationStatusDenied:
                 ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:827:26: error: no visible @interface for 'EKEventStore' declares the selector 'requestFullAccessToEventsWithCompletion:'
        [self.eventStore requestFullAccessToEventsWithCompletion:^(BOOL granted, NSError *error) {
         ~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings and 5 errors generated.
** BUILD FAILED **
yaoyi601131548 commented 8 months ago

Hi, @andrejguran @mysport12 I'm on IOS 17.2 and have done everything you said, but when I call RNCalendarEvents.requestPermissions() I still get “denied”, do you have any other suggestions? Thanks very much.

mysport12 commented 8 months ago

See discussion above. You likely missed adding the new info.plist string for full calendar access.

yaoyi601131548 commented 8 months ago

See discussion above. You likely missed adding the new info.plist string for full calendar access.

@mysport12 I'm so happy that you replied my question. upon closer inspection, i found out that i really didn't add NSCalendarsFullAccessUsageDescription correctly due to the TargetConfig of the project. i have another question here, is this plugin repository no going to be updated anymore ? Thanks !

daxaxelrod commented 7 months ago

I debugged this further, it's a deprecation issue. I logged the error from RNCalendarEvents.m:765 and the error from the callback says the following.

Printing description of ((_NSBPlistMappedString *)0x8d7a9589435cdad2):
-requestAccessToEntityType:completion: has been deprecated-calling this method is no longer allowed. 
Instead, use -requestFullAccessToEventsWithCompletion:, -requestWriteOnlyAccessToEventsWithCompletion:, or -requestFullAccessToRemindersWithCompletion:.

Edit: I edited requestPermissions to the following:

RCT_EXPORT_METHOD(requestPermissions:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{

    if (@available(iOS 17.0, *)) {
        [self.eventStore requestFullAccessToEventsWithCompletion:^(BOOL granted, NSError *error) {
            NSString *status = granted ? @"authorized" : @"denied";
            if (!error) {
                resolve(status);
            } else {
                reject(@"error", @"authorization request error", error);
            }
        }];
    } else {
        [self.eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
            NSString *status = granted ? @"authorized" : @"denied";
            if (!error) {
                resolve(status);
            } else {
                reject(@"error", @"authorization request error", error);
            }
        }];
    }    
}
kalmahik commented 7 months ago

@daxaxelrod thanks dude! It is working well right now👍👏

KTDevelopment commented 7 months ago

@daxaxelrod thanks for the fix.

I opened a pull request to get this fix in the main repo: https://github.com/wmcmahan/react-native-calendar-events/pull/448

OmarUsman777 commented 6 months ago

In my case once the user deny the the permission access, It does not ask for permissions again on respective screen. ios: 16.2 my code

useEffect(() => { if (!selector?.calendarPermission) { calendarPermissions(); } }, [selector?.calendarPermission]);

const calendarPermissions = async () => { try { let requestAccess: any = ''; if (Platform.OS === 'android') { requestAccess = await RNCalendarEvents.requestPermissions(); } else { requestAccess = await RNCalendarEvents.requestPermissions(); } if (requestAccess !== 'authorized') { dispatch(setCalendarPermission(false)); } else { console.log('call the police'); dispatch(setCalendarPermission(true)); } } catch (e) { console.log('e ', e); } };

AEP20 commented 6 months ago

I've tried implementing this fix, but I'm getting these errors on detox build:

 1 warning generated.
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:99:27: error: use of undeclared identifier 'EKAuthorizationStatusFullAccess'
        return (status == EKAuthorizationStatusFullAccess || status == EKAuthorizationStatusAuthorized);
                          ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:127:17: warning: unused variable 'futureEvents' [-Wunused-variable]
        Boolean futureEvents = [RCTConvert BOOL:options[@"futureEvents"]];
                ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:336:27: warning: incompatible pointer to integer conversion initializing 'EKRecurrenceFrequency' (aka 'enum EKRecurrenceFrequency') with an expression of type 'void *' [-Wint-conversion]
    EKRecurrenceFrequency recurrence = nil;
                          ^            ~~~
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:794:18: error: use of undeclared identifier 'EKAuthorizationStatusFullAccess'
            case EKAuthorizationStatusFullAccess:
                 ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:797:18: error: use of undeclared identifier 'EKAuthorizationStatusWriteOnly'; did you mean 'EKAuthorizationStatusDenied'?
            case EKAuthorizationStatusWriteOnly:
                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 EKAuthorizationStatusDenied
In module 'EventKit' imported from /Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:4:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.5.sdk/System/Library/Frameworks/EventKit.framework/Headers/EKTypes.h:27:5: note: 'EKAuthorizationStatusDenied' declared here
    EKAuthorizationStatusDenied,
    ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:797:18: error: duplicate case value 'EKAuthorizationStatusDenied'
            case EKAuthorizationStatusWriteOnly:
                 ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:788:18: note: previous case defined here
            case EKAuthorizationStatusDenied:
                 ^
/Users/runner/actions-runner/_work/my-app/my-app/node_modules/react-native-calendar-events/ios/RNCalendarEvents.m:827:26: error: no visible @interface for 'EKEventStore' declares the selector 'requestFullAccessToEventsWithCompletion:'
        [self.eventStore requestFullAccessToEventsWithCompletion:^(BOOL granted, NSError *error) {
         ~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 warnings and 5 errors generated.
** BUILD FAILED **

hey did you find any solution ?

gkasireddy202 commented 5 months ago

unauthorized to access calendar error using permission: NSCalendarsWriteOnlyAccessUsageDescription and created event with permission: NSCalendarsFullAccessUsageDescription.Do I need a write-only access permission instead of full access for iOS 17?

componentDidMount() { RNCalendarEvents.requestPermissions() .then(res => { alert('Premission Response', res); }) .catch(error => { console.log(error); }); }

wesselvantilburg commented 5 months ago

For our app we only want to request write only access for iOS, but using @daxaxelrod their fix and changing requestFullAccessToEventsWithCompletion to requestWriteOnlyAccessToEventsWithCompletion doesn't let us save events yet. This is due to the boolean returned by isCalendarAccessGranted, this will return false because the event is different if you request write only.

To resolve this we created a separate boolean returning if write only access has been granted and in saveEvents we want to check full access or write only access.

Below isCalendarAccessGranted I added this:

- (BOOL)isCalendarWriteOnlyAccessGranted
{
    EKAuthorizationStatus status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];

    if (@available(iOS 17.0, *)) {
        return status == EKAuthorizationStatusWriteOnly;
    }
    return false;
}

And I edited RCT_EXPORT_METHOD(saveEvent to check if one of these permission is granted:

RCT_EXPORT_METHOD(saveEvent:(NSString *)title
                  settings:(NSDictionary *)settings
                  options:(NSDictionary *)options
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    if (![self isCalendarAccessGranted] && ![self isCalendarWriteOnlyAccessGranted]) {
        reject(@"error", @"unauthorized to access calendar", nil);
        return;
    }

    NSMutableDictionary *details = [NSMutableDictionary dictionaryWithDictionary:settings];
    [details setValue:title forKey:_title];

    __weak RNCalendarEvents *weakSelf = self;
    dispatch_async(serialQueue, ^{
        @try {
            RNCalendarEvents *strongSelf = weakSelf;

            NSDictionary *response = [strongSelf buildAndSaveEvent:details options:options];

            if ([response valueForKey:@"success"] != [NSNull null]) {
                resolve([response valueForKey:@"success"]);
            } else {
                reject(@"error", [response valueForKey:@"error"], nil);
            }
        }
        @catch (NSException *exception) {
            reject(@"error", @"saveEvent error", [self exceptionToError:exception]);
        }
    });
}

And if everything's correct you can write events using Full Access or WriteOnly Access permissions! 🎉 Let me know if I missed something.