904 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			Markdown
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			904 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			Markdown
		
	
	
		
			Executable File
		
	
	
| # External Dependency Manager for Unity
 | ||
| 
 | ||
| [](https://openupm.com/packages/com.google.external-dependency-manager/)
 | ||
| [](https://openupm.com/packages/com.google.external-dependency-manager/)
 | ||
| 
 | ||
| ## Overview
 | ||
| 
 | ||
| The External Dependency Manager for Unity (EDM4U) (formerly Play Services
 | ||
| Resolver/Jar Resolver) is intended to be used by any Unity package or user that
 | ||
| requires:
 | ||
| 
 | ||
| *   Android specific libraries (e.g
 | ||
|     [AARs](https://developer.android.com/studio/projects/android-library.html))
 | ||
| 
 | ||
| *   iOS [CocoaPods](https://cocoapods.org/)
 | ||
| 
 | ||
| *   Version management of transitive dependencies
 | ||
| 
 | ||
| *   Management of Package Manager (PM) Registries
 | ||
| 
 | ||
| If you want to add and use iOS/Android dependencies directly in your project,
 | ||
| then you should to install EDM4U in your project.
 | ||
| 
 | ||
| If you are a package user and the plugin you are using depends on EDM4U, *and*
 | ||
| the package does not include EDM4U as a package dependency already, then you
 | ||
| should to install EDM4U in your project.
 | ||
| 
 | ||
| If you are a UPM package maintainer and your package requires EDM4U, then you
 | ||
| should add EDM4U as a
 | ||
| [package dependency](https://docs.unity3d.com/2019.3/Documentation/Manual/upm-dependencies.html)
 | ||
| in your package manifest (`package.json`):
 | ||
| 
 | ||
| ```json
 | ||
| {
 | ||
|   "dependencies": {
 | ||
|     "com.google.external-dependency-manager": "1.2.178"
 | ||
|   }
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| You should still install EDM4U to test out the package during development.
 | ||
| 
 | ||
| If you are a legacy `.unitypackage` package maintainer and your package requires
 | ||
| EDM4U, please ask the user to install EDM4U separately. You should install EDM4U
 | ||
| to test out the package during development.
 | ||
| 
 | ||
| Updated releases are available on
 | ||
| [GitHub](https://github.com/googlesamples/unity-jar-resolver)
 | ||
| 
 | ||
| ## Requirements
 | ||
| 
 | ||
| The *Android Resolver* and *iOS Resolver* components of the plugin only work
 | ||
| with Unity version 4.6.8 or higher.
 | ||
| 
 | ||
| The *Version Handler* component only works with Unity 5.x or higher as it
 | ||
| depends upon the `PluginImporter` UnityEditor API.
 | ||
| 
 | ||
| The *Package Manager Resolver* component only works with Unity 2018.4 or above,
 | ||
| when [scoped registry](https://docs.unity3d.com/Manual/upm-scoped.html) support
 | ||
| was added to the Package Manager.
 | ||
| 
 | ||
| ## Getting Started
 | ||
| 
 | ||
| Check out [troubleshooting](troubleshooting-faq.md) if you need help.
 | ||
| 
 | ||
| ### Install via OpenUPM
 | ||
| 
 | ||
| EDM4U is available on
 | ||
| [OpenUPM](https://openupm.com/packages/com.google.external-dependency-manager/):
 | ||
| 
 | ||
| ```shell
 | ||
| openupm add com.google.external-dependency-manager
 | ||
| ```
 | ||
| 
 | ||
| ### Install via git URL
 | ||
| 1. Open Package Manager
 | ||
| 2. Click on the + icon on the top left corner of the "Package Manager" screen
 | ||
| 3. Click on "Install package from git url..."
 | ||
| 4. Paste: https://github.com/googlesamples/unity-jar-resolver.git?path=upm
 | ||
| 
 | ||
| ### Install via Google APIs for Unity
 | ||
| 
 | ||
| EDM4U is available both in UPM and legacy `.unitypackage` formats on
 | ||
| [Google APIs for Unity](https://developers.google.com/unity/archive#external_dependency_manager_for_unity).
 | ||
| 
 | ||
| You may install the UPM version (.tgz) as a
 | ||
| [local UPM package](https://docs.unity3d.com/Manual/upm-ui-local.html).
 | ||
| 
 | ||
| You can also install EDM4U in your project as a `.unitypackage`. This is not
 | ||
| recommended due to potential conflicts.
 | ||
| 
 | ||
| ### Conflict Resolution
 | ||
| 
 | ||
| For historical reasons, a package maintainer may choose to embed EDM4U in their
 | ||
| package for ease of installation. This will create a conflict when you try to
 | ||
| install EDM4U with the steps above, or with another package with embedded EDM4U.
 | ||
| If your project imported a `.unitypackage` that has a copy of EDM4U embedded in
 | ||
| it, you may safely delete it from your Assets folder. If your project depends on
 | ||
| another UPM package with EDM4U, please reach out to the package maintainer and
 | ||
| ask them to replace it with a dependency to this package. In the meantime, you
 | ||
| can workaround the issue by copying the package to your Packages folder (to
 | ||
| create an
 | ||
| [embedded package](https://docs.unity3d.com/Manual/upm-concepts.html#Embedded))
 | ||
| and perform the steps yourself to avoid a dependency conflict.
 | ||
| 
 | ||
| ### Config file
 | ||
| 
 | ||
| To start adding dependencies to your project, copy and rename the
 | ||
| [SampleDependencies.xml](https://github.com/googlesamples/unity-jar-resolver/blob/master/sample/Assets/ExternalDependencyManager/Editor/SampleDependencies.xml)
 | ||
| file into your plugin and add the dependencies your project requires.
 | ||
| 
 | ||
| The XML file needs to be under an `Editor` directory and match the name
 | ||
| `*Dependencies.xml`. For example, `MyPlugin/Editor/MyPluginDependencies.xml`.
 | ||
| 
 | ||
| ## Usages
 | ||
| 
 | ||
| ### Android Resolver
 | ||
| 
 | ||
| The Android Resolver copies specified dependencies from local or remote Maven
 | ||
| repositories into the Unity project when a user selects Android as the build
 | ||
| target in the Unity editor.
 | ||
| 
 | ||
| For example, to add the Google Play Games library
 | ||
| (`com.google.android.gms:play-services-games` package) at version `9.8.0` to the
 | ||
| set of a plugin's Android dependencies:
 | ||
| 
 | ||
| ```xml
 | ||
| <dependencies>
 | ||
|   <androidPackages>
 | ||
|     <androidPackage spec="com.google.android.gms:play-services-games:9.8.0">
 | ||
|       <androidSdkPackageIds>
 | ||
|         <androidSdkPackageId>extra-google-m2repository</androidSdkPackageId>
 | ||
|       </androidSdkPackageIds>
 | ||
|     </androidPackage>
 | ||
|   </androidPackages>
 | ||
| </dependencies>
 | ||
| ```
 | ||
| 
 | ||
| The version specification (last component) supports:
 | ||
| 
 | ||
| *   Specific versions e.g `9.8.0`
 | ||
| 
 | ||
| *   Partial matches e.g `9.8.+` would match 9.8.0, 9.8.1 etc. choosing the most
 | ||
|     recent version
 | ||
| 
 | ||
| *   Latest version using `LATEST` or `+`. We do *not* recommend using this
 | ||
|     unless you're 100% sure the library you depend upon will not break your
 | ||
|     Unity plugin in future
 | ||
| 
 | ||
| The above example specifies the dependency as a component of the Android SDK
 | ||
| manager such that the Android SDK manager will be executed to install the
 | ||
| package if it's not found. If your Android dependency is located on Maven
 | ||
| central it's possible to specify the package simply using the `androidPackage`
 | ||
| element:
 | ||
| 
 | ||
| ```xml
 | ||
| <dependencies>
 | ||
|   <androidPackages>
 | ||
|     <androidPackage spec="com.google.api-client:google-api-client-android:1.22.0" />
 | ||
|   </androidPackages>
 | ||
| </dependencies>
 | ||
| ```
 | ||
| 
 | ||
| #### Auto-resolution
 | ||
| 
 | ||
| By default the Android Resolver automatically monitors the dependencies you have
 | ||
| specified and the `Plugins/Android` folder of your Unity project. The resolution
 | ||
| process runs when the specified dependencies are not present in your project.
 | ||
| 
 | ||
| The *auto-resolution* process can be disabled via the `Assets > External
 | ||
| Dependency Manager > Android Resolver > Settings` menu.
 | ||
| 
 | ||
| Manual resolution can be performed using the following menu options:
 | ||
| 
 | ||
| *   `Assets > External Dependency Manager > Android Resolver > Resolve`
 | ||
| 
 | ||
| *   `Assets > External Dependency Manager > Android Resolver > Force Resolve`
 | ||
| 
 | ||
| #### Deleting libraries
 | ||
| 
 | ||
| Resolved packages are tracked via asset labels by the Android Resolver. They can
 | ||
| easily be deleted using the `Assets > External Dependency Manager > Android
 | ||
| Resolver > Delete Resolved Libraries` menu item.
 | ||
| 
 | ||
| #### Android Manifest Variable Processing
 | ||
| 
 | ||
| Some AAR files (for example play-services-measurement) contain variables that
 | ||
| are processed by the Android Gradle plugin. Unfortunately, Unity does not
 | ||
| perform the same processing when using Unity's Internal Build System, so the
 | ||
| Android Resolver plugin handles known cases of this variable substitution by
 | ||
| exploding the AAR into a folder and replacing `${applicationId}` with the
 | ||
| `bundleID`.
 | ||
| 
 | ||
| Disabling AAR explosion and therefore Android manifest processing can be done
 | ||
| via the `Assets > External Dependency Manager > Android Resolver > Settings`
 | ||
| menu. You may want to disable explosion of AARs if you're exporting a project to
 | ||
| be built with Gradle/Android Studio.
 | ||
| 
 | ||
| #### ABI Stripping
 | ||
| 
 | ||
| Some AAR files contain native libraries (.so files) for each ABI supported by
 | ||
| Android. Unfortunately, when targeting a single ABI (e.g x86), Unity does not
 | ||
| strip native libraries for unused ABIs. To strip unused ABIs, the Android
 | ||
| Resolver plugin explodes an AAR into a folder and removes unused ABIs to reduce
 | ||
| the built APK size. Furthermore, if native libraries are not stripped from an
 | ||
| APK (e.g you have a mix of Unity's x86 library and some armeabi-v7a libraries)
 | ||
| Android may attempt to load the wrong library for the current runtime ABI
 | ||
| completely breaking your plugin when targeting some architectures.
 | ||
| 
 | ||
| AAR explosion and therefore ABI stripping can be disabled via the `Assets >
 | ||
| External Dependency Manager > Android Resolver > Settings` menu. You may want to
 | ||
| disable explosion of AARs if you're exporting a project to be built with
 | ||
| Gradle/Android Studio.
 | ||
| 
 | ||
| #### Resolution Strategies
 | ||
| 
 | ||
| By default the Android Resolver will use Gradle to download dependencies prior
 | ||
| to integrating them into a Unity project. This works with Unity's internal build
 | ||
| system and Gradle/Android Studio project export.
 | ||
| 
 | ||
| It's possible to change the resolution strategy via the `Assets > External
 | ||
| Dependency Manager > Android Resolver > Settings` menu.
 | ||
| 
 | ||
| ##### Download Artifacts with Gradle
 | ||
| 
 | ||
| Using the default resolution strategy, the Android resolver executes the
 | ||
| following operations:
 | ||
| 
 | ||
| -   Remove the result of previous Android resolutions. E.g Delete all files and
 | ||
|     directories labeled with "gpsr" under `Plugins/Android` from the project.
 | ||
| 
 | ||
| -   Collect the set of Android dependencies (libraries) specified by a project's
 | ||
|     `*Dependencies.xml` files.
 | ||
| 
 | ||
| -   Run `download_artifacts.gradle` with Gradle to resolve conflicts and, if
 | ||
|     successful, download the set of resolved Android libraries (AARs, JARs).
 | ||
| 
 | ||
| -   Process each AAR/JAR so that it can be used with the currently selected
 | ||
|     Unity build system (e.g Internal vs. Gradle, Export vs. No Export). This
 | ||
|     involves patching each reference to `applicationId` in the
 | ||
|     `AndroidManifest.xml` with the project's bundle ID. This means resolution
 | ||
|     must be run again if the bundle ID has changed.
 | ||
| 
 | ||
| -   Move the processed AARs to `Plugins/Android` so they will be included when
 | ||
|     Unity invokes the Android build.
 | ||
| 
 | ||
| ##### Integrate into mainTemplate.gradle
 | ||
| 
 | ||
| Unity 5.6 introduced support for customizing the `build.gradle` used to build
 | ||
| Unity projects with Gradle. When the *Patch mainTemplate.gradle* setting is
 | ||
| enabled, rather than downloading artifacts before the build, Android resolution
 | ||
| results in the execution of the following operations:
 | ||
| 
 | ||
| -   Remove the result of previous Android resolutions. E.g Delete all files and
 | ||
|     directories labeled with "gpsr" under `Plugins/Android` from the project and
 | ||
|     remove sections delimited with `// Android Resolver * Start` and `// Android
 | ||
|     Resolver * End` lines.
 | ||
| 
 | ||
| -   Collect the set of Android dependencies (libraries) specified by a project's
 | ||
|     `*Dependencies.xml` files.
 | ||
| 
 | ||
| -   Rename any `.srcaar` files in the build to `.aar` and exclude them from
 | ||
|     being included directly by Unity in the Android build as
 | ||
|     `mainTemplate.gradle` will be patched to include them instead from their
 | ||
|     local maven repositories.
 | ||
| 
 | ||
| -   Inject the required Gradle repositories into `mainTemplate.gradle` at the
 | ||
|     line matching the pattern `.*apply plugin:
 | ||
|     'com\.android\.(application|library)'.*` or the section starting at the line
 | ||
|     `// Android Resolver Repos Start`. If you want to control the injection
 | ||
|     point in the file, the section delimited by the lines `// Android Resolver
 | ||
|     Repos Start` and `// Android Resolver Repos End` should be placed in the
 | ||
|     global scope before the `dependencies` section.
 | ||
| 
 | ||
| -   Inject the required Android dependencies (libraries) into
 | ||
|     `mainTemplate.gradle` at the line matching the pattern `***DEPS***` or the
 | ||
|     section starting at the line `// Android Resolver Dependencies Start`. If
 | ||
|     you want to control the injection point in the file, the section delimited
 | ||
|     by the lines `// Android Resolver Dependencies Start` and `// Android
 | ||
|     Resolver Dependencies End` should be placed in the `dependencies` section.
 | ||
| 
 | ||
| -   Inject the packaging options logic, which excludes architecture specific
 | ||
|     libraries based upon the selected build target, into `mainTemplate.gradle`
 | ||
|     at the line matching the pattern `android +{` or the section starting at the
 | ||
|     line `// Android Resolver Exclusions Start`. If you want to control the
 | ||
|     injection point in the file, the section delimited by the lines `// Android
 | ||
|     Resolver Exclusions Start` and `// Android Resolver Exclusions End` should
 | ||
|     be placed in the global scope before the `android` section.
 | ||
| 
 | ||
| #### Dependency Tracking
 | ||
| 
 | ||
| The Android Resolver creates the
 | ||
| `ProjectSettings/AndroidResolverDependencies.xml` to quickly determine the set
 | ||
| of resolved dependencies in a project. This is used by the auto-resolution
 | ||
| process to only run the expensive resolution process when necessary.
 | ||
| 
 | ||
| #### Displaying Dependencies
 | ||
| 
 | ||
| It's possible to display the set of dependencies the Android Resolver would
 | ||
| download and process in your project via the `Assets > External Dependency
 | ||
| Manager > Android Resolver > Display Libraries` menu item.
 | ||
| 
 | ||
| ### iOS Resolver
 | ||
| 
 | ||
| The iOS resolver component of this plugin manages
 | ||
| [CocoaPods](https://cocoapods.org/). A CocoaPods `Podfile` is generated and the
 | ||
| `pod` tool is executed as a post build process step to add dependencies to the
 | ||
| Xcode project exported by Unity.
 | ||
| 
 | ||
| Dependencies for iOS are added by referring to CocoaPods.
 | ||
| 
 | ||
| For example, to add the AdMob pod, version 7.0 or greater with bitcode enabled:
 | ||
| 
 | ||
| ```xml
 | ||
| <dependencies>
 | ||
|   <iosPods>
 | ||
|     <iosPod name="Google-Mobile-Ads-SDK" version="~> 7.0" bitcodeEnabled="true"
 | ||
|             minTargetSdk="6.0" addToAllTargets="false" />
 | ||
|   </iosPods>
 | ||
| </dependencies>
 | ||
| ```
 | ||
| 
 | ||
| #### Integration Strategies
 | ||
| 
 | ||
| The `CocoaPods` are either:
 | ||
| 
 | ||
| *   Downloaded and injected into the Xcode project file directly, rather than
 | ||
|     creating a separate xcworkspace. We call this `Xcode project` integration.
 | ||
| 
 | ||
| *   If the Unity version supports opening a xcworkspace file, the `pod` tool is
 | ||
|     used as intended to generate a xcworkspace which references the CocoaPods.
 | ||
|     We call this `Xcode workspace` integration.
 | ||
| 
 | ||
| The resolution strategy can be changed via the `Assets > External Dependency
 | ||
| Manager > iOS Resolver > Settings` menu.
 | ||
| 
 | ||
| ##### Appending text to generated Podfile
 | ||
| 
 | ||
| In order to modify the generated Podfile you can create a script like this:
 | ||
| 
 | ||
| ```csharp
 | ||
| using System.IO;
 | ||
| 
 | ||
| using UnityEditor;
 | ||
| using UnityEditor.Callbacks;
 | ||
| using UnityEngine;
 | ||
| 
 | ||
| public class PostProcessIOS : MonoBehaviour
 | ||
| {
 | ||
|     // Must be between 40 and 50 to ensure that it's not overriden by Podfile generation (40) and
 | ||
|     // that it's added before "pod install" (50).
 | ||
|     [PostProcessBuildAttribute(45)]
 | ||
|     private static void PostProcessBuild_iOS(BuildTarget target, string buildPath)
 | ||
|     {
 | ||
|         if (target == BuildTarget.iOS)
 | ||
|         {
 | ||
|             using (StreamWriter sw = File.AppendText(buildPath + "/Podfile"))
 | ||
|             {
 | ||
|                 // E.g. add an app extension
 | ||
|                 sw.WriteLine("\ntarget 'NSExtension' do\n  pod 'Firebase/Messaging', '6.6.0'\nend");
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| ### Package Manager Resolver
 | ||
| 
 | ||
| Adding registries to the
 | ||
| [Package Manager](https://docs.unity3d.com/Manual/Packages.html) (PM) is a
 | ||
| manual process. The Package Manager Resolver (PMR) component of this plugin
 | ||
| makes it easy for plugin maintainers to distribute new PM registry servers and
 | ||
| easy for plugin users to manage PM registry servers.
 | ||
| 
 | ||
| #### Adding Registries
 | ||
| 
 | ||
| For example, to add a registry for plugins in the scope `com.coolstuff`:
 | ||
| 
 | ||
| ```xml
 | ||
| <registries>
 | ||
|   <registry name="Cool Stuff"
 | ||
|             url="https://unityregistry.coolstuff.com"
 | ||
|             termsOfService="https://coolstuff.com/unityregistry/terms"
 | ||
|             privacyPolicy="https://coolstuff.com/unityregistry/privacy">
 | ||
|     <scopes>
 | ||
|       <scope>com.coolstuff</scope>
 | ||
|     </scopes>
 | ||
|   </registry>
 | ||
| </registries>
 | ||
| ```
 | ||
| 
 | ||
| When PMR is loaded it will prompt the developer to add the registry to their
 | ||
| project if it isn't already present in the `Packages/manifest.json` file.
 | ||
| 
 | ||
| For more information, see Unity's documentation on
 | ||
| [scoped package registries](https://docs.unity3d.com/Manual/upm-scoped.html).
 | ||
| 
 | ||
| #### Managing Registries
 | ||
| 
 | ||
| It's possible to add and remove registries that are specified via PMR XML
 | ||
| configuration files via the following menu options:
 | ||
| 
 | ||
| *   `Assets > External Dependency Manager > Package Manager Resolver > Add
 | ||
|     Registries` will prompt the user with a window which allows them to add
 | ||
|     registries discovered in the project to the Package Manager.
 | ||
| 
 | ||
| *   `Assets > External Dependency Manager > Package Manager Resolver > Remove
 | ||
|     Registries` will prompt the user with a window which allows them to remove
 | ||
|     registries discovered in the project from the Package Manager.
 | ||
| 
 | ||
| *   `Assets > External Dependency Manager > Package Manager Resolver > Modify
 | ||
|     Registries` will prompt the user with a window which allows them to add or
 | ||
|     remove registries discovered in the project.
 | ||
| 
 | ||
| #### Migration
 | ||
| 
 | ||
| PMR can migrate Version Handler packages installed in the `Assets` folder to PM
 | ||
| packages. This requires the plugins to implement the following:
 | ||
| 
 | ||
| *   `.unitypackage` must include a Version Handler manifests that describes the
 | ||
|     components of the plugin. If the plugin has no dependencies the manifest
 | ||
|     would just include the files in the plugin.
 | ||
| 
 | ||
| *   The PM package JSON provided by the registry must include a keyword (in the
 | ||
|     `versions.VERSION.keyword` list) that maps the PM package to a Version
 | ||
|     Handler package using the format `vh-name:VERSION_HANDLER_MANIFEST_NAME`
 | ||
|     where `VERSION_HANDLER_MANIFEST_NAME` is the name of the manifest defined in
 | ||
|     the `.unitypackage`. For more information see the description of the
 | ||
|     `gvhp_manifestname` asset label in the [Version Handler](#version-handler)
 | ||
|     section.
 | ||
| 
 | ||
| When using the `Assets > External Dependency Manager > Package Manager
 | ||
| Resolver > Migrate Packages` menu option, PMR then will:
 | ||
| 
 | ||
| *   List all Version Handler manager packages in the project.
 | ||
| 
 | ||
| *   Search all available packages in the PM registries and fetch keywords
 | ||
|     associated with each package parsing the Version Handler manifest names for
 | ||
|     each package.
 | ||
| 
 | ||
| *   Map each installed Version Handler package to a PM package.
 | ||
| 
 | ||
| *   Prompt the user to migrate the discovered packages.
 | ||
| 
 | ||
| *   Perform package migration for all selected packages if the user clicks the
 | ||
|     `Apply` button.
 | ||
| 
 | ||
| #### Configuration
 | ||
| 
 | ||
| PMR can be configured via the `Assets > External Dependency Manager > Package
 | ||
| Manager Resolver > Settings` menu option:
 | ||
| 
 | ||
| *   `Add package registries` when enabled, when the plugin loads or registry
 | ||
|     configuration files change, this will prompt the user to add registries that
 | ||
|     are not present in the Package Manager.
 | ||
| 
 | ||
| *   `Prompt to add package registries` will cause a developer to be prompted
 | ||
|     with a window that will ask for confirmation before adding registries. When
 | ||
|     this is disabled registries are added silently to the project.
 | ||
| 
 | ||
| *   `Prompt to migrate packages` will cause a developer to be prompted with a
 | ||
|     window that will ask for confirmation before migrating packages installed in
 | ||
|     the `Assets` directory to PM packages.
 | ||
| 
 | ||
| *   `Enable Analytics Reporting` when enabled, reports the use of the plugin to
 | ||
|     the developers so they can make imrpovements.
 | ||
| 
 | ||
| *   `Verbose logging` when enabled prints debug information to the console which
 | ||
|     can be useful when filing bug reports.
 | ||
| 
 | ||
| ### Version Handler
 | ||
| 
 | ||
| The Version Handler component of this plugin manages:
 | ||
| 
 | ||
| *   Shared Unity plugin dependencies.
 | ||
| 
 | ||
| *   Upgrading Unity plugins by cleaning up old files from previous versions.
 | ||
| 
 | ||
| *   Uninstallation of plugins that are distributed with manifest files.
 | ||
| 
 | ||
| *   Restoration of plugin assets to their original install locations if assets
 | ||
|     are tagged with the `exportpath` label.
 | ||
| 
 | ||
| Since the Version Handler needs to modify Unity asset metadata (`.meta` files),
 | ||
| to enable/disable components, rename and delete asset files it does not work
 | ||
| with Package Manager installed packages. It's still possible to include EDM4U in
 | ||
| Package Manager packages, the Version Handler component simply won't do anything
 | ||
| to PM plugins in this case.
 | ||
| 
 | ||
| #### Using Version Handler Managed Plugins
 | ||
| 
 | ||
| If a plugin is imported at multiple different versions into a project, if the
 | ||
| Version Handler is enabled, it will automatically check all managed assets to
 | ||
| determine the set of assets that are out of date and assets that should be
 | ||
| removed. To disable automatic checking managed assets disable the `Enable
 | ||
| version management` option in the `Assets > External Dependency Manager >
 | ||
| Version Handler > Settings` menu.
 | ||
| 
 | ||
| If version management is disabled, it's possible to check managed assets
 | ||
| manually using the `Assets > External Dependency Manager > Version Handler >
 | ||
| Update` menu option.
 | ||
| 
 | ||
| ##### Listing Managed Plugins
 | ||
| 
 | ||
| Plugins managed by the Version Handler, those that ship with manifest files, can
 | ||
| displayed using the `Assets > External Dependency Manager > Version Handler >
 | ||
| Display Managed Packages` menu option. The list of plugins are written to the
 | ||
| console window along with the set of files used by each plugin.
 | ||
| 
 | ||
| ##### Uninstalling Managed Plugins
 | ||
| 
 | ||
| Plugins managed by the Version Handler, those that ship with manifest files, can
 | ||
| be removed using the `Assets > External Dependency Manager > Version Handler >
 | ||
| Uninstall Managed Packages` menu option. This operation will display a window
 | ||
| that allows a developer to select a set of plugins to remove which will remove
 | ||
| all files owned by each plugin excluding those that are in use by other
 | ||
| installed plugins.
 | ||
| 
 | ||
| Files managed by the Version Handler, those labeled with the `gvh` asset label,
 | ||
| can be checked to see whether anything needs to be upgraded, disabled or removed
 | ||
| using the `Assets > External Dependency Manager > Version Handler > Update` menu
 | ||
| option.
 | ||
| 
 | ||
| ##### Restore Install Paths
 | ||
| 
 | ||
| Some developers move assets around in their project which can make it harder for
 | ||
| plugin maintainers to debug issues if this breaks Unity's
 | ||
| [special folders](https://docs.unity3d.com/Manual/SpecialFolders.html) rules. If
 | ||
| assets are labeled with their original install/export path (see
 | ||
| `gvhp_exportpath` below), Version Handler can restore assets to their original
 | ||
| locations when using the `Assets > External Dependency Manager > Version
 | ||
| Handler > Move Files To Install Locations` menu option.
 | ||
| 
 | ||
| ##### Settings
 | ||
| 
 | ||
| Some behavior of the Version Handler can be configured via the `Assets >
 | ||
| External Dependency Manager > Version Handler > Settings` menu option.
 | ||
| 
 | ||
| *   `Enable version management` controls whether the plugin should automatically
 | ||
|     check asset versions and apply changes. If this is disabled the process
 | ||
|     should be run manually when installing or upgrading managed plugins using
 | ||
|     `Assets > External Dependency Manager > Version Handler > Update`.
 | ||
| 
 | ||
| *   `Rename to canonical filenames` is a legacy option that will rename files to
 | ||
|     remove version numbers and other labels from filenames.
 | ||
| 
 | ||
| *   `Prompt for obsolete file deletion` enables the display of a window when
 | ||
|     obsolete files are deleted allowing the developer to select which files to
 | ||
|     delete and those to keep.
 | ||
| 
 | ||
| *   `Allow disabling files via renaming` controls whether obsolete or disabled
 | ||
|     files should be disabled by renaming them to `myfilename_DISABLED`. Renaming
 | ||
|     to disable files is required in some scenarios where Unity doesn't support
 | ||
|     removing files from the build via the PluginImporter.
 | ||
| 
 | ||
| *   `Enable Analytics Reporting` enables/disables usage reporting to plugin
 | ||
|     developers to improve the product.
 | ||
| 
 | ||
| *   `Verbose logging` enables *very* noisy log output that is useful for
 | ||
|     debugging while filing a bug report or building a new managed plugin.
 | ||
| 
 | ||
| *   `Use project settings` saves settings for the plugin in the project rather
 | ||
|     than system-wide.
 | ||
| 
 | ||
| #### Redistributing a Managed Plugin
 | ||
| 
 | ||
| The Version Handler employs a couple of methods for managing version selection,
 | ||
| upgrade and removal of plugins.
 | ||
| 
 | ||
| *   Each plugin can ship with a manifest file that lists the files it includes.
 | ||
|     This makes it possible for Version Handler to calculate the difference in
 | ||
|     assets between the most recent release of a plugin and the previous release
 | ||
|     installed in a project. If a files are removed the Version Handler will
 | ||
|     prompt the user to clean up obsolete files.
 | ||
| 
 | ||
| *   Plugins can ship using assets with unique names, unique GUIDs and version
 | ||
|     number labels. Version numbers can be attached to assets using labels or
 | ||
|     added to the filename (e.g `myfile.txt` would be `myfile_version-x.y.z.txt).
 | ||
|     This allows the Version Handler to determine which set of files are the same
 | ||
|     file at different versions, select the most recent version and prompt the
 | ||
|     developer to clean up old versions.
 | ||
| 
 | ||
| Unity plugins can be managed by the Version Handler using the following steps:
 | ||
| 
 | ||
| 1.  Add the `gvh` asset label to each asset (file) you want Version Handler to
 | ||
|     manage.
 | ||
| 
 | ||
| 1.  Add the `gvh_version-VERSION` label to each asset where `VERSION` is the
 | ||
|     version of the plugin you're releasing (e.g 1.2.3).
 | ||
| 
 | ||
| 1.  Add the `gvhp_exportpath-PATH` label to each asset where `PATH` is the
 | ||
|     export path of the file when the `.unitypackage` is created. This is used to
 | ||
|     track files if they're moved around in a project by developers.
 | ||
| 
 | ||
| 1.  Optional: Add `gvh_targets-editor` label to each editor DLL in your plugin
 | ||
|     and disable `editor` as a target platform for the DLL. The Version Handler
 | ||
|     will enable the most recent version of this DLL when the plugin is imported.
 | ||
| 
 | ||
| 1.  Optional: If your plugin is included in other Unity plugins, you should add
 | ||
|     the version number to each filename and change the GUID of each asset. This
 | ||
|     allows multiple versions of your plugin to be imported into a Unity project,
 | ||
|     with the Version Handler component activating only the most recent version.
 | ||
| 
 | ||
| 1.  Create a manifest text file named `MY_UNIQUE_PLUGIN_NAME_VERSION.txt` that
 | ||
|     lists all the files in your plugin relative to the project root. Then add
 | ||
|     the `gvh_manifest` label to the asset to indicate this file is a plugin
 | ||
|     manifest.
 | ||
| 
 | ||
| 1.  Optional: Add a `gvhp_manifestname-NAME` label to your manifest file to
 | ||
|     provide a human readable name for your package. If this isn't provided the
 | ||
|     name of the manifest file will be used as the package name. NAME can match
 | ||
|     the pattern `[0-9]+[a-zA-Z -]` where a leading integer will set the priority
 | ||
|     of the name where `0` is the highest priority and preferably used as the
 | ||
|     display name. The lowest value (i.e highest priority name) will be used as
 | ||
|     the display name and all other specified names will be aliases of the
 | ||
|     display name. Aliases can refer to previous names of the package allowing
 | ||
|     renaming across published versions.
 | ||
| 
 | ||
| 1.  Redistribute EDM4U Unity plugin with your plugin. See the
 | ||
|     [Plugin Redistribution](#plugin-redistribution) section for details.
 | ||
| 
 | ||
| If you follow these steps:
 | ||
| 
 | ||
| *   When users import a newer version of your plugin, files referenced by the
 | ||
|     older version's manifest are cleaned up.
 | ||
| 
 | ||
| *   The latest version of the plugin will be selected when users import multiple
 | ||
|     packages that include your plugin, assuming the steps in
 | ||
|     [Plugin Redistribution](#plugin-redistribution) are followed.
 | ||
| 
 | ||
| ## Background
 | ||
| 
 | ||
| Many Unity plugins have dependencies upon Android specific libraries, iOS
 | ||
| CocoaPods, and sometimes have transitive dependencies upon other Unity plugins.
 | ||
| This causes the following problems:
 | ||
| 
 | ||
| *   Integrating platform specific (e.g Android and iOS) libraries within a Unity
 | ||
|     project can be complex and a burden on a Unity plugin maintainer.
 | ||
| *   The process of resolving conflicting dependencies on platform specific
 | ||
|     libraries is pushed to the developer attempting to use a Unity plugin. The
 | ||
|     developer trying to use your plugin is very likely to give up when faced
 | ||
|     with Android or iOS specific build errors.
 | ||
| *   The process of resolving conflicting Unity plugins (due to shared Unity
 | ||
|     plugin components) is pushed to the developer attempting to use your Unity
 | ||
|     plugin. In an effort to resolve conflicts, the developer will very likely
 | ||
|     attempt to resolve problems by deleting random files in your plugin, report
 | ||
|     bugs when that doesn't work and finally give up.
 | ||
| 
 | ||
| EDM4U provides solutions for each of these problems.
 | ||
| 
 | ||
| ### Android Dependency Management
 | ||
| 
 | ||
| The *Android Resolver* component of this plugin will download and integrate
 | ||
| Android library dependencies and handle any conflicts between plugins that share
 | ||
| the same dependencies.
 | ||
| 
 | ||
| Without the Android Resolver, typically Unity plugins bundle their AAR and JAR
 | ||
| dependencies, e.g. a Unity plugin `SomePlugin` that requires the Google Play
 | ||
| Games Android library would redistribute the library and its transitive
 | ||
| dependencies in the folder `SomePlugin/Android/`. When a user imports
 | ||
| `SomeOtherPlugin` that includes the same libraries (potentially at different
 | ||
| versions) in `SomeOtherPlugin/Android/`, the developer using `SomePlugin` and
 | ||
| `SomeOtherPlugin` will see an error when building for Android that can be hard
 | ||
| to interpret.
 | ||
| 
 | ||
| Using the Android Resolver to manage Android library dependencies:
 | ||
| 
 | ||
| *   Solves Android library conflicts between plugins.
 | ||
| *   Handles all of the various processing steps required to use Android
 | ||
|     libraries (AARs, JARs) in Unity 4.x and above projects. Almost all versions
 | ||
|     of Unity have - at best - partial support for AARs.
 | ||
| *   (Experimental) Supports minification of included Java components without
 | ||
|     exporting a project.
 | ||
| 
 | ||
| ### iOS Dependency Management
 | ||
| 
 | ||
| The *iOS Resolver* component of this plugin integrates with
 | ||
| [CocoaPods](https://cocoapods.org/) to download and integrate iOS libraries and
 | ||
| frameworks into the Xcode project Unity generates when building for iOS. Using
 | ||
| CocoaPods allows multiple plugins to utilize shared components without forcing
 | ||
| developers to fix either duplicate or incompatible versions of libraries
 | ||
| included through multiple Unity plugins in their project.
 | ||
| 
 | ||
| ### Package Manager Registry Setup
 | ||
| 
 | ||
| The [Package Manager](https://docs.unity3d.com/Manual/Packages.html) (PM) makes
 | ||
| use of [NPM](https://www.npmjs.com/) registry servers for package hosting and
 | ||
| provides ways to discover, install, upgrade and uninstall packages. This makes
 | ||
| it easier for developers to manage plugins within their projects.
 | ||
| 
 | ||
| However, installing additional package registries requires a few manual steps
 | ||
| that can potentially be error prone. The *Package Manager Resolver* component of
 | ||
| this plugin integrates with [PM](https://docs.unity3d.com/Manual/Packages.html)
 | ||
| to provide a way to auto-install PM package registries when a `.unitypackage` is
 | ||
| installed which allows plugin maintainers to ship a `.unitypackage` that can
 | ||
| provide access to their own PM registry server to make it easier for developers
 | ||
| to manage their plugins.
 | ||
| 
 | ||
| ### Unity Plugin Version Management
 | ||
| 
 | ||
| Finally, the *Version Handler* component of this plugin simplifies the process
 | ||
| of managing transitive dependencies of Unity plugins and each plugin's upgrade
 | ||
| process.
 | ||
| 
 | ||
| For example, without the Version Handler plugin, if:
 | ||
| 
 | ||
| *   Unity plugin `SomePlugin` includes `EDM4U` plugin at version 1.1.
 | ||
| *   Unity plugin `SomeOtherPlugin` includes `EDM4U` plugin at version 1.2.
 | ||
| 
 | ||
| The version of `EDM4U` included in the developer's project depends upon the
 | ||
| order the developer imports `SomePlugin` or `SomeOtherPlugin`.
 | ||
| 
 | ||
| This results in:
 | ||
| 
 | ||
| *   `EDM4U` at version 1.2, if `SomePlugin` is imported then `SomeOtherPlugin`
 | ||
|     is imported.
 | ||
| *   `EDM4U` at version 1.1, if `SomeOtherPlugin` is imported then `SomePlugin`
 | ||
|     is imported.
 | ||
| 
 | ||
| The Version Handler solves the problem of managing transitive dependencies by:
 | ||
| 
 | ||
| *   Specifying a set of packaging requirements that enable a plugin at different
 | ||
|     versions to be imported into a Unity project.
 | ||
| *   Providing activation logic that selects the latest version of a plugin
 | ||
|     within a project.
 | ||
| 
 | ||
| When using the Version Handler to manage `EDM4U` included in `SomePlugin` and
 | ||
| `SomeOtherPlugin`, from the prior example, version 1.2 will always be the
 | ||
| version activated in a developer's Unity project.
 | ||
| 
 | ||
| Plugin creators are encouraged to adopt this library to ease integration for
 | ||
| their customers. For more information about integrating EDM4U into your own
 | ||
| plugin, see the [Plugin Redistribution](#plugin-redistribution) section of this
 | ||
| document.
 | ||
| 
 | ||
| ## Analytics
 | ||
| 
 | ||
| The External Dependency Manager for Unity plugin by default logs usage to Google
 | ||
| Analytics. The purpose of the logging is to quantitatively measure the usage of
 | ||
| functionality, to gather reports on integration failures and to inform future
 | ||
| improvements to the developer experience of the External Dependency Manager
 | ||
| plugin. Note that the analytics collected are limited to the scope of the EDM4U
 | ||
| plugin’s usage.
 | ||
| 
 | ||
| For details of what is logged, please refer to the usage of
 | ||
| `EditorMeasurement.Report()` in the source code.
 | ||
| 
 | ||
| ## Plugin Redistribution
 | ||
| 
 | ||
| If you are a package maintainer and your package depends on EDM4U, it is highly
 | ||
| recommended to use the UPM format and add EDM4U as a dependency. If you must
 | ||
| include it in your `.unitypackage`, redistributing `EDM4U` inside your own
 | ||
| plugin might ease the integration process for your users.
 | ||
| 
 | ||
| If you wish to redistribute `EDM4U` inside your plugin, you **must** follow
 | ||
| these steps when importing the `external-dependency-manager-*.unitypackage`, and
 | ||
| when exporting your own plugin package:
 | ||
| 
 | ||
| 1.  Import the `external-dependency-manager-*.unitypackage` into your plugin
 | ||
|     project by
 | ||
|     [running Unity from the command line](https://docs.unity3d.com/Manual/CommandLineArguments.html),
 | ||
|     ensuring that you add the `-gvh_disable` option.
 | ||
| 1.  Export your plugin by
 | ||
|     [running Unity from the command line](https://docs.unity3d.com/Manual/CommandLineArguments.html),
 | ||
|     ensuring that you:
 | ||
|     -   Include the contents of the `Assets/PlayServicesResolver` and
 | ||
|         `Assets/ExternalDependencyManager` directory.
 | ||
|     -   Add the `-gvh_disable` option.
 | ||
| 
 | ||
| You **must** specify the `-gvh_disable` option in order for the Version Handler
 | ||
| to work correctly!
 | ||
| 
 | ||
| For example, the following command will import the
 | ||
| `external-dependency-manager-1.2.46.0.unitypackage` into the project
 | ||
| `MyPluginProject` and export the entire Assets folder to
 | ||
| `MyPlugin.unitypackage`:
 | ||
| 
 | ||
| ```shell
 | ||
| Unity -gvh_disable \
 | ||
|       -batchmode \
 | ||
|       -importPackage external-dependency-manager-1.2.46.0.unitypackage \
 | ||
|       -projectPath MyPluginProject \
 | ||
|       -exportPackage Assets MyPlugin.unitypackage \
 | ||
|       -quit
 | ||
| ```
 | ||
| 
 | ||
| ### Background
 | ||
| 
 | ||
| The *Version Handler* component relies upon deferring the load of editor DLLs so
 | ||
| that it can run first and determine the latest version of a plugin component to
 | ||
| activate. The build of `EDM4U` plugin has Unity asset metadata that is
 | ||
| configured so that the editor components are not initially enabled when it's
 | ||
| imported into a Unity project. To maintain this configuration when importing the
 | ||
| `external-dependency-manager.unitypackage` into a Unity plugin project, you
 | ||
| *must* specify the command line option `-gvh_disable` which will prevent the
 | ||
| Version Handler component from running and changing the Unity asset metadata.
 | ||
| 
 | ||
| ## Building from Source
 | ||
| 
 | ||
| To build this plugin from source you need the following tools installed: * Unity
 | ||
| 2021 and below (with iOS and Android modules installed) * Java 11
 | ||
| 
 | ||
| You can build the plugin by running the following from your shell (Linux / OSX):
 | ||
| 
 | ||
| ```shell
 | ||
| ./gradlew build
 | ||
| 
 | ||
| ```
 | ||
| 
 | ||
| or Windows:
 | ||
| 
 | ||
| ```shell
 | ||
| ./gradlew.bat build
 | ||
| ```
 | ||
| 
 | ||
| If Java 11 is not your default Java command, add
 | ||
| `-Dorg.gradle.java.home=<PATH_TO_JAVA_HOME>` to the command above.
 | ||
| 
 | ||
| ## Testing
 | ||
| 
 | ||
| You can run the tests by running the following from your shell (Linux / OSX):
 | ||
| 
 | ||
| ```shell
 | ||
| ./gradlew test
 | ||
| ```
 | ||
| 
 | ||
| or Windows:
 | ||
| 
 | ||
| ```shell
 | ||
| ./gradlew.bat test
 | ||
| ```
 | ||
| 
 | ||
| The following properties can be set to narrow down the tests to run or change
 | ||
| the test run behavior.
 | ||
| 
 | ||
| *   `INTERACTIVE_MODE_TESTS_ENABLED` - Default to `1`. Set to `1` to enable
 | ||
|     interactive mode tests, which requires GPU on the machine. Otherwise, only
 | ||
|     run tests in the batch mode.
 | ||
| *   `INCLUDE_TEST_TYPES` - Default to empty string, which means to include every
 | ||
|     type of the test. To narrow down the types of test to run, set this
 | ||
|     properties with a list of case-insensitive type strings separated by comma.
 | ||
|     For instance, `-PINCLUDE_TEST_TYPES="Python,NUnit"` means to include only
 | ||
|     Python tests and NUnit tests. See `TestTypeEnum` in `build.gradle` for
 | ||
|     available options.
 | ||
| *   `EXCLUDE_TEST_TYPES` - Default to empty string, which means to exclude none.
 | ||
|     To add types of tests to exclude, set this properties with a list of
 | ||
|     case-insensitive type strings separated by comma. For instance,
 | ||
|     `-PEXCLUDE_TEST_TYPES="Python,NUnit"` means to exclude Python tests and
 | ||
|     NUnit tests. See `TestTypeEnum` in `build.gradle` for available options.
 | ||
| *   `INCLUDE_TEST_MODULES` - Default to empty string, which means to include the
 | ||
|     tests for every modules. To narrow down modules to test, set this properties
 | ||
|     with a list of case-insensitive module strings separated by comma. For
 | ||
|     instance, `-PINCLUDE_TEST_MODULES="Tool,AndroidResolver"` means to run tests
 | ||
|     for tools and Android Resolver only. See `TestModuleEnum` in `build.gradle`
 | ||
|     for available options.
 | ||
| *   `EXCLUDE_TEST_MODULES` - Default to empty string, which means to exclude
 | ||
|     none. To add modules to exclude, set this properties with a list of
 | ||
|     case-insensitive module strings separated by comma. For instance,
 | ||
|     `-PEXCLUDE_TEST_MODULES="Tool,AndroidResolver"` means to run tests for any
 | ||
|     modules other than tools and Android Resolver. See `TestModuleEnum` in
 | ||
|     `build.gradle` for available options.
 | ||
| *   `EXCLUDE_TESTS` - Default to empty string, which means to exclude none. To
 | ||
|     add tests to exclude, set this properties with a list of case-insensitive
 | ||
|     test names separated by comma. For instance,
 | ||
|     `-PEXCLUDE_TESTS="testGenGuids,testDownloadArtifacts"` means to run tests
 | ||
|     except the tests with name of `testGenGuids` and `testDownloadArtifacts`.
 | ||
| *   `CONTINUE_ON_FAIL_FOR_TESTS_ENABLED` - Default to `1`. Set to `1` to
 | ||
|     continue running the next test when the current one fails. Otherwise, the
 | ||
|     build script stops whenever any test fails.
 | ||
| 
 | ||
| For instance, by running the following command, it only runs the Unity
 | ||
| integration tests that does not requires GPU, but exclude tests for Android
 | ||
| Resolver module and iOS Resolver module.
 | ||
| 
 | ||
| ```shell
 | ||
| ./gradlew test \
 | ||
|   -PINTERACTIVE_MODE_TESTS_ENABLED=0 \
 | ||
|   -PINCLUDE_TEST_TYPES="Integration" \
 | ||
|   -PEXCLUDE_TEST_MODULES="AndroidResolver,iOSResolver"
 | ||
| ```
 | ||
| 
 | ||
| ## Releasing
 | ||
| 
 | ||
| Each time a new build of this plugin is checked into the source tree you need to
 | ||
| do the following:
 | ||
| 
 | ||
| *   Bump the plugin version variable `pluginVersion` in `build.gradle`
 | ||
| *   Update `CHANGELOG.md` with the new version number and changes included in
 | ||
|     the release.
 | ||
| *   Build the release using `./gradlew release` which performs the following:
 | ||
|     *   Updates `external-dependency-manager-*.unitypackage`
 | ||
|     *   Copies the unpacked plugin to the `exploded` directory.
 | ||
|     *   Updates template metadata files in the `plugin` directory. The GUIDs of
 | ||
|         all asset metadata is modified due to the version number change. Each
 | ||
|         file within the plugin is versioned to allow multiple versions of the
 | ||
|         plugin to be imported into a Unity project which allows the most recent
 | ||
|         version to be activated by the Version Handler component.
 | ||
| *   Create release commit using `./gradlew gitCreateReleaseCommit` which
 | ||
|     performs `git commit -a -m "description from CHANGELOG.md"`
 | ||
| *   Once the release commit is merge, tag the release using `./gradlew
 | ||
|     gitTagRelease` which performs the following:
 | ||
|     *   `git tag -a pluginVersion -m "version RELEASE"` to tag the release.
 | ||
| *   Update tags on remote branch using `git push --tag REMOTE HEAD:master`
 |