Expo 29.0 on iOS is no longer resolving Permissions.askAsync promise for NOTIFICATIONS

In Expo 29.0 SDK it appears that the NOTIFICATIONS permission does not resolve when requesting Permissions.askAsync(Permissions.NOTIFICATIONS). It is working properly in 28.0.1. Not sure if this effects other permissions as well.

I tried to make a Snack for it, but the 29 SDK was not running for iOS or Android.

The promise did not resolve if I accepted or rejected the permissions. This was through the Expo application if that helps. Also, this issue only occurred when showing the operating system dialog and selecting a response; after that subsequent attempts to call askAsync resolved successfully or failed depending on what choice was made.

I also did not notice an issue with the Permissions.getAsync call.

1 Like

same here, since Expo 29.0, I’ve noticed the same behaviour as described.

it is only in expo ios and ios standalone app, while in android standalone app it never happened since permissions already given as the app being installed.

1 Like

A fix was recently landed, which should fix this Permissions issue.
cc: @tsapeta @sjchmiela

1 Like

On Ios, Using all pods Its asking Permissions ok (Detached App)
On Android, i’m experiencing the same issue.

Hi all!

When it comes to permissions on iOS (Expo Client) we are aware of an issue resulting in the permissions being handled improperly, we’re tracking the issue in https://github.com/expo/expo/issues/2042.

Regarding Android, I’ve just tried running

Permissions.askAsync(Permissions.NOTIFICATIONS).then(console.log).catch(console.warn);

in a detached application on SDK 29 and it logged { expires: never, status: granted } properly.

Could you please provide more information on the environment in which you’re experiencing the error?

1 Like

Hi,

@quinlanj said:

A fix was recently landed

How do I get it? Is it enough to re-install the SDK with npm install?

In addition to iOS bug reported above I had similar problem with FileSystem.downloadAsync. Perhaps it’s related. I’ve reported it here: https://github.com/facebook/react-native/issues/20364

I’m also experiencing this issue.

const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);

The above code never resolves in a stand alone iOS app - any update on this fix?

1 Like

I think the problem is here:

the resolver is never called when strongSelf is false

1 Like

Same here on SKD29, the following line wait forever when I force the disabling of notifications from settings.

const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);

The previous scenario works as expect on SKD28

I am also having the same issue on a recent upgrade to sdk 29

if (existingStatus !== 'granted') {
      Alert.alert(`we've asked for permission because status is ${finalStatus}`)
      this.events.sendNotificationsAsked()
      // Android remote notification permissions are granted during the app
      // install, so this will only ask on iOS
      const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
      finalStatus = status;
      Alert.alert(`we've asked for permission and received ${finalStatus}`)
    }

on devices through testflight it will not resolve await Permissions.askAsync(Permissions.NOTIFICATIONS)
I will get the first alert but not the second.
on simulator through expo it will resolve as undetermined (as it always has)

this is a new issue with sdk 29

As a note, I am getting asked for permissions on ios, but it never resolved - haven’t tested android.

Another note, I have not detached which i can see is not supported at the moment from github issues. I am using a standard standalone app

1 Like

+1
I’m Having the same problem! Pod 2.7.0

[Updated]
I Updated to Pod 2.7.4, I Will Test to know it’s working now!

After further testing, it works when you call getAsync on next run. So something is causing the issue on first call askAsync.

Like OP stated

1 Like

We’re having exactly the same issue.

  if (existingStatus !== 'granted') {
    // Android remote notification permissions are granted during the app
    // install, so this will only ask on iOS
    const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
    finalStatus = status;
    Expo.Segment.trackWithProperties('push.notifications.final.status', {
      status
    });
  }

We call this after the user logs into our app but we never get the status and the Segment event is never sent.

We’re on 29.0.0 and this is causing a rejection from the App Store. Has anyone fixed this? Does it work if we downgrade to 28?

EDIT:

This is not a detached app. Just a regular standalone expo app.

Same with me on the rejection from app store, they didn’t like you have to click continue twice (so it gets picked up on getAsync :slight_smile: )

Devs haven’t chimed in here or github so no eta.

I was thinking of using timers but seems to janky for me.

Hi all!

My sincere apologies it took us so long to fix that bug. :disappointed: The fix is waiting for review and we’ll push it to Turtle builders ASAP so you can rebuild your iOS apps to see the bug fixed.

Let me at least explain what was the problem. :slightly_smiling_face:

Let’s start with what’s included in every Expo Client or a standalone app at the moment:

  • an unversioned core, containing Kernel (services helping all the experiences access some specific devices’ APIs, like permissions or sensors manager) and ExpoKit, a central dispatch station for all the events that should be passed to different experiences (that is different applications running on Expo Client, eg.)
  • an unversioned SDK
  • a couple of versioned SDKs included in the runtime as pods (see eg. Podfile section for SDK29).

To be able to compile different versions of the SDK in one project, when a new SDK is released, we prefix files/classes/constants names with ABI_SDK_VERSION, eg. ABI_29_0_0. This way the compiler doesn’t complain about duplicate symbols and what not.

However, there are some constants values that shouldn’t change from version to version — they should be shared for all SDKs. An example of such constant would be EXAppDidRegisterForRemoteNotificationsNotification.

This is the name of the notification that is posted by ExpoKit on NSNotificationCenter when - application:didRegisterForRemoteNotificationsWithDeviceToken: is called on AppDelegate, so all interested parties (in that case all remote notification permissions managers) know that the user allowed the app to receive remote notifications.

The way we ensured that this constant will be left as it is by the versioning script was an EX_UNVERSIONED macro which did… nothing. See definition, usage example and versioned example.

The problem that caused this bug is that when moving Permissions API to a universal module we forgot about versioning that happens automatically when we release a new SDK version. In SDK 29’s expo-permissions module, EXAppDidRegister… was prefixed with ABI29_0_0 so Permissions was listening on NSNotificationCenter for ABI29_0_0EXAppDidRegister… which was posted there.

The solution was to ensure that the names match in every SDK version. To ensure this doesn’t happen in the future I’ve added k before EXAppDidRegisterForRemoteNotificationsNotification in all versioned and unversioned code. The versioning script won’t bother us anymore!

Sorry for the problems, everyone! I’ll let you know when we release the fix to the builders. :slight_smile:

5 Likes

Hey, thanks for the quick response and for the detailed explanation of the issue :smiley:

Due to the complexity of our login process (and the lack of detailed feedback from Apple) it took us some time to figure out what was happening so it’s actually really nice to know the root cause of this thing that has been causing us so many headaches haha.

Keep up the good work, guys!

New version of SDK for iOS builders has just been deployed (https://github.com/expo/expo/issues/663#issuecomment-416148660), new version of Expo Client (2.7.5) is propagating now across App Store, the issue should be fixed! :slightly_smiling_face:

2 Likes

I can confirm the bug is fixed now :partying_face:

3 Likes

This bug still isn’t fixed as of 2.7.6. Is there work ongoing to fix it?

1 Like

I’m still seeing this issue too on an app built via build:ios today - is there a workaround?