Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS 17 issues: unable to request permissions #440

Open
RhysTowey opened this issue Aug 31, 2023 · 27 comments
Open

iOS 17 issues: unable to request permissions #440

RhysTowey opened this issue Aug 31, 2023 · 27 comments

Comments

@RhysTowey
Copy link

RhysTowey commented Aug 31, 2023

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
Copy link

andrejguran commented Sep 7, 2023

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

@RhysTowey
Copy link
Author

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 RhysTowey reopened this Sep 8, 2023
@taschik
Copy link

taschik commented Sep 12, 2023

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

@RhysTowey
Copy link
Author

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

@andrejguran
Copy link

@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
Copy link

mysport12 commented Sep 22, 2023

@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
Copy link

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
Copy link

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

@jakehasler
Copy link

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
Copy link

Appreciate if a new version can be released with the fix

@ziarno
Copy link

ziarno commented Oct 18, 2023

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

@ziarno
Copy link

ziarno commented Oct 19, 2023

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
Copy link

David-upTor commented Oct 20, 2023

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
Copy link

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
Copy link

ElicaInc commented Nov 1, 2023

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
Copy link

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
Copy link

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
Copy link

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

@yaoyi601131548
Copy link

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
Copy link

daxaxelrod commented Feb 1, 2024

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
Copy link

kalmahik commented Feb 6, 2024

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

@KTDevelopment
Copy link

@daxaxelrod thanks for the fix.

I opened a pull request to get this fix in the main repo:
#448

@OmarUsman777
Copy link

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
Copy link

AEP20 commented Mar 12, 2024

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
Copy link

gkasireddy202 commented Mar 28, 2024

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
Copy link

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.

@ng-cen
Copy link

ng-cen commented Nov 8, 2024

@voslartomas thanks, with your commit, i got it works very good. this is the code snippet:

// ios/myProjectName/Info.plist

<key>NSCalendarsFullAccessUsageDescription</key>
<string>APP requires access to the calendar</string>

// tsx code
IMPORTANT NOTE: first need to call RNCalendarEvents.requestPermissions()

  const handleClick = useCallback(() => {
    RNCalendarEvents.requestPermissions().then(
      (result) => {
        Alert.alert('Auth requested', result);
        createEvent();
      },
      (result) => {
        console.error(result);
      },
    );
}, [])

const createEvent = async () => {
    const eventDetails = {
      title: 'New Event',
      startDate: new Date().toISOString(), // Start date
      endDate: new Date(new Date().getTime() + 60 * 60 * 1000).toISOString(), // End date (1 hour later)
      description: 'This is a test event',
      location: 'Somewhere',
    };

    // Check for existing events
    const events = await RNCalendarEvents.fetchAllEvents(eventDetails.startDate, eventDetails.endDate);
    const isDuplicate = events.some((event) => event.title === eventDetails.title);

    if (isDuplicate) {
      Alert.alert('Duplicate Event', 'This event already exists in your calendar.');
      return;
    }

    // Save the new event
    RNCalendarEvents.saveEvent(eventDetails.title, eventDetails)
      .then((id) => {
        console.log(`Event created with ID: ${id}`);
        Alert.alert('Success', 'Event created successfully!');
      })
      .catch((error) => {
        console.error('Error creating event:', error);
        Alert.alert('Error', 'Failed to create event.');
      });
  };
`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests