react-native-calendar-events icon indicating copy to clipboard operation
react-native-calendar-events copied to clipboard

iOS 17 issues: unable to request permissions

Open RhysTowey opened this issue 10 months ago β€’ 26 comments

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

RhysTowey avatar Aug 31 '23 11:08 RhysTowey

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

andrejguran avatar Sep 07 '23 12:09 andrejguran

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!

RhysTowey avatar Sep 08 '23 13:09 RhysTowey

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

taschik avatar Sep 12 '23 22:09 taschik

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

RhysTowey avatar Sep 13 '23 15:09 RhysTowey

@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.

andrejguran avatar Sep 15 '23 09:09 andrejguran

@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

mysport12 avatar Sep 22 '23 16:09 mysport12

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?

jakehasler avatar Oct 09 '23 21:10 jakehasler

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

mysport12 avatar Oct 10 '23 02:10 mysport12

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

jakehasler avatar Oct 10 '23 03:10 jakehasler

Appreciate if a new version can be released with the fix

malwatte avatar Oct 16 '23 07:10 malwatte

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

ziarno avatar Oct 18 '23 10:10 ziarno

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?

ziarno avatar Oct 19 '23 08:10 ziarno

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:." }

David-upTor avatar Oct 20 '23 17:10 David-upTor

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",

voslartomas avatar Oct 24 '23 16:10 voslartomas

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!

ElicaInc avatar Nov 01 '23 06:11 ElicaInc

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 **

LaikaTheSpaceDog avatar Nov 17 '23 09:11 LaikaTheSpaceDog

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.

yaoyi601131548 avatar Jan 12 '24 07:01 yaoyi601131548

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

mysport12 avatar Jan 12 '24 16:01 mysport12

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 !

yaoyi601131548 avatar Jan 13 '24 02:01 yaoyi601131548

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);
            }
        }];
    }    
}

daxaxelrod avatar Feb 01 '24 19:02 daxaxelrod

@daxaxelrod thanks dude! It is working well right nowπŸ‘πŸ‘

kalmahik avatar Feb 06 '24 13:02 kalmahik

@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

KTDevelopment avatar Feb 06 '24 14:02 KTDevelopment

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); } };

OmarUsman777 avatar Feb 29 '24 12:02 OmarUsman777

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 ?

AEP20 avatar Mar 12 '24 19:03 AEP20

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); }); }

gkasireddy202 avatar Mar 28 '24 06:03 gkasireddy202

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.

wesselvantilburg avatar Apr 08 '24 12:04 wesselvantilburg