How do I enable Remote Push Notification Capability using Unity Cloud Build?

Hi, I’ve been struggling on and off for a few weeks now to get Push Notifications working for my Unity Game.
I always get the following message when trying to submit my IPA file.

I think the issues is I need to enable Capabilities>Background Modes>Remote Notifications.

And I’ve tried doing this by adding the following into the info.plist. Which appears to not do anything

                <key>UIBackgroundModes</key>
                <array>
                    <string>remote-notification</string>
                </array>

The thing is, I’m using Unity Cloud Build for everything and have no-idea how this is meant to work for that. I’ve done extensive Googling and cannot come up with ANYTHING. It’s really surprising me that in my search no-one has come up against this issue… I really need help…

Thanks in advance!

2 Likes

Bump :slight_smile:

Having similar problem but with iCloud. Suspect whatever solution you get will also help with mine

Got push notifications to work in UCB via this post might help with other capabilities

3 Likes

YEP! THAT WORKED!
I skipped the part about XCode and creating an entitlements file. I just put the contents of my “AppName.Entitlements” file as

<?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>
  </dict>
</plist>

Pointed the .UnityPackage at the file, commited to Unity Cloud Build and after uploading to Apple, voila! It worked!

2 Likes

This is how you can add background-modes through post-process-build script:

PBXProject proj = new PBXProject();
string projPath = PBXProject.GetPBXProjectPath(buildPath);
proj.ReadFromFile(projPath);

string targetName = PBXProject.GetUnityTargetName();
string mainTarget = proj.TargetGuidByName(targetName);

// Enable background mode
proj.AddCapability(mainTarget, PBXCapabilityType.BackgroundModes);

proj.WriteToFile(projPath);
File.WriteAllText(projPath, proj.WriteToString());

// Add background modes
string plistPath = buildPath + "/Info.plist";
PlistDocument plist = new PlistDocument();
plist.ReadFromString(File.ReadAllText(plistPath));
PlistElementDict rootDict = plist.root;
PlistElementArray arr = rootDict.CreateArray("UIBackgroundModes");
arr.AddString("remote-notification");
arr.AddString("fetch");
File.WriteAllText(plistPath, plist.WriteToString());
2 Likes

Just don’t forget :
Push notification entitile value is choosen from Xcode - when in simple test build it will give you either development or production value!
Also, don’t forget to check if the frameworks are linked! (Xcode API is old so it does’nt know about new Xcode!)

We are using a third party Scalefusion iOS MDM for remote push notification.

If anyone already uses ProjectCapabilityManager, one can simply add these lines:

var capManager = new ProjectCapabilityManager(projPath, entitlementsPath, "Unity-iPhone");
capManager.AddBackgroundModes(BackgroundModesOptions.BackgroundFetch);    capManager.AddBackgroundModes(BackgroundModesOptions.RemoteNotifications);
capManager.WriteToFile();
2 Likes

Where did you get the entitlementsPath? did you need to create an empty file?

var entitlementsFileName = pbxProject.GetBuildPropertyForAnyConfig(mainTarget, “CODE_SIGN_ENTITLEMENTS”) ?? Application.identifier + “.entitlements”;

var capManager = new ProjectCapabilityManager(projPath, entitlementsFileName, “Unity-iPhone”);

1 Like

Time for another update to this thread, with a few pointers that might help people that are in the same situation I was.

The previous comments on this thread are very good, but deprecated methods and specific circumstances weren’t allowing them to get the job done that I needed.

Deprecated methods
You’ll see in my solution that there is a new way of getting the GUID that you’ll need. I actually could not find a way of getting the target name by method (“Unity-iPhone” by default I believe) as the old one is deprecated and throws an error if you try to use it. My project is using the default, so unless you have explicitly changed yours somehow then this should work just fine.

Plugin also accessing entitlements
Even after fixing all errors and doing my best to get the naming conventions correct, I still wasn’t seeing the right entitlements added. Turns out one of the SDK’s I added to my project was also accessing the entitlements file, and for some reason their method was setting the name of my entitlements file (sorry, didn’t find out why this is or if I could stop it). Fortunately I was able to edit their scripts and explicitly set the name of the entitlements file in both theirs and my scripts.

