The External Dependency Manager for Unity (EDM4U)
(formerly Play Services Resolver / Jar Resolver) is intended to be used by any
Unity plugin that requires:
Updated releases are available on
GitHub
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:
EDM provides solutions for each of these problems.
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 importsSomeOtherPlugin that includes the same libraries (potentially at different
versions) in SomeOtherPlugin/Android/, the developer using SomePlugin andSomeOtherPlugin will see an error when building for Android that can be hard
to interpret.
Using the Android Resolver to manage Android library dependencies:
The iOS Resolver component of this plugin integrates with
CocoaPods 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.
The Package Manager
(PM) makes use of NPM 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 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.
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:
SomePlugin includes EDM4U plugin atSomeOtherPlugin includes EDM4UThe 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 SomeOtherPluginEDM4U at version 1.1, if SomeOtherPlugin is imported thenSomePlugin is imported.The Version Handler solves the problem of managing transitive dependencies by:
When using the Version Handler to manage EDM4U included in SomePlugin andSomeOtherPlugin, 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
section of this document.
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 ofEditorMeasurement.Report() in the source code.
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
support was added to the Package Manager.
Before you import EDM4U into your plugin project, you first
need to consider whether you intend to redistribute EDM4U
along with your own plugin.
If you're a plugin maintainer, redistributing EDM4U inside your own plugin
will ease the integration process for your users, by resolving dependency
conflicts between your plugin and other plugins in a user's project.
If you wish to redistribute EDM4U inside your plugin,
you must follow these steps when importing theexternal-dependency-manager-*.unitypackage, and when exporting your own plugin
package:
external-dependency-manager-*.unitypackage into your plugin-gvh_disable option.Assets/PlayServicesResolver andAssets/ExternalDependencyManager directory.-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 theexternal-dependency-manager-1.2.46.0.unitypackage into the projectMyPluginProject and export the entire Assets folder toMyPlugin.unitypackage:
Unity -gvh_disable \
-batchmode \
-importPackage external-dependency-manager-1.2.46.0.unitypackage \
-projectPath MyPluginProject \
-exportPackage Assets MyPlugin.unitypackage \
-quit
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.
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.
Add the external-dependency-manager-*.unitypackage to your plugin
project (assuming you are developing a plugin). If you are redistributing
EDM4U with your plugin, you must follow the
import steps in the Getting Started section!
Copy and rename the
SampleDependencies.xml
file into your plugin and add the dependencies your plugin requires.
The XML file just needs to be under an Editor directory and match the
name *Dependencies.xml. For example,
MyPlugin/Editor/MyPluginDependencies.xml.
Follow the steps in the Getting Started
section when you are exporting your plugin package.
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:
<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:
9.8.09.8.+ would match 9.8.0, 9.8.1 etc. choosing the mostLATEST or +. We do not recommend using thisThe 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:
<dependencies>
<androidPackages>
<androidPackage spec="com.google.api-client:google-api-client-android:1.22.0" />
</androidPackages>
</dependencies>
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 theAssets > External Dependency Manager > Android Resolver > Settings menu.
Manual resolution can be performed using the following menu options:
Assets > External Dependency Manager > Android Resolver > ResolveAssets > External Dependency Manager > Android Resolver > Force ResolveResolved packages are tracked via asset labels by the Android Resolver.
They can easily be deleted using theAssets > External Dependency Manager > Android Resolver > Delete Resolved Libraries
menu item.
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 thebundleID.
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.
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 theAssets > 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.
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 theAssets > External Dependency Manager > Android Resolver > Settings menu.
Using the default resolution strategy, the Android resolver executes the
following operations:
Plugins/Android from the project.*Dependencies.xml files.download_artifacts.gradle with Gradle to resolve conflicts and,applicationId in thePlugins/Android so they will be included whenUnity 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:
Plugins/Android from the project and remove sections delimited with// Android Resolver * Start and // Android Resolver * End lines.*Dependencies.xml files..srcaar files in the build to .aar and exclude them frommainTemplate.gradle will be patched to include them instead from theirmainTemplate.gradle at the.*apply plugin: 'com\.android\.(application|library)'.* or the section// Android Resolver Repos Start.// Android Resolver Repos Start and// Android Resolver Repos End should be placed in the global scopedependencies section.mainTemplate.gradle at the line matching the pattern ***DEPS*** or// Android Resolver Dependencies Start.// Android Resolver Dependencies Start and// Android Resolver Dependencies End should be placed in thedependencies section.mainTemplate.gradleandroid +{ or the section starting at// Android Resolver Exclusions Start.// Android Resolver Exclusions Start and// Android Resolver Exclusions End should be placed in the globalandroid section.The Android Resolver creates theProjectSettings/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.
It's possible to display the set of dependencies the Android Resolver
would download and process in your project via theAssets > External Dependency Manager > Android Resolver > Display Libraries
menu item.
The iOS resolver component of this plugin manages
CocoaPods. 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.
Add the external-dependency-manager-*.unitypackage to your plugin
project (assuming you are developing a plugin). If you are redistributing
EDM4U with your plugin, you must follow the
import steps in the Getting Started section!
Copy and rename the
SampleDependencies.xml
file into your plugin and add the dependencies your plugin requires.
The XML file just needs to be under an Editor directory and match the
name *Dependencies.xml. For example,
MyPlugin/Editor/MyPluginDependencies.xml.
Follow the steps in the Getting Started
section when you are exporting your plugin package.
For example, to add the AdMob pod, version 7.0 or greater with bitcode enabled:
<dependencies>
<iosPods>
<iosPod name="Google-Mobile-Ads-SDK" version="~> 7.0" bitcodeEnabled="true"
minTargetSdk="6.0" addToAllTargets="false" />
</iosPods>
</dependencies>
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 theAssets > External Dependency Manager > iOS Resolver > Settings menu.
In order to modify the generated Podfile you can create a script like this:
```
using System.IO;
public class PostProcessIOS : MonoBehaviour {
[PostProcessBuildAttribute(45)]//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)
private static void PostProcessBuild_iOS(BuildTarget target, string buildPath)
{
if (target == BuildTarget.iOS)
{
using (StreamWriter sw = File.AppendText(buildPath + "/Podfile"))
{
//in this example I'm adding an app extension
sw.WriteLine("\ntarget 'NSExtension' do\n pod 'Firebase/Messaging', '6.6.0'\nend");
}
}
}
```
Adding registries to the
Package Manager
(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.
Add the external-dependency-manager-*.unitypackage to your plugin
project (assuming you are developing a plugin). If you are redistributing
EDM4U with your plugin, you must follow the
import steps in the Getting Started section!
Copy and rename the
SampleRegistries.xml
file into your plugin and add the registries your plugin requires.
The XML file just needs to be under an Editor directory and match the
name *Registries.xml or labeled with gumpr_registries. For example,
MyPlugin/Editor/MyPluginRegistries.xml.
Follow the steps in the Getting Started
section when you are exporting your plugin package.
For example, to add a registry for plugins in the scope com.coolstuff:
<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.
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 toAssets > External Dependency Manager > Package Manager Resolver > Remove Registries will prompt the user with a window which allows them toAssets > External Dependency Manager > Package Manager Resolver > Modify Registries will prompt the user with a window which allows them toPMR 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 describesversions.VERSION.keyword list) that maps the PM packagevh-name:VERSION_HANDLER_MANIFEST_NAME where VERSION_HANDLER_MANIFEST_NAME.unitypackage. Forgvhp_manifestname asset labelWhen using the Assets > External Dependency Manager > Package Manager Resolver > Migrate Packages menu option, PMR then
will:
Apply button.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 registryPrompt to add package registries will cause a developer to be promptedPrompt to migrate packages will cause a developer to be promptedAssets directory to PM packages.Enable Analytics Reporting when enabled, reports the use of the pluginVerbose logging when enabled prints debug information to the consoleThe Version Handler component of this plugin manages:
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.
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 theAssets > External Dependency Manager > Version Handler > Settings menu.
If version management is disabled, it's possible to check managed assets
manually using theAssets > External Dependency Manager > Version Handler > Update menu option.
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.
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.
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 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.
Some behavior of the Version Handler can be configured via theAssets > External Dependency Manager > Version Handler > Settings menu
option.
Enable version management controls whether the plugin should automaticallyAssets > External Dependency Manager > Version Handler > Update.Rename to canonical filenames is a legacy option that will rename files toPrompt for obsolete file deletion enables the display of a window whenAllow disabling files via renaming controls whether obsolete or disabledmyfilename_DISABLED.Enable Analytics Reporting enables / disables usage reporting to pluginVerbose logging enables very noisy log output that is useful forUse project settings saves settings for the plugin in the project ratherThe Version Handler employs a couple of methods for managing version
selection, upgrade and removal of plugins.
myfile.txt would be `myfile_version-x.y.z.txt).Unity plugins can be managed by the Version Handler using the following steps:
gvh asset label to each asset (file) you want Version Handlergvh_version-VERSION label to each asset where VERSION is thegvhp_exportpath-PATH label to each asset where PATH is the.unitypackage is created. This isgvh_targets-editor label to each editor DLL in youreditor as a target platform for the DLL.MY_UNIQUE_PLUGIN_NAME_VERSION.txtgvh_manifest label to the asset to indicate this file isgvhp_manifestname-NAME label to your manifest file[0-9]+[a-zA-Z -]' where a leading integer will set the priority of the name where0` is the highest priorityIf you follow these steps:
To build this plugin from source you need the following tools installed:
* Unity (with iOS and Android modules installed)
You can build the plugin by running the following from your shell
(Linux / OSX):
./gradlew build
or Windows:
./gradlew.bat build
Each time a new build of this plugin is checked into the source tree you
need to do the following:
pluginVersion in build.gradleCHANGELOG.md with the new version number and changes included in./gradlew release which performs the following:
external-dependency-manager-*.unitypackageexploded directory.plugin directory../gradlew gitCreateReleaseCommit whichgit commit -a -m "description from CHANGELOG.md"./gradlew gitTagRelease which performs the following:
git tag -a pluginVersion -m "version RELEASE" to tag the release.git push --tag REMOTE HEAD:master