Search Unity

Building Adressables & Bundles for Multiple Platforms (separate content project)

Discussion in 'Addressables' started by Moritz5thPlanet, Sep 10, 2021.

  1. Moritz5thPlanet

    Moritz5thPlanet

    Joined:
    Feb 5, 2019
    Posts:
    73
    This topic has come up a few times, but - from within the Editor, how do I, without manually switching the platform, build my Addressables and Bundles for all platforms I care about? This is NOT a player build, this is a separate content editing project.

    EditorUserBuildSettings.SwitchActiveBuildTargetAsync doesn't let me switch reliably, sometimes it gets picky about Standalone platforms, sometimes about non-standalone platforms. (what is the special about BuildTargetGroup.Standalone, anyway).

    I tried to invoke it in Batchmode from the command line, but no Addressables are built and nothing appears in /ServerData.
     
  2. Moritz5thPlanet

    Moritz5thPlanet

    Joined:
    Feb 5, 2019
    Posts:
    73
    Code (CSharp):
    1.         [MenuItem("5th Planet Games/Content/Build All")]
    2.         private static void Build()
    3.         {
    4.             var gl = new List<BuildTargetGroup>
    5.             {
    6.                 BuildTargetGroup.Android,
    7.                 BuildTargetGroup.iOS,
    8.                 BuildTargetGroup.Standalone,
    9.                 BuildTargetGroup.Standalone,
    10.             };
    11.  
    12.             gl.Remove(EditorUserBuildSettings.selectedBuildTargetGroup);
    13.  
    14.             groups.Clear();
    15.             foreach (var g in gl) groups.Enqueue(g);
    16.  
    17.          
    18.             var tl = new List<BuildTarget>
    19.             {
    20.                 BuildTarget.Android,
    21.                 BuildTarget.iOS,
    22.                 BuildTarget.StandaloneWindows64,
    23.                 BuildTarget.StandaloneOSX,
    24.             };
    25.  
    26.             tl.Remove(EditorUserBuildSettings.activeBuildTarget);
    27.          
    28.             targets.Clear();
    29.             foreach (var t in tl) targets.Enqueue(t);
    30.          
    31.             BuildAddressables(EditorUserBuildSettings.activeBuildTarget);
    32.         }
    33.  
    34.         private static void BuildAddressables(BuildTarget target)
    35.         {
    36.             AddressableAssetSettings.CleanPlayerContent();
    37.             AddressableAssetSettings.BuildPlayerContent();
    38.  
    39.             if (groups.Count <= 0) return;
    40.             EditorUserBuildSettings.SwitchActiveBuildTargetAsync(groups.Dequeue(), targets.Dequeue());
    41.         }
    42.      
    43.         public void OnActiveBuildTargetChanged(BuildTarget previousTarget, BuildTarget newTarget)
    44.         {
    45.             Debug.Log($"Active platform is now {newTarget}");
    46.  
    47.             BuildAddressables(newTarget);
    48.         }
    49.  
     
  3. Moritz5thPlanet

    Moritz5thPlanet

    Joined:
    Feb 5, 2019
    Posts:
    73
    upload_2021-9-10_19-29-54.png
    This gives me, among others, these errors, but there actually ISN'T a compilation error. The platform switches and compiles successfully. What gives?
     
  4. Moritz5thPlanet

    Moritz5thPlanet

    Joined:
    Feb 5, 2019
    Posts:
    73
    The compilation error was something in FmodUnity (kind of disturbing - why do addressables care, at all, about IL2CPP)

    Anyway, next problem: This is the platform switch problem I keep getting - what's going on? Is this two wrong parameters? It happens when switching from BuildTargetGroup.IOS, BuildTarget.IOS to BuildTargetGroup. Android,BuildTarget.Android.
    upload_2021-9-10_19-47-56.png

    EDIT: Maybe I'm just too dumb to organize my queues...
     
  5. Moritz5thPlanet

    Moritz5thPlanet

    Joined:
    Feb 5, 2019
    Posts:
    73
    upload_2021-9-10_19-53-48.png

    upload_2021-9-10_19-53-58.png

    No... I'm just dumbfounded. What?! How can my current BuildTargetGroup be Android here?
     
  6. Moritz5thPlanet

    Moritz5thPlanet

    Joined:
    Feb 5, 2019
    Posts:
    73
    My workaround is to strictly decide what the group is based on the next target. The old (obsolete) API actually did this. I guess the domain reloads are also awful, time to serialize the queue somehow...
     
    Last edited: Sep 10, 2021
  7. Moritz5thPlanet

    Moritz5thPlanet

    Joined:
    Feb 5, 2019
    Posts:
    73
    My solution after various much more verbose attemots: EditorCoroutine, works like a charm.

    Code (CSharp):
    1.        
    2. private static IEnumerator BuildAndDeployCoroutine()
    3.         {
    4.             yield return null;
    5.             BuildAddressables(BuildTarget.Android);
    6.             yield return null;
    7.             BuildAddressables(BuildTarget.iOS);
    8.             yield return null;
    9.             BuildAddressables(BuildTarget.StandaloneOSX);
    10.             yield return null;
    11.             BuildAddressables(BuildTarget.StandaloneWindows64);
    12.             yield return null;
    13.  
    14.             DeployDevel();
    15.         }
    16.  
    17.         private static void BuildAddressables(BuildTarget target)
    18.         {
    19.             Debug.Log($"<color=magenta>Building Addressables for {target}</color>");
    20.            
    21.             EditorUserBuildSettings.SwitchActiveBuildTarget(Target2Group(target), target);
    22.  
    23.             AddressableAssetSettings.CleanPlayerContent();
    24.             AddressableAssetSettings.BuildPlayerContent();
    25.         }
    26.  
    27.         [MenuItem("5th Planet Games/Content/Build && Deploy", false, -1)]
    28.         private static void BuildAndDeploy()
    29.         {
    30.             Debug.ClearDeveloperConsole();
    31.            
    32.             EditorCoroutineUtility.StartCoroutineOwnerless(BuildAndDeployCoroutine());
    33.         }
    34.  
    35.         private static BuildTargetGroup Target2Group(BuildTarget nextTarget)
    36.         {
    37.             switch (nextTarget)
    38.             {
    39.                 case BuildTarget.StandaloneOSX:
    40.                 case BuildTarget.StandaloneWindows:
    41.                 case BuildTarget.StandaloneLinux64:
    42.                 case BuildTarget.StandaloneWindows64:
    43.                     return BuildTargetGroup.Standalone;
    44.  
    45.                 case BuildTarget.iOS:
    46.                     return BuildTargetGroup.iOS;
    47.  
    48.                 case BuildTarget.Android:
    49.                     return BuildTargetGroup.Android;
    50.  
    51.                 default:
    52.                     return BuildTargetGroup.Unknown;
    53.             }
    54.         }
    55.  
     
  8. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,618
    This approach usually doesn't scale well with the project size. It works good for small projects, but costs a lot more time when the project grows.

    A faster solution is to checkout the project for each platform to a separate folder, see discussion here: https://forum.unity.com/threads/aut...riation-in-example-repo.1073480/#post-6950015
     
  9. Moritz5thPlanet

    Moritz5thPlanet

    Joined:
    Feb 5, 2019
    Posts:
    73
    Yeah I was thinking about this - it does scale pretty okay with UnityAccelerator for now. We can split this up later if needed. Only with a fresh library folder and no accelerator support you're hit by the full brunt of the import work times the number of platforms - usually only happens on an Editor Version Upgrade.

    Turns out, at least in Unity 2021, the Library can contain AssetDatabases for multiple BuildTargets. (not sure when that changed) Keep your Library folders, folks!

    So, since the Library is usually kept, and because this is run exclusively manually, this feels right to me right now. And running it on a server would basically be the same action - navigate somewhere and click - but with much higher complexity and putting load on our already strained build machines.

    This approach clearly beats building the content individually, checking out multiple projects, with someone possibly (I dare say... usually!!!) forgetting one, etc.

    We also always need at least 2 (realistically 4) BuildTargets to be perfectly in sync, so they coexist in [BuildTarget] subfolders of ServerData. We also want to be able to quickly build one of these without committing to PlasticSCM first (this is for the "Latest" badge on our Devel cloud bucket).
     
    Last edited: Sep 11, 2021
  10. Heeg0r

    Heeg0r

    Joined:
    Mar 7, 2023
    Posts:
    1
    I am a beginner in Unity who is still in the internship period, I need to build to Windows, iOS and Android.
    I was wondering if you could post the command line example(if it is necessary) and complete C# codes here?
    Do I need to create a new Object in the Editor folder to mount the C# Script?
    I have spent 3 days on this problem but no good progress yet.

    Thanks very much!