Search Unity

Push Notifications on iOS with Cloud Build?

Discussion in 'Unity Build Automation' started by SniperED007, May 14, 2019.

  1. SniperED007

    SniperED007

    Joined:
    Sep 29, 2013
    Posts:
    345
    Do push notifications work with Cloud Build, or is there something you have to setup specifically so that it will work with iOS?

    With Xcode you need to do this:
    • Scroll down to Linked Frameworks and Libraries and click the + button to add a framework.
      • In the window that appears, scroll to UserNotifications.framework and click on that entry, then click on Add.
    • Select the Capabilities tab from the Editor area.
    • Switch Push Notifications to On.
    How do I do this in Cloud Build and is it required or does Cloud Build auto handle this?
    I'm using Firebase Messaging.
     
    Last edited: May 14, 2019
  2. henriqueranj

    henriqueranj

    Joined:
    Feb 18, 2016
    Posts:
    177
    Hello @SniperED007 ,

    You can use a PostProcessBuild Script to manipulate the resulting XCode via code to add the necessary Capabilities for Push Notifications.

    There are several examples online if you search for it. The PostProcessScript should do the following steps: https://firebase.google.com/docs/cloud-messaging/unity/client#add_user_notifications

    Hereby follows the one I implemented:

    Code (CSharp):
    1. public static class PushNotificationsPostBuildScript {
    2.     [PostProcessBuild(100)]
    3.     public static void OnPostprocessBuild(BuildTarget buildTarget, string path) {    
    4.        // Only perform these steps for iOS builds
    5.       if (buildTarget == BuildTarget.iOS) {
    6.         ProcessPostBuildIOS(buildTarget, path);
    7.       }
    8.     }
    9.  
    10.     private static void ProcessPostBuildIOS(BuildTarget buildTarget, string path) {
    11.  
    12.       Debug.Log("[PushNotificationsPostBuildScript] ProcessPostBuild - iOS - Adding Push Notification capabilities.");
    13.  
    14.       // get XCode project path
    15.       string pbxPath = PBXProject.GetPBXProjectPath(path);
    16.  
    17.       // Add linked frameworks
    18.       PBXProject pbxProject = new PBXProject();
    19.       pbxProject.ReadFromString(File.ReadAllText(pbxPath));
    20.       string targetName = PBXProject.GetUnityTargetName();
    21.       string targetGUID = pbxProject.TargetGuidByName(targetName);
    22.       pbxProject.AddFrameworkToProject(targetGUID, "UserNotifications.framework", false);
    23.       File.WriteAllText(pbxPath, pbxProject.WriteToString());
    24.  
    25.       // Add required capabilities: Push Notifications, and Remote Notifications in Background Modes
    26.       var isDevelopment = Debug.isDebugBuild;
    27.       var capabilities = new ProjectCapabilityManager(pbxPath, "app.entitlements", "Unity-iPhone");
    28.       capabilities.AddPushNotifications(isDevelopment);
    29.       capabilities.AddBackgroundModes(BackgroundModesOptions.RemoteNotifications);
    30.       capabilities.WriteToFile();
    31.     }
    32.   }
     
  3. wowcrazyguy

    wowcrazyguy

    Joined:
    Sep 24, 2018
    Posts:
    49
    Can you help me with the latest solution. I've tried 20 different solutions using postProcess to enable push notification but still with no luck.
     
  4. SniperED007

    SniperED007

    Joined:
    Sep 29, 2013
    Posts:
    345
    Code (CSharp):
    1. #if APPLE
    2. using UnityEngine;
    3. using UnityEditor;
    4. using UnityEditor.Callbacks;
    5. using UnityEditor.iOS.Xcode;
    6.  
    7. public class EntitlementsPostProcess : ScriptableObject
    8. {
    9.     public DefaultAsset m_entitlementsFile;
    10.  
    11.     [PostProcessBuild]
    12.     public static void OnPostProcess(BuildTarget buildTarget, string buildPath)
    13.     {
    14.         if (buildTarget != BuildTarget.iOS)
    15.             return;
    16.  
    17.         var dummy = CreateInstance<EntitlementsPostProcess>();
    18.         var file = dummy.m_entitlementsFile;
    19.         DestroyImmediate(dummy);
    20.         if (file == null)
    21.             return;
    22.              
    23.         var proj_path = PBXProject.GetPBXProjectPath(buildPath);
    24.         var proj = new PBXProject();
    25.  
    26.         var unityFrameworkGUID = proj.GetUnityFrameworkTargetGuid();
    27.  
    28.         proj.ReadFromFile(proj_path);      
    29.         var target_name = proj.GetUnityMainTargetGuid();
    30.  
    31.         // NEW
    32.         //Set the entitlements file name to what you want but make sure it has this extension
    33.         string entitlementsFileName = "my_app.entitlements";
    34.  
    35.         var entitlements = new ProjectCapabilityManager(proj_path, entitlementsFileName, "Unity-iPhone", target_name);            
    36. entitlements.AddPushNotifications(true);
    37.      
    38.         //Apply
    39.         entitlements.WriteToFile();
    40.     }
    41. }
    42. #endif
    Try this, I removed a few things that I don't think you need but hopefully should work.
     
    raraco likes this.
  5. wowcrazyguy

    wowcrazyguy

    Joined:
    Sep 24, 2018
    Posts:
    49
    Thank you for the solution, I suppose it should work because I see the entitlement finally set into production automatically and so does the background, push notification enabled in xcode automatically, but still when I try to send cloud messaging from firebase. My app just don't receive it. I'm sure my firebase script and setting are correct since I can receive it on android.

    What might be the problem. Is it because I run the app through test flight mode.
     
  6. SniperED007

    SniperED007

    Joined:
    Sep 29, 2013
    Posts:
    345
    No, nothing to do with test flight, it will work even on a unity cloud build without test flight etc. Check your iOS settings on Firebase.
     
  7. wowcrazyguy

    wowcrazyguy

    Joined:
    Sep 24, 2018
    Posts:
    49
    Thanks, wow didn't know to set cloud messaging for iOS is this complicated. Gatta need some times to study into it.
     
  8. wowcrazyguy

    wowcrazyguy

    Joined:
    Sep 24, 2018
    Posts:
    49
    So I have followed the steps to upload my APN to firebase but still can't get things going. I've checked my APN, package ID, App store ID, and team ID. All four sees correct.

    The only thing I haven't done is to configure the push notification under app id configuration because I realize to use keychain generating certificate is an old method (it eventually cannot export to p8 file).

    What possibly am I still missing here.
     
  9. wowcrazyguy

    wowcrazyguy

    Joined:
    Sep 24, 2018
    Posts:
    49
    SniperED007 :

    Thanks! It finally gets to work after 24 hours of uploading my APN (cloud messaging won't start right away after uploaded). Thank you again, I've been working on this for two weeks.
     
    SniperED007 likes this.
  10. d_sharov

    d_sharov

    Joined:
    Dec 24, 2021
    Posts:
    23
    We have a big problem with notifications and UCB.
    For the third day I have been trying any options, but the cloud build refuses to assemble.
    Unity version: 2022.2.14f
    xcode version: 14.1
    Mobile Provision was recreated after the push certificate was added.
    True, in the mobile itself there is nothing about the notification service. Is this correct?


    error from cloud
    [error] 7.3.5.2.7.4 - INFO: ▸ /BUILD_PATH/Unity-iPhone.xcodeproj: error: Provisioning profile has app ID "com.redrift.StorySpark", which does not match the bundle ID "com.redrift.StorySpark.notificationservice". (in target 'notificationservice' from project 'Unity-iPhone')

    Here is the postbuild processing code we are using.


    Code (CSharp):
    1. [PostProcessBuild(1)]
    2.         public static void OnPostProcessBuild(BuildTarget target, string path)
    3.         {
    4.             try
    5.             {
    6.                 if (target != BuildTarget.iOS)
    7.                     return;
    8.  
    9.                 Debug.Log($"{nameof(SignInWithApplePostprocessor)} Start Post Process Build");
    10.  
    11.                 var projectPath = PBXProject.GetPBXProjectPath(path);
    12.                 var project = new PBXProject();
    13.                 project.ReadFromString(File.ReadAllText(projectPath));
    14.                 var projectCapabilityManager = new ProjectCapabilityManager(projectPath,
    15.                     "Entitlements.entitlements",
    16.                     null,
    17.                     project.GetUnityMainTargetGuid());
    18.                 projectCapabilityManager.AddSignInWithAppleWithCompatibility(project.GetUnityFrameworkTargetGuid());
    19.                 projectCapabilityManager.AddPushNotifications(true);
    20.                 projectCapabilityManager.WriteToFile();
    21.                 Debug.Log(
    22.                     $"{nameof(SignInWithApplePostprocessor)} End success Post Process Build. Entitlements: {string.Join(";", projectCapabilityManager.Entitlements.root.values.Select(x => x.Key))}");
    23.             }
    24.             catch (Exception e)
    25.             {
    26.                 Debug.LogError(
    27.                     $"{nameof(SignInWithApplePostprocessor)} End failed Post Process Build. Message: {e.Message}");
    28.                 Debug.LogException(e);
    29.                 throw;
    30.             }
    31.         }

    Code (CSharp):
    1. private static readonly string SwiftStandardLibraries = "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES";
    2.         private static readonly string BitCode = "ENABLE_BITCODE";
    3.         private static readonly string AlwaysSearchUserPaths = "ALWAYS_SEARCH_USER_PATHS";
    4.         private static readonly string UseHeadermap = "USE_HEADERMAP";
    5.         private static readonly string Notificationservice = "notificationservice";
    6.         private static readonly string No = nameof(No).ToUpper();
    7.         private static readonly string Yes = nameof(Yes).ToUpper();
    8.  
    9.         [PostProcessBuild(999)]
    10.         public static void OnPostProcessBuild(BuildTarget target, string path)
    11.         {
    12.             if (target != BuildTarget.iOS)
    13.                 return;
    14.  
    15.             try
    16.             {
    17.                 Debug.Log($"{nameof(ModifyFrameworksPostProcess)} Start Post Process Build");
    18.                 var projPath = PBXProject.GetPBXProjectPath(path);
    19.                 Debug.Log($"{nameof(projPath)}: {projPath}");
    20.  
    21.                 var project = new PBXProject();
    22.                 project.ReadFromFile(projPath);
    23.  
    24.                 Debug.Log($"{nameof(ModifyFrameworksPostProcess)} Project successfully initialized");
    25.  
    26.                 project.DisableSwiftStandardLibraries();
    27.                 project.EnableSwiftStandardLibraries();
    28.                 project.DisableBitcode();
    29.                 project.DisableHeaderMap();
    30.                 project.WriteToFile(projPath);
    31.  
    32.                 Debug.Log($"{nameof(ModifyFrameworksPostProcess)} End success Post Process Build");
    33.             }
    34.             catch (Exception e)
    35.             {
    36.                 Debug.LogError(
    37.                     $"{nameof(ModifyFrameworksPostProcess)} End failed Post Process Build. Message: {e.Message}");
    38.                 Debug.LogException(e);
    39.                 throw;
    40.             }
    41.         }
    42. private static PBXProject DisableHeaderMap(this PBXProject project)
    43.         {
    44.             var notificationserviceGuid = project.TargetGuidByName(Notificationservice);
    45.             project.SafeSetBuildProperty(notificationserviceGuid, AlwaysSearchUserPaths, No);
    46.             project.SafeSetBuildProperty(notificationserviceGuid, UseHeadermap, No);
    47.  
    48.             Debug.Log($"{nameof(ModifyFrameworksPostProcess)} {nameof(DisableHeaderMap)} end");
    49.             return project;
    50.         }
    I omitted some methods, they do not apply to the work of other SDKs
    I would be grateful if you give me more options. Or at least point to the cause of the problem
     
  11. qball13z

    qball13z

    Joined:
    Nov 30, 2013
    Posts:
    15
    I'm running into this issue today, wondering if you found a resolution?
     
  12. d_sharov

    d_sharov

    Joined:
    Dec 24, 2021
    Posts:
    23
    No. We tried different options.
    Also tried to switch to the OneSignal.
    Together with OneSiganl support, we came to the conclusion that Unity Cloud does not support building projects with push notifications.

    Because for correct operation, it is required to use extensions that the cloud assembly cannot correctly sign
     
  13. israel_nftgco

    israel_nftgco

    Joined:
    Apr 27, 2023
    Posts:
    6
    We workedaround the issue of ".notificationservices" suffix being added to the appid by writting this post processing script:

    Code (CSharp):
    1. internal static class IOSRichPushNotificationPostProcess2
    2.     {
    3.         [PostProcessBuild(2)]
    4.         public static void ConfigureRichPushNotificationTarget(BuildTarget buildTarget, string buildOutputPath)
    5.         {
    6.             if (buildTarget != BuildTarget.iOS)
    7.             {
    8.                 return;
    9.             }
    10.  
    11.             var xcodeProjectPath = PBXProject.GetPBXProjectPath(buildOutputPath);
    12.             var project = new PBXProject();
    13.             project.ReadFromFile(xcodeProjectPath);
    14.  
    15.             var displayName = "notificationservice";
    16.            
    17.             var notificationserviceGuid = project.TargetGuidByName(displayName);
    18.  
    19.             var pathToNotificationServiceImplementation = Path.Combine(buildOutputPath, displayName);
    20.  
    21.             var pathToNotificationServicePlist = Path.Combine(pathToNotificationServiceImplementation, "Info.plist");
    22.             var notificationServicePlist = new PlistDocument();
    23.             notificationServicePlist.ReadFromFile(pathToNotificationServicePlist);
    24.             notificationServicePlist.root.SetString("CFBundleIdentifier", "$(PRODUCT_BUNDLE_IDENTIFIER)");
    25.             notificationServicePlist.WriteToFile(pathToNotificationServicePlist);
    26.  
    27.             project.SetBuildProperty(notificationserviceGuid, "PRODUCT_BUNDLE_IDENTIFIER", Application.identifier);
    28.  
    29.             project.WriteToFile(xcodeProjectPath);
    30.         }
    31.     }
     
  14. israel_nftgco

    israel_nftgco

    Joined:
    Apr 27, 2023
    Posts:
    6
    Forget it, this prevents installing it to a device.

    So we opted to remove push notifications from ios builds:
    Code (CSharp):
    1. internal class RemovePushNotifications : IPreprocessBuildWithReport
    2.     {
    3.         public int callbackOrder => -10000;
    4.         public void OnPreprocessBuild(BuildReport report)
    5.         {
    6.             if (report.summary.platform != BuildTarget.iOS) return;
    7.  
    8.             var request = UnityEditor.PackageManager.Client.Remove("com.unity.services.push-notifications");
    9.             while (!request.IsCompleted)
    10.             {
    11.                 AssetDatabase.Refresh();
    12.             }
    13.         }
    14.     }