TL;DR: Unity has (imo) poorly thought out rules that disallow uploading executables, Microsoft consistently (but slowly) flags my workaround as a virus, leaving me with no solution to ship my tool.
Chapter 1: Creating Alacrity
I’ve always wanted to use web tech to make UIs for games. I’m good at it, it’s easy, and there are a ton of resources available. So, last year, I did a ton of research about how I could make it happen, and ended up with the Chromium Embedded Framework (CEF). It’s an amazing piece of open source software, and I was fairly quickly able to get it up and running in a prototype.
I figured out early on that one of the important parts of getting CEF to work within Unity was to separate out the binary running CEF from the game itself, and have them communicate via IPC. This was essential because CEF forks its own process many times to run different parts of the browser (e.g. GPU process, network process, etc), and we can’t easily do that while in the Unity Editor or by using the game executable itself. CEF also doesn’t allow you to keep the main process alive after stopping CEF, meaning we couldn’t just use a separate binary for the subprocesses, but we needed one for the entire operation. The fact that we need a separate binary is important later in this story.
This way, we’d be able to freely start and stop the CEF Binary process without having to start/stop the Unity Process (be it the game binary, or the Editor). Unity wouldn’t even know anything about CEF, it’d just have a simple protocol to communicate with the CEF Binary process, which would also make it easy to swap out CEF if desired down the road.
While I was able to get a prototype up and running fairly quickly, it didn’t quite perform as well as I wanted. Why was I able to get buttery smooth 144fps animations in my Chrome browser, but when running CEF using off-screen rendering, it just felt really choppy, as if it wasn’t even 60fps? After much more research and forum-sleuthing, I learned that I could use shared textures to get the GPU to write directly into my game engine, avoiding costly CPU frame copies.
After much more hard work and research, I figured out how to patch and build CEF & Chromium in order to get it working exactly how I wanted it, with shared textures and message posting between Javascript and my game. I was finally able to make game UIs with web tech, and they even felt native. This seemed to me like a great tool to put up on the official Unity Asset Store, so that others could benefit from it, and I could make some money for the time I spent on the project.
Chapter 2: Submitting to Unity
Seemed like it would be pretty easy to get this software in commercial shape. I tidied up the code, added documentation, ensured it worked in various production circumstances, and go ready to submit it to the Unity Asset Store. I’ve done this before with other storefronts, like the Chrome Web Store, Google Play store, etc, so I felt confident that it should be fairly straightforward.
Boy, was I wrong.
First, when “validating” my asset using Unity’s validation tool, it complained that there was a .exe
file in the submission. It told me that I couldn’t include .exe
files, and I should instead host them on my website and tell people to download them after downloading my asset. I personally thought this would be a horrible user experience, and made very little sense, so I thought it may be an acceptable compromise to rename the file to a different extension (.exe.mv
), and have my code detect and move the file to execute it. I figured if they still weren’t happy with that, then I’d just host it myself and accept the poor experience.
Now that my asset was passing validation, I submitted the asset. Unity estimated it would take 20 business days for them to review my asset. I thought that was pretty long, but fine - a calendar month was acceptable.
Two and a half calendar months later, they rejected the asset.
Your package must not contain executables, installer programs, or other applications (.exe or other). (https://assetstore.unity.com/publishing/submission-guidelines, Section 1.5.a)
Crap. I guess they found the renamed .exe.mv
file. No problem, I’ll remove it and just host it myself, like their own tool suggested to do.
Wait a minute though, reading the section 1.5a they cited shows this:
1.5.a Until further notice, the Asset Store is not accepting any submissions that include executables (for example, .exe, .apk, or other executables), embedded inside the package or as separate dependencies located in other websites.
So I can’t even host this as a separate dependency on my own site? Is Unity essentially telling me I can’t sell this asset? But why? Interestingly, Unity does allow you to include .dll
files in your submission. So, I had another idea: what if I embed the .exe
file inside of a .dll
file, have the dll extract it and run it, and then clean it up afterwards? So that’s exactly what I did.
I resubmitted the package with a dll that embedded the required binary, extracted it upon use and cleaned it up afterwards. Unity said it would take 3 business days to review it this time.
Chapter 3: Microsoft
Unity’s estimate was accurate this time. 3 business days later, they approved my package for sale. I made a few posts about it and waited.
After making a few sales, I decided I should try to ramp up my marketing efforts. I loaded up the project and started working on another demo of what you could do with the tool.
After a few uses of my own tool (which I had successfully used many times prior, during its development), I started getting an error:
Operation did not complete successfully because the file contains a virus or potentially unwanted software
What the hell? What virus? My own software is a virus? Windows was preventing me from running the software that I wrote! I was able to get around it eventually by adding some bypasses in Windows Defender, but I knew this would essentially kill my tool, as no-one would be able to actually ship their game if their users could only play it by marking it as safe in Windows Defender.
Time for more research. What could be flagging this? What’s going on here?
The first thing I found was that Microsoft has a website where you can report false-positives. So I uploaded my .dll
file that was being automatically deleted by Windows Defender as a false positive, explaining what it was and why it worked that way.
I figured it would take a long time to get a reply from Microsoft, so in the meantime I started investigating what could be going on. I went back to my old process of having the .exe
just as a regular file and executing it, instead of embedding it in a dll, but it was still being flagged. I realized that if I changed the dll slightly, it stopped getting flagged for a few runs, but then quickly got picked back up again.
My strong suspicion was that Windows Defender just didn’t like the fact that it was embedding a binary .exe
file inside of a dll and executing it. So I took it out, modified it (so that Windows Defender wouldn’t flag it), and it seemed to be working. After many attempts, it seemed like it would be OK, it wasn’t being flagged. But I’ve already submitted something just like this to Unity and they rejected it for including “executable” files. This time, instead of naming the file Alacrity.exe.mv
to get around automated detection, I renamed it to Alacrity.mv
, so that if someone manually looked through the list of included files they also wouldn’t know it was a binary file. I’d already sold some copies of the asset and I really wanted to ensure that the product wouldn’t be showing up as a virus for those users, so I quickly got this working and resubmitted it to Unity, who once again said it would take 3 business days to review.
The same day, the false-positive report I sent Microsoft was updated:
At this time, the submitted files do not meet our criteria for malware or potentially unwanted applications. The detection has been removed.
That’s a very fast response from Microsoft, kudos to them. Running the command they gave me to clear the Defender cache to seemed to work at first too, Windows Defender wasn’t flagging it anymore.
The next day, Unity also approved my updated package. Seemed like we should be in the clear now, both the old and new versions should be fine, or so I thought.
So, I decided to spend the day creating the video that I had wanted to make previously to market the asset, assuming all was fixed now. However, while working on the video, the binary started getting flagged again by Windows Defender. Seems like there’s something in the binary it doesn’t like, and even submitting it and having them claim it’s fine isn’t enough. Perhaps because I had made some minor changes when I submitted it to Unity. Perhaps because we’re renaming a .mv
file to a .exe
and executing it. It’s not going to be sustainable if I have to resubmit the executable to Microsoft every single time I make a change, and there’s not much information I can use to figure out what’s going on.
Chapter 4: Defeat
I can make wild guesses at the problem. Everything did seem to work fine when I just had a .exe
file and ran it like normal. But Unity won’t let me do that, so I’m stuck with this weird renaming of a file with a “fake” extension. Maybe that renaming is what makes Windows eventually suspicious (even though it seems to work fine for quite a while).
So we’re stuck. Unity says I cannot include .exe
files, even if those files are separately downloaded by users of the tool. Microsoft won’t let me ship my workaround I found to rename the file. Guess this potentially useful software is dead.
It seems this is what making software has become. It’s impossible not to depend on a big faceless platform, be it Apple, Google, Microsoft, or countless others, where you can’t get real support when you run into issues. It seems nearly impossible to compete anymore as an individual.
I don’t really know the point of this post. Maybe there’s more we can do to support smaller software, but I don’t really know how to get there. I do know that if you work at Microsoft, Google, Apple, Unity, etc - you have a lot of power to make it better for the little guy. Please use your voice to help.
If anyone has other ideas for how I can make this work, please let me know!