Search Unity

Android Cloud Build not honouring custom define

Discussion in 'Unity Build Automation' started by PeachyPixels, May 24, 2021.

  1. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    Hello Everyone!

    I'm using a custom conditional define (LOGGING_ENABLED) to enable logging within my game. The logging methods are decorated with the corresponding conditional attribute, like so...

    Code (CSharp):
    1. [Conditional("LOGGING_ENABLED")]
    2. public static void LogInfo(string message)
    3. {
    4.   // Log info here...
    5. }
    It's been working as expected on UWP local builds (dev & release) and Android cloud builds (dev) where the define is actually specified.

    But I've just built the Android cloud build (release) version, where the define is NOT specified and it seems logging is enabled in the built APK.

    I've checked the full build log and it shows correct release defines (as specified in the build config)...

    Injecting custom Scripting Define Symbols 'RELEASE_BUILD;UNITY_CLOUD_BUILD'

    I've tried a clean & non-clean build and it makes no difference. Logging is always enabled, which it should not be.

    Am I mis-understanding how UCB handles custom defines or have I hit an issue here?

    Any help would be much appreciated.
     
    Last edited: May 25, 2021
  2. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    An update on this...

    Not sure if I should be sharing, but it's useful information.

    So I enrolled in the new Windows Beta Build program and cloned the release build (using the new Windows builder) and the resulting APK does not include logging (as expected)

    I then did another clean build on a non-Windows builder and the resulting APK does include logging (not as expected)

    So we have the strange situation where the new Windows builders are working correctly, but the existing non-Windows builders are not.
     
    Last edited: May 25, 2021
  3. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    Is anyone from Unity able to comment please?

    I'm am confident that this is not something I am doing wrong, as it works on one builder but not the other.

    It's a pretty big issue if so...
     
  4. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    Please could someone from Unity confirm that this is either being investigated and\or is a known issue?

    It's a pretty big one if so and for a paid product, the silence is particularly frustrating.

    Based on other threads, I am not the only one experiencing this.

    Thanks!
     
  5. Justin-Unity

    Justin-Unity

    Unity Technologies

    Joined:
    Jan 16, 2020
    Posts:
    24
    Please let me know what your ticket number is and I will try to help.
     
  6. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    Thanks Justin.

    Tbh I didn't report it as I've not had much success with that route before.

    But just reported it (case 1341599) so it should hopefully be official now.

    I've switched the Android builds to the Windows builders, which works around the problem for now.

    Once the iOS builds are test flighted, I'll let you know if those are experiencing the same issue as well.
     
  7. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    Hi @Justin-Unity,

    I had a reply from one of your Customer QA colleagues yesterday.

    Their reply implied that custom defines in a cloud build environment were not possible\reliable. It was then closed.

    Now I'm hoping it was just a mis-understanding. That either my original post (or their reply) wasn't clear or was mis-understood by one of us.

    Because if that's not the case and the use of custom defines is not possible\reliable in the cloud build environment, then UCB is not fit for purpose (sorry to say it)

    Now I really don't believe this is true, especially as the new UCB Windows Builders seem to honour them.

    I've replied back, which has re-opened the ticket, so it would be really appreciated if you could look over it and weigh in please.
     
    Last edited: Jun 11, 2021
  8. Justin-Unity

    Justin-Unity

    Unity Technologies

    Joined:
    Jan 16, 2020
    Posts:
    24
    Yeah, I reached out to my support team and they found the ticket in another department at Unity. We're discussing it and have pulled it over to our side of Unity. Sorry for the confusion on this and the time it is taking.

    We've engaged another group about the custom define and some support work they were doing for us around this same topic. I am making other members of my support team aware of this issue to help get you support.
     
    PeachyPixels likes this.
  9. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    That's great, many thanks Justin.

    Sounds like things are heading in the right direction :)

    Have you managed to replicate the issue or are you aware of what's causing it?

    I don't think all my custom defines are failing, but to be honest I've not checked each and every one.

    That said, the others all use #ifdef where-as LOGGING_ENABLED is the only one that uses the Conditional attribute. Maybe that's the issue?

    I am managing to work the problem for now by using the Windows builders (for Android) but have yet to test iOS. I'll report back on that as soon as I have news.

    If there's anything else I can do to help, please just ask.
     
    Last edited: Jun 15, 2021
  10. Justin-Unity

    Justin-Unity

    Unity Technologies

    Joined:
    Jan 16, 2020
    Posts:
    24
    I have put one of our devs on it. They will reach out through the support ticket for any sensitive details. Thanks!
     
  11. MarceloL-Unity

    MarceloL-Unity

    Joined:
    Jan 5, 2021
    Posts:
    12
    Hi.

    Our Windows builders were behaving differently in comparison to the Mac ones and we have now updated the Windows builders to behave in the same way.

    In regards to your issue in particular, we believe there might be a conflict with your Player Scripting Define Symbols and the Unity Cloud Build Custom Defines and that could be the reason why your log method is being called in builds generated in Unity Cloud Build.

    Unity Cloud Build generates .rsp files with the defines that are included in the project in addition to the Player Scripting Define Symbols.

    If you would like to use only Custom Defines you setup in Unity Cloud Build dashboard, one solution for your case is to use a Pre-Export Method to clean up the Player Scripting Define Symbols, as the example below:

    Code (CSharp):
    1.  
    2. using UnityEditor;
    3.  
    4. public class PreExportScript
    5. {
    6.     public static void RemovePlatformCustomDefines()
    7.     {
    8.   PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget), new string[] {});        
    9.     }
    10. }
    Best regards,
    Marcelo
     
    PeachyPixels and Justin-Unity like this.
  12. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    Hi Marcelo,

    Thanks for the reply, it's much appreciated.

    So you're saying that Unity Cloud Build merges the cloud config & Unity project custom defines?

    I have three UCB configs per project. Development, Beta & Production. Each one using specific defines.

    This is (logically) how you would expect Unity Cloud Build to work and how other cloud builders (I've used) work...

    1. Code changes committed to source control (default custom defines in Unity project are Development)
    2. Build Development config -> Output = Development package
    3. Build Beta config -> Output = Beta package
    4. Build Production config -> Output = Production package

    Basically, UCB overwrites the Unity project custom defines. Intuitive and simple.

    What you're implying requires this...

    1. Code changes committed to source control (default custom defines in Unity project are Development)
    2. Custom defines are removed from Unity project and project committed to source control
    3. Build Development config -> Output = Development package
    4. Build Beta config -> Output = Beta package
    5. Build Production config -> Output = Production package
    6. Custom defines are re-added to Unity project and project committed to source control

    So for every build you now have to commit temporary changes to source control and undo them at the end? If so, that's very non-standard and awkward. It also means the UCB auto-build feature is largely pointless.

    As for the script, thanks also for sending but I can't see how it would work in a UCB environment as it uses UnityEditor which is not available.

    I did try it though and as expected, it failed with these errors...

    [Unity] Assets\Framework\Scripts\Building\UnityCloudBuildPreExport.cs(12,5): error CS0103: The name 'PlayerSettings' does not exist in the current context
    7988: [Unity] Assets\Framework\Scripts\Building\UnityCloudBuildPreExport.cs(12,54): error CS0103: The name 'BuildPipeline' does not exist in the current context
    7989: [Unity] Assets\Framework\Scripts\Building\UnityCloudBuildPreExport.cs(12,88): error CS0103: The name 'EditorUserBuildSettings' does not exist in the current context

    Surely there is a better way for UCB for handle custom defines? A simple UCB option to specify merging or overwriting project defines would be perfect.
     
    Last edited: Jul 8, 2021
  13. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    Aha! You learn something every day :) I didn't realise this namespace is available if the relevant script is in the Editor folder.

    So it was moved there and appears to be building now. It's 10 minutes in and no failures yet.

    I'll test the conditional defines (on\off) and report back my findings.
     
  14. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    Ok, it looks like SetScriptingDefineSymbolsForGroup is working as expected, as long as the script resides in the Editor folder.

    I added some logging to the method (to make sure it was invoked) and checked the final build and it appears the correct features are now being enabled\disabled.

    It's a workaround for now, but one I'm very grateful for. Thank you! :)

    Long term, could you please consider a UCB option to either merge or overwrite the Unity project defines? Or something similar?

    It will definitely make UCB easier and more intuitive to use.

    PS: Will calling Debug.LogError(...) in the pre-export method fail the cloud build? Great if so as I can double check if the project defines have been removed and fail if not.
     
    MarceloL-Unity likes this.
  15. MarceloL-Unity

    MarceloL-Unity

    Joined:
    Jan 5, 2021
    Posts:
    12
    Hello David.

    We are glad this solution worked for you and we have already logged a feature request to add the option to either override or merge the Unity project defines.

    Also, in order to fail the build in a pre-export method, we suggest throwing an exception, since the Debug.LogError won't fail the build.

    Best regards,
    Marcelo
     
    PeachyPixels likes this.
  16. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    Great! Thanks Marcelo :)

    One thing I noticed though...

    I plan to add a sanity check to the pre-export method to look for the existence of custom defines (after attempting to clear them) and fail the build if they are still defined. That way, I don't have to check each and every build log manually.

    Code (CSharp):
    1. PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget), out customDefines);
    But the above method is always indicating that none are defined, even when they are in the Unity project. This is applicable to both the array and string versions. This is obviously with the clear code commented out :)

    That doesn't seem right to me?
     
    Last edited: Jul 14, 2021
  17. MarceloL-Unity

    MarceloL-Unity

    Joined:
    Jan 5, 2021
    Posts:
    12
    Hello David.

    I have just tested your snippet and the defines seem to be defined correctly. See the script below:

    Code (CSharp):
    1. public class PreExportScript
    2. {
    3.     public static void PrintDefines()
    4.     {
    5.         string[] defines;
    6.         PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget), out defines);
    7.         Debug.Log("Custom defines from player settings: " + string.Join(";", defines));
    8.     }
    9. }
    This is logging the defines from the player settings.

    Could you please confirm that you have the custom defines set in the player settings in the same platform as your build target? If yes, could you please share your build log link so that we can investigate further?

    Best regards,
    Marcelo
     
    PeachyPixels likes this.
  18. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    Hi Marcelo,

    Many apologies, but this one turned out to be user error :rolleyes:

    I've now got it working as expected.

    One thing to note though...

    If no custom defines are specified, the array version of GetScriptingDefineSymbolsForGroup will always return an array with one element (an empty string). This is regardless of whether you pass in a null or zero array. It's a little non-standard and means extra checking, which is not ideal. I would personally expect a zero element array.

    That said, the string version of GetScriptingDefineSymbolsForGroup returns a null string in the same scenario, so I've switched to using that as it's easier to check.

    The following script will highlight the problem...
    Code (CSharp):
    1. public class CustomDefineTest : MonoBehaviour
    2. {
    3.     void Start()
    4.     {
    5.       // Array...
    6.       string[] customDefines1;
    7.       PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget), out customDefines1);
    8.       if (customDefines1.Length > 0)
    9.         Debug.LogError($"Unity player custom defines detected [{string.Join(";", customDefines1)}]");
    10.  
    11.       // String...
    12.       string customDefines2 = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget));
    13.       if (!String.IsNullOrWhiteSpace(customDefines2))
    14.         Debug.LogError($"Unity player custom defines detected [{string.Join(";", customDefines2)}]");
    15.   }
    16.  
    17. }
    So all my builds now appear to be working as expected :)

    Many thanks for the help with this, it's very much appreciated.
     
    MarceloL-Unity likes this.
  19. MarceloL-Unity

    MarceloL-Unity

    Joined:
    Jan 5, 2021
    Posts:
    12
    Hello David.

    We are glad that your builds are working as expected!

    Please let us know in case we can assist with anything else.

    In regards to the array version of GetScriptingDefineSymbolsForGroup, we will send your feedback to the relevant team.

    Best,
    Marcelo
     
    PeachyPixels likes this.
  20. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    Great! Thanks :)
     
  21. PeachyPixels

    PeachyPixels

    Joined:
    Feb 17, 2018
    Posts:
    713
    So to wrap up...

    For anyone that would like the cloud build custom defines to completely replace the player defines (and not merge them) the following script works well (and also includes a sanity check)...

    Code (CSharp):
    1. public class UnityCloudBuildPreExport
    2. {
    3.  
    4.   public static void Execute()
    5.   {
    6.     Debug.Log("Removing Unity player custom defines");
    7.     PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget), new string[] { });
    8.     string customDefines = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget));
    9.     if (!string.IsNullOrWhiteSpace(customDefines))
    10.     {
    11.       Debug.LogError($"Unity player custom defines detected [{string.Join(";", customDefines)}]");
    12.       throw new Exception($"Unity player custom defines detected [{string.Join(";", customDefines)}]");
    13.     }
    14.     else
    15.       Debug.Log("Removed Unity player custom defines");
    16.   }
    17.  
    18. }
    Hope it helps!
     
    LilGames and MarceloL-Unity like this.