Good knowledge to have
For your enrichment, it seems there might be two ways of fixing this error. Some here appear to be fixing it by adding remote notifications. At one point, when I tried adding remote notifications I got an error that it was already there. Yet I was still getting the same error as the OP. What I needed was to have the Push Notifications capability added. To do this, you need to have the “aps-environment” key added to the entitlements file, with either the “production” or “development” value. This is what is happening in the capManager.AddPushNotifications() method (True for development. Haven’t yet learned the full implications of true or false yet).

For newbies
If you’re really new to this concept, it might be helpful to know that any method with the [PostProcessBuild] attribute will run after the build, so you can put this function anywhere you like.

[PostProcessBuild]
    public static void AddToEntitlements(BuildTarget buildTarget, string buildPath)
    {

        if (buildTarget != BuildTarget.iOS) return;

        // get project info
        string pbxPath = PBXProject.GetPBXProjectPath(buildPath);
        var proj = new PBXProject();
        proj.ReadFromFile(pbxPath);
        var guid = proj.GetUnityMainTargetGuid();

        // get entitlements path
        string[] idArray = Application.identifier.Split('.');
        var entitlementsPath = $"Unity-iPhone/{idArray[idArray.Length - 1]}.entitlements";

        // create capabilities manager
        var capManager = new ProjectCapabilityManager(pbxPath, entitlementsPath, null, guid);

        // Add necessary capabilities
        capManager.AddPushNotifications(true);

        // Write to file
        capManager.WriteToFile();
    }
9 Likes

Not sure if this is going to work on UCB, since I haven’t tested on this platform, but I recently wanted to add the Push Notifications capability automatically (so I didn’t need to edit anything in Xcode) and I had many problems. I’m just going to show the code that finally worked for me, which doesn’t require using the ProjectCapabilityManager.

Just change {your-game-name} with the name of your game as it appears on Player Settings. Also, this will only work if you don’t have any other entitlements file, since I hardcode the entitlements file contents in a string. I’m using Unity 2019.4.28 and Xcode 12.5:

[PostProcessBuild()]
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
{       
        if (target != BuildTarget.iOS)
            return;

        string projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
        PBXProject proj = new PBXProject();
        proj.ReadFromString(File.ReadAllText(projPath));

        MyLogger.Debug("Adding Push Notifications capability");
        AddPushNotificationCapability(pathToBuiltProject, proj);

        proj.WriteToFile(projPath);
}

private static void AddPushNotificationCapability(string buildPath, PBXProject proj)
{
        string entitlementsPath = AddEntitlementsFile(buildPath, proj);
        proj.AddCapability(proj.GetUnityMainTargetGuid(), PBXCapabilityType.PushNotifications, entitlementsPath);  
}

private static string AddEntitlementsFile(string buildPath, PBXProject proj)
{
        const string contents = @"<?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>development</string>
    </dict>
    </plist>";

        string entitlementsPath = $"{buildPath}/Unity-iPhone/{your-game-name}.entitlements";

        File.WriteAllText(entitlementsPath, contents);
        return entitlementsPath;
}
 private static void AddPushNotificationCapabilities(string path)
    {
        Debug.Log("ProcessPostBuild - iOS - Adding Push Notification capabilities.");

        // get XCode project path
        string pbxPath = PBXProject.GetPBXProjectPath(path);

        // Add linked frameworks
        PBXProject pbxProject = new PBXProject();
        pbxProject.ReadFromString(File.ReadAllText(pbxPath));
        string targetName = pbxProject.TargetGuidByName(PBXProject.GetUnityTestTargetName());
        string targetGUID = pbxProject.GetUnityMainTargetGuid();
        pbxProject.AddFrameworkToProject(targetGUID, "UserNotifications.framework", false);
        File.WriteAllText(pbxPath, pbxProject.WriteToString());

        // Add required capabilities: Push Notifications, and Remote Notifications in Background Modes
        var isDevelopment = Debug.isDebugBuild;
        var capabilities = new ProjectCapabilityManager(pbxPath, "app.entitlements", "Unity-iPhone");
        capabilities.AddPushNotifications(isDevelopment);
        capabilities.AddBackgroundModes(BackgroundModesOptions.RemoteNotifications);
        capabilities.WriteToFile();
    }

Mine is like this and it’s working :