Push Notification entitlement not being added via EAS Build

When I use EAS Build and Submit to make a build and submit it to the iOS App Store, I receive the following message from Apple:

ITMS-90078: Missing Push Notification Entitlement - Your app appears to register with the Apple Push Notification service, but the app signature’s entitlements do not include the ‘aps-environment’ entitlement. If your app uses the Apple Push Notification service, make sure your App ID is enabled for Push Notification in the Provisioning Portal, and resubmit after signing your app with a Distribution provisioning profile that includes the ‘aps-environment’ entitlement. Xcode does not automatically copy the aps-environment entitlement from provisioning profiles at build time. This behavior is intentional. To use this entitlement, either enable Push Notifications in the project editor’s Capabilities pane, or manually add the entitlement to your entitlements file.

I verified that Push Notification is turned on and configured in my app’s Identity file, and I can see that EAS Build is logging into my Apple account and going through the capabilities sync process. I deleted my provisioning profile and let EAS re-create it, and I also tried manually using my own provisioning file and disabling capability sync. Nothing worked. I really did try every combination!

In order to see what was going on, I ejected from Expo, built the app directly from Xcode, and submitted. Same exact message from Apple. A clue: when I was uploading the build from Xcode, I noticed that the “aps-environment” entitlement was missing in the app.

Then I manually added the Push Notification capability via Xcode Capabilities page, and this created a new Entitlements file. Once I did that, I was able to successfully submit the build. When I was uploading the build this time, I saw the “aps-environment” entitlement in the app.

As an experiment, I added the ""expo-notifications” plugin to app.json, but the managed workflow still produced a build without the “aps-environment” entitlement.

How can I fix this issue? I miss using managed builds!

We’ve been using EAS for a long time and never had this warning from Apple but it has started popping up in the last few days. Nothing has changed in the Apple Developer account and everything looks like it is correct – we have Push Notifications enabled in the Capabilities of the Identifier (as we always have) and we’ve rebuilt the provisioning profiles to make sure that wasn’t an issue but nothing has helped so far.

It seems to me that the warning from Apple is perhaps something that can be ignored but I’m not completely certain. It would be great to know what’s changed – whether it’s something in EAS or just that Apple have added a new check.

Our app is using the managed workflow and recently migrated from the classic build using EAS on SDK 44 and v0.43.0 of eas-cli.

We’re getting the same experience that every time we submit to Apple the ITMS-90078: Missing Push Notification Entitlement message gets emailed to us. I have checked in Expo and Apple and everything looks as expected. I even tried creating a new Provisioning Profile, but still no luck.

I’ve since tested the build with the warning (via TestFlight) to see if push notifications are actually working using the Expo push notifications tool with no joy.

Can confirm, same issue. We build two different apps with the same codebase (but just different app configs; whitelabel app). The configs are the same (except naming, schemes, etc). For one app we get this “ITMS-90078: Missing Push Notification Entitlement” mail from Apple, but not for the other…

Tried to create a new provisioning profile, Apple push keys, it doesn’t work. SDK 44 and EAS CLI 0.44.0.

This warning from Apple is valid. An app without the aps-environment entitlement will not generate valid device tokens and thus will not receive push notifications.

I noticed this in eas-cli v0.44.0 change logs. Not 100% sure if it might have anything todo with it or not, but thought I would share incase.

This is 100% the issue! Good find @sdelaney. However, as I mentioned, I “installed” expo-notifications (thinking this might be needed) by adding it to plugins section of app.json, and it still did not work. So I need to look through the PR and see what “installed” means.

I am trying this out in app.json:

    "plugins": [
        // ...
      [
        "expo-notifications",
        {
          "mode": "production"
        }
      ]
    ],

I will let you know if It works soon!

I already tried this and it didn’t squash the warning from Apple and push notifications still didn’t work.

Here is the relevant code in the expo-notifications plugin:

export const withNotificationsIOS: ConfigPlugin<NotificationsPluginProps> = (
  config,
  { mode = 'development', sounds = [] }
) => {
  config = withEntitlementsPlist(config, (config) => {
    config.modResults['aps-environment'] = mode;
    return config;
  });
  config = withNotificationSounds(config, { sounds });
  return config;
};

