RevenueCat now supports Unity Package Manager
To make our Unity SDK even easier to use, it's now available using UPM — but the asset package is still available.
At RevenueCat, we believe that making our SDKs as easy to use as possible is of paramount importance. Developers need to have a great experience and be able to start earning money without any of the headaches associated with the stores.
One of the first things that developers need to do is to install our SDK in their app. Each platform has different systems. For Unity, our SDK has always been distributed as an asset package (a .unitypackage file). Now, we are glad to announce that, starting on version 4.6.4 of our SDK, we have added support for Unity Package Manager (UPM) and have set it as our preferred distribution system.
We are using OpenUPM as the registry for our dependency. You can find more details on how to install our SDK using UPM in our installation docs.
Using an asset package vs Unity Package Manager
First, we should understand the differences between both distribution systems.
Asset package
To summarize, asset packages are compressed files containing Unity assets, such as images, textures or scripts. This container can be imported into your Unity project, which will add all the assets to your assets directory. This is a relatively simple import process but it has its downsides, like:
- No version management support. A .unitypackage doesn’t have a concept of version so it’s more difficult to keep track of the current version, update the dependency, and other common tasks.
- No dependency management support. It doesn’t provide any system to set up a chain of dependencies if you depend on other packages.
- Dependencies live alongside other assets. This means developers can accidentally modify the dependency in ways unintended by the authors.
The asset package file for RevenueCat can be downloaded from our Unity SDK Github repo releases page and you can just import it into your project, which looks like:
Unity Package Manager
Unity Package Manager is a system released by Unity back in 2017. It’s based on npm and it allows the distribution of packages through a package registry, where these dependencies are published.
This distribution system addresses the downsides of .unitypackages by providing version management support, dependency management support, and separating the dependencies from the rest of your project (among other advantages).
Package maintainers can distribute packages using options such as npm’s registry, creating their own registry, or using OpenUPM’s registry. Then, users of a package just need to add the registry to their project which will allow them to see and install all the packages there. You can find more details on how to do this on our Unity SDK installation docs.
At RevenueCat, we publish our package using the OpenUPM registry. You can add this registry to your project in your Project Settings > Package Manager section.
As you can see, an asset package has the advantage of being simpler to import, but has several downsides when you want to distribute a software package — downsides that UPM manages to solve. At RevenueCat, we offer both distribution systems, so developers can import our SDK as they prefer — though we recommend using UPM.
The migration process
We’ve been distributing our Unity SDK as an asset package for a while, so now we will explain the process we had to follow to support UPM. We followed Unity’s documented process.
Adapting our code to support UPM
We wanted to make sure developers could use our SDK as a UPM package but we also wanted to allow them to continue using it as an asset package if they preferred. First of all, we had to add a few things to make our SDK compatible with UPM:
- First, we added the package manifest with the information of our package, like version number and changelog links.
- We added some assembly definition files to the folders containing the scripts of our SDK. This allows developers to access the scripts in our package in a much more organized way.
That’s it! Now we could start distributing our package. Pretty easy right? Well, not quite yet. We had two more problems to solve:
- Our SDK’s dependency, Google’s External Dependencies Manager for Unity (EDM4U), is not available through UPM.
- We want to make sure we test both distribution systems to avoid any regressions. This was not straightforward.
Google’s External Dependencies Manager for Unity (EDM4U)
Our SDK has a dependency with Google’s External Dependencies Manager for Unity (EDM4U). This is used to resolve our SDK dependencies with our iOS and Android SDKs on each respective platform.
Google officially only supports distributing this dependency as an asset package and they don’t distribute it officially in any package registry available through UPM. When we distribute our SDK as an asset package, we also include the EDM4U dependency within the package but adding this dependency through UPM was trickier due to the lack of UPM support from the library.
For now, we are asking developers to download the EDM4U asset package and add it to their project when they use our SDK through UPM. This can have problems if the specific EDM4U version doesn’t work with our SDK. We plan to add some functionality to the Unity Editor to download this library and make sure it matches our SDK.
Testing both distribution systems
Part of our engineering culture is to make sure our code is reliable, and automated tests are an intrinsic part to make sure that’s true. Since we are supporting two distribution systems, we need to make sure both work as expected.
Some of the things we need to test are making sure our SDK can be imported successfully as an asset package and through UPM, and making sure our API is accessible and functional when using either system. In our Unity SDK, we have what we call API tests. These tests make sure the API of our SDK can’t be changed by accident. Since we wanted to offer both distribution systems, we had to make sure both systems had reliable API tests.
In order to run API tests, we have to add our package to a Unity project, call each method in our API and make sure the project compiles correctly. Additionally, to create an asset package, we need to add the assets that belong to the package to a unity project and export it from that project. That means:
- We need a Unity project in order to export the asset package.
- We need a Unity project to run API tests with a project that imports our SDK as an asset package.
- We need a Unity project to run API tests with a project that imports our SDK from UPM.
Before adding UPM support, we already had the first two projects. Note that we can’t reuse the same project easily since adding the same sources multiple times to the same project would cause collision errors in Unity.
After adding UPM support we had to either create a new project that used UPM or reuse the existing projects. Additionally, since we recommend using UPM, we wanted our main development Unity project to use UPM to import the SDK, to make sure we were using the same as developers use.
We decided to reuse the existing projects to avoid creating extra unnecessary projects. Currently our setup consists of two projects:
- Subtester
- This is the project we use to test our SDK.
- It imports our SDK using a local package through UPM (this means we get access to the latest changes in the SDK immediately).
- We run automated API tests in this project.
- We use it to export the asset package to be used by the other project.
- IntegrationTests
- It imports our SDK using an asset package generated from Subtester.
- We run automated API tests in this project.
The Subtester project does a lot of things. This project uses the SDK through UPM, so the SDK sources are not part of the assets. The issue is that in order to be able to export an asset package from this project to be able to distribute it as a unitypackage file, the sources need to be part of the assets of the project. In order to do this, we created a script that runs during our automation processes. This script:
- Adds the SDK sources as assets of the project.
- Removes the UPM dependency with our SDK. This is necessary, otherwise the project won’t compile since it will have duplicated sources (from the assets and from UPM).
- Downloads the latest version of EDM4U and adds it as assets of the project.
- Finally, it creates an asset package with our SDK and EDM4U included.
The IntegrationTests project is pretty straightforward. It’s a simple project that includes our API tests. When running automated tests, we import the asset package generated from Subtester beforehand and then compile iOS and Android projects that include these API tests.
Distributing our package: OpenUPM vs npm registry
Another decision we had to make when adding UPM support was where to publish our package. Our investigation led us to two popular registries: npm’s official registry or OpenUPM’s registry. Both are very popular but we decided to publish in OpenUPM for now. Reasons for that are:
- OpenUPM has automations to automatically detect new versions of the SDK released in Github, so we can avoid adding automations to publish ourselves.
- OpenUPM is oriented towards unity developers, whereas npmjs is more broad.
We might revisit this decision in the future or maybe even publish to both.
Have any feedback?
In this post we described the process we followed in order to add UPM support to our SDK. We are excited for you to try it out! Please let us know if you have any feedback as it greatly helps us to improve our SDKs.
You might also like
- Blog post
Implementing in-app purchases and monetizing your Roku app: A step-by-step guide
A comprehensive guide to implementing and monetizing your Roku channel, from choosing the right strategy to technical tips and integration best practices.
- Blog post
How we built the RevenueCat SDK for Kotlin Multiplatform
Explore the architecture and key decisions behind building the RevenueCat Kotlin Multiplatform SDK, designed to streamline in-app purchases across platforms.
- Blog post
Inside RevenueCat’s engineering strategy: Scaling beyond 32,000+ apps
The strategies and principles that guide our global team to build reliable, developer-loved software