Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Feature Request Enable/disable packages and assemblies for specific platforms

Discussion in 'Package Manager' started by DZZc0rd, May 10, 2023.

  1. DZZc0rd

    DZZc0rd

    Joined:
    Sep 4, 2021
    Posts:
    58
    Hello. I consider this feature necessary, because if you need to enable or disable for a specific platform, then for convenience and less time spent on creating and importing
    almost all object and resources. If you do not add this feature, then provide me with another option.
     
    Last edited: May 10, 2023
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    You need to be more specific as to what you consider a „plugin“. There is no such term used in Unity editor environments, instead we have assets, packages (two kinds), assemblies, asset bundles, and probably more.

    And it‘s the same with „elements“, probably you mean assets but the kind of assets is important too.
     
  3. DZZc0rd

    DZZc0rd

    Joined:
    Sep 4, 2021
    Posts:
    58
    Fixed
     
  4. DZZc0rd

    DZZc0rd

    Joined:
    Sep 4, 2021
    Posts:
    58
    And I want to make a game with IAP(for iOS) and Google AdMob(for Android)
     
  5. DZZc0rd

    DZZc0rd

    Joined:
    Sep 4, 2021
    Posts:
    58
    There are no other solutions, or some other reason?
     
    Last edited: May 14, 2023
    TobiasVetter likes this.
  6. TobiasVetter

    TobiasVetter

    Joined:
    Aug 31, 2021
    Posts:
    1
    Hi :) I'm also curious to know, if there is a way to disable packages for specific platform builds, as I am currently running into errors for android builds because of a package, which I need for UWP builds. Embedding a package and adjusting is a rather hacky workaround.
     
  7. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    According to this post optionally importing a package is possible with Version Defines.

    You should then #if YOUR_DEFINE_SYMBOL any code that optionally relies on the specified package. Alternatively, some packages already define their own symbol, like Input Manager does when it is installed so you can write code that uses either legacy input or Input Manager depending on whether Input Manager is installed.

    For instance, just yesterday I installed an asset that has optional serialization support for Odin Inspector.
     
  8. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,900
    No, this post doesn't say anything like it.

    This post says what is possible: having optional code(!) based on the presence of an asmdef and a version define setup in it. If the
    asmdef
    present (if it's a package, it is installed), then a directive will be defined which then can be used to fence code with the
    #ifdef
    method.
    But it does not allow you to install/uninstall packages based on target platform and AFAIK it is not possible out of the box.
    Unity is flexible though, I'm pretty sure you can write some sort of automation around it, but I do not recommend installing/uninstalling/reinstalling packages on a whim. It constant recompile, potential source of serious bugs. At some point you will forget what code is in on which platform and you will mess up greatly.
     
  9. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    Thanks for the clarification.
    I need to look into this myself as I currently rely on Unity.Serialization but I want to make this optional since it's still experimental, and serialization in general should be a "plugin" solution.
     
  10. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,900
    Quick usage example:

    Version Define definition:
    https://github.com/LurkingNinja/com...n/Runtime/com.lurking-ninja.cheat-code.asmdef

    Ifdef:
    https://github.com/LurkingNinja/com...ode/blob/main/Runtime/CheatCode/CheatCodes.cs

    Basically I'm monitoring if one of my other packages are installed or not.
     
  11. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    Hmmm can't help but think about possible solutions. Really got to try this ....

    One way I see that might be doable is to hook into the build process (a supported Unity feature) and depending on the target platform you'd modify a specific .asmdef - adding and removing dependencies and setting version defines.

    Ideally you'd have a .asmdef like "AdServices" which simply contains a factory class that creates either a AdmobService or IapService when requested to get an instance of the IAdService interface. The creation of instances is properly guarded with #if based on version defines set by the other two asmdefs. Those would exist at all times in the project but will only be referenced when building for either Android or iOS builds.

    That's my theory at least. Perhaps there's something obvious that would make this NOT work?
    I just worry what happens if you change an asmdef (or script) in the build process step. That might trigger an immediate assembly reload, possibly stopping the build.

    The solution that should work (again, in theory) is monitoring AssemblyReloadEvents in an editor script. The script notices if the target platform has changed, and if so, will modify the necessary .asmdef files. Shouldn't be an issue even if switching build targets causes two consecutive assembly reloads. And since the .asmdef are json files they're trivial to change.
     
  12. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,900
    CodeSmile likes this.
  13. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,899
    So I made a quick test and to be honest, I was expecting way more friction. In fact, it's almost trivial to optionally use a package or assembly definition using just Define Constraints. But yes, you have to think around a corner or two.

    I attached a zip file with the two scripts and two asmdefs that were needed to make this happen. The "optional package" depends on Unity.Serialization package, but it could be any other package.

    Here's the rundown, starting with UsesOptionalPackage.cs - this would be your project's main code path that wants to optionally use a package if installed:
    Code (CSharp):
    1.     [InitializeOnLoad]
    2.     public static class UsesOptionalPackage
    3.     {
    4.         static UsesOptionalPackage()
    5.         {
    6.             Debug.Log("static ctor");
    7.  
    8. #if USE_OPTIONAL_PACKAGE
    9.             var optional = new OptionalAssembly.OptionalCode();
    10.             Debug.Log(optional.GetOptionalString());
    11. #endif
    12.         }
    13.     }
    This uses the USE_OPTIONAL_PACKAGE script symbol to either use or not use the optional code.

    Instead, you would define an interface (or an abstract base class) that contains the necessary public methods such as GetOptionalString() or ShowAd(). Then #if once where you create an instance of the platform-specific class, returning that interface (or an abstract base class) rather than the instance itself. You can then use the interface everywhere without using #if. You could even have a "null" implementation as default for platforms that won't need to show ads - the ShowAd() and any other methods will simply not do anything, or return safe default values.

    The assembly definition of UsesOptionalPackage references the OptionalPackage assembly:
    upload_2023-5-28_17-52-33.png

    The OptionalPackage.asmdef in this example references Unity.Serialization - I use this because for Unity versions below 2022.2 it is still and probably will remain in experimental status, so I wish to only optionally use it. Of course this could be any other package, like AdMob, IAP, you name it.
    upload_2023-5-28_17-54-6.png

    Further down the same asmdef defines this constraint:
    upload_2023-5-28_17-55-46.png

    Where to define the USE_OPTIONAL_PACKAGE symbol?
    In the Scripting Define Symbols list of the Player settings - and of course only for the platforms where you want to use that optional code/assembly/package:
    upload_2023-5-28_17-50-27.png

    I set it in the WebGL package and I get the "optional installed" message in the Console.
    Then I switch to Windows platform, and the "optional installed" message is missing. Perfect.

    For completeness sake, here's the optional code's class:
    Code (CSharp):
    1.     public class OptionalCode
    2.     {
    3.         public string GetOptionalString() => "optional installed";
    4.     }
    Adding one more test with Version Defines (reproducing the .asmdef content because this post has reached its 5 attachments limit):
    Code (CSharp):
    1.     "versionDefines": [
    2.         {
    3.             "name": "com.unity.serialization",
    4.             "expression": "3.1",
    5.             "define": "UNITY_SERIALIZATION_3_1_0_AVAILABLE"
    6.         }
    7.     ],
    8.  
    This sets the given symbol only when the com.unity.serialization package is installed as version 3.1.0 or higher (the first non-experimental/non-preview version). This allows you to use a fallback serialization in case the package isn't installed or if it's too old.
     

    Attached Files:

    Last edited: May 28, 2023
    maximeb_unity likes this.