Looks like it is doing the right thing. I am on the latest version (0.14.0). So we need to dig in further to see why notifications plugin is not doing its job.

Worth mentioning: EAS Build always says:

:heavy_check_mark: Push Notifications setup for next: us.nextforce.app

But it is not true! At least not right now.

@zeneducate is correct. Adding the expo-notifications plugin does not add the entitlement. So Expo SDK 44 is truly broken. My guess is that the plugin is not triggering an entitlement file to be created.

I am using app.json. Has anyone tried the expo-notifications plugin in app.config.js?

When I run EXPO_DEBUG=1 expo prebuild, I get an “ios” directory with an {APPNAME}.Entitlements file in it, and in that file is:

<key>aps-environment</key>
<string>production</string>

However, if I open this in Xcode, I do not see the Push Notification capability in the Signing and Capabilities screen. If I manually add the capability, then Xcode asks me to create an entitlements file called {APPNAME}Release.entitlements. And then it works.

So this is the bug: the notifications plugin is adding the capability to the wrong entitlements file.

Actually, the problem is that APPNAME.entitlements is not being added to CODE_SIGN_ENTITLEMENTS in the project file. Here is the relevant code from the Entitlements module:

export function getEntitlementsPath(projectRoot: string): string {
  const paths = Paths.getAllEntitlementsPaths(projectRoot);
  let targetPath: string | null = null;

  /**
   * Add file to pbxproj under CODE_SIGN_ENTITLEMENTS
   */
  const project = getPbxproj(projectRoot);
  const projectName = getProjectName(projectRoot);
  const productName = getProductName(project);

  // Use posix formatted path, even on Windows
  const entitlementsRelativePath = slash(path.join(projectName, `${productName}.entitlements`));
  const entitlementsPath = slash(
    path.normalize(path.join(projectRoot, 'ios', entitlementsRelativePath))
  );

  const pathsToDelete: string[] = [];

  while (paths.length) {
    const last = slash(path.normalize(paths.pop()!));
    if (last !== entitlementsPath) {
      pathsToDelete.push(last);
    } else {
      targetPath = last;
    }
  }

  // Create a new entitlements file
  if (!targetPath) {
    targetPath = entitlementsPath;

    // Use the default template
    let template = ENTITLEMENTS_TEMPLATE;

    // If an old entitlements file exists, copy it's contents into the new file.
    if (pathsToDelete.length) {
      // Get the last entitlements file and use it as the template
      const last = pathsToDelete[pathsToDelete.length - 1]!;
      template = fs.readFileSync(last, 'utf8');
    }

    fs.ensureDirSync(path.dirname(entitlementsPath));
    fs.writeFileSync(entitlementsPath, template);

    Object.entries(project.pbxXCBuildConfigurationSection())
      .filter(isNotComment)
      .filter(isBuildConfig)
      .filter(isNotTestHost)
      .forEach(({ 1: { buildSettings } }: any) => {
        buildSettings.CODE_SIGN_ENTITLEMENTS = entitlementsRelativePath;
      });
    fs.writeFileSync(project.filepath, project.writeSync());
  }

  // Clean up others
  deleteEntitlementsFiles(pathsToDelete);

  return entitlementsPath;
}

Nice detective work! Perhaps we should open an issue on GitHub?

Please do!

I am digging deeper, and it turns out that the CODE_SIGN_ENTITLEMENTS is actually set correctly. However the entitlements file is not added to the Xcode project. When I try to add it and try to view it, I get an error: “Failed to open property list: Found non-key inside at line 16”.

Here is what the file looks like:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>aps-environment</key>
    <string>production</string>
    ...
    <key>com.apple.developer.icloud-container-environment</key>
    <key>com.apple.developer.icloud-container-identifiers</key>
    ...
  </dict>
</plist>

Note that the com.apple.developer.icloud-container-environment key has no associated value. If I add a dummy value for this key, suddenly Xcode can see the push notification capability. So the real bug is that the entitilements file is malformed.

If I remove "usesIcloudStorage": true from app.json, suddenly the entitlements file is valid again. I am trying a build like this now to see if push notifications capability works again. Is everyone in this thread using iCloud storage?