First published on MSDN on Jun 26, 2018
The playground is the following: We develop an app or a game using Unity and may be with an old version like Unity 5.6.5. You would say: "why?" :thinking_face: The answer is that, in the real world, is not always easy to follow the huge rhythm given by Software Editors. The other possible reason is, when we use third party softwares or plugins, we depend on their ability to update to new versions or or using the latest sdks.
So, let’s imagine that we build a standard EXE from a Unity project. We target Windows. The executable is packaged using Desktop Bridge for Windows 10 and we would like to use the Universal Windows Platform (UWP) APIs. Is it even possible? How can we do?
➡ Just keep calm! Read :books: and code :man_technologist:
Just a side note: This article is about a "Windows executable build from Unity". If you build directly for UWP in Unity, there is no extra work: just code on using the UWP APIs. Here are the details -
https://docs.unity3d.com/Manual/windowsstore-scripts.html
The chosen architecture and steps are:
- A C# .NET dll using the UWP APIs.
- We use this dll as a Unity Plugin and we build the Unity project as a standard Windows executable.
- We package the executable with Desktop Bridge.
1. The C# .NET dll using the Windows APIs
The purpose is to code in C# and expose this dll as a native Unity plugin.
- Create a new C# Windows desktop Class Library project using the full .NET Framework. Name it “dotNETClassLibraryUsingUWPAPIs”.
- Rename the default
class1.cs
in
NotificationHelper.cs
.
- Right click on the
References
node in the
Solution Explorer
for the project and click on
Add Reference…
- Click on the
Browse
item in the vertical menu on the left and on the
Browse
button at the bottom.
The strict minimum in order to be able to call UWP APIs are the following two references. This sample code uses Toast notifications. For using others UWP APIs, referencing other winmd files should be required.
- The first one reference is "
C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.15063.0\Windows.winmd
". Be sure to filter to
All Files (*.*)
in the dialog box.
- The second one is "
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll
"
We need an extra component to make our dll visible as a native plugin for Unity:
- Right click on the project in the
Solution Explorer
and choose
Manage NuGet Packages…
- Search for "dllexport", you will find the
DllExport
package by 3F. Click on the
Install
button.
The next steps are not usual and may change in the future: To really use the package will need to use a command line script. Here is the message we get:
- Click on "
Local version from this package
". Windows Explorer will open the package’ folder with the mentioned script.
- Open a command prompt and execute the
DllExport_Configure.bat
file. You will get a popup. Just check “
Installed
” and click
Apply
.
- Going back to the Visual Studio project and the NuGet Package Manager windows, remove the DllExpert NuGet package. The project's configuration was done by the script we launched.
- To test displaying a Toast notification, use this sample code. Please note that for each method we would like to export and use in Unity, we use
[DllExport(CallingConvention.StdCall)]
.
using System;
using System.Runtime.InteropServices;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
namespace dotNETClassLibraryUsingUWPAPIs
{
class NotificationHelper
{
[DllExport(CallingConvention.StdCall)]
public static string Notify(string toastTitle, string toastContent)
{
try
{
string xml = @"<toast activationType='foreground'>
<visual>
<binding template='ToastGeneric'>
</binding>
</visual>
</toast>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var binding = doc.SelectSingleNode("//binding");
var el = doc.CreateElement("text");
el.InnerText = toastTitle;
binding.AppendChild(el);
el = doc.CreateElement("text");
el.InnerText = toastContent;
binding.AppendChild(el);
var toast = new ToastNotification(doc);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
catch (AggregateException ex)
{
return "Exception:" + ex.ToString() + "exMessage:" + ex.Message;
}
return "Ok";
}
}
}
- The last step is to build your dll using
Release
and
x64
(not Any CPU). If the compilation does not work, try to close and reopen the project before retrying to compile.
- You can then get the dll from the
bin\x64\Release
folder or
bin\x64\Release\x64
(keep it for later)
2. The Unity project using the dll
For testing purpose, I use an old Unity version: 5.6.5. Feel free to use the version you want.
- Create a new project named "UnityEXEApp".
- We use the default scene as is. Save it and name it "ClickScene" for example. We will compile for Windows as "
PC, Mac & Linux Standalone
" and
x86_x64
for
Windows
.
This confirms that nothing is related to UWP for this Unity App ;).
The first action is to add the previously compiled dll as a Unity native plugin:
- Create a new folder inside the
Project
window by right clicking and use
Create
/
New folder
. Name it "Plugins" (this is the mandatory name for using dlls in Unity. The dlls are called plugins).
- Drag and drop the
dotNETClassLibraryUsingUWPAPIs.dll
from the project
bin\Release\x64
folder to the
plugins
folder in the
Project
Unity windows.
You now have the dll inside the plugins folder.
To verify that you have chosen the good dll, the inspector should look like the following (with
Native type
for the dll):
Please note that, because the dll is using .NET 4.6, you will not able to run in Unity. Do not try play the app in Unity without compilation directives.
Let’s add now a C# script for using this dll:
- Click on the
camera
in the
Hierarchy
window and then on
Add Component
in the
Inspector
window. Search for "script".
- Enter the name "ClickToUseDll".
- Double click on the created script. Visual Studio opens it.
In order to be able to use the functions exported by the dll, we need to declare them as external methods.
- In the
ClickToUseDll
class, add the following declaration which corresponds exactly to the method in the C# Dll project.
[DllImport("dotNETClassLibraryUsingUWPAPIs")]
extern static string Notify(string toastTitle, string toastContent);
- To use "DllImport", please add the
System.Runtime.InteropServices
namespace.
using System.Runtime.InteropServices;
- Let’s use the function in the Update method for each mouse click.
void Update()
{
if (Input.GetMouseButtonDown(0))
{
string output = Notify("Toast title",
"Unity toast sent at " + System.DateTime.Now.ToLongTimeString());
}
}
- Build the project for Windows: "
PC, Mac & Linux Standalone
" and
x86_64
. Create a "Builds" folder and name the executable "UnityEXEApp" (If you have a compilation error, please close and reopen Unity before retrying to build the executable).
We now have the binaries inside the Builds folder.
3. The Desktop Bridge packaging
There is one last step which is to package the UnityEXEApp.exe with Desktop Bridge.
- Launch the
Desktop App Converter
app in administrator mode.
- Use the following command line (please adapt the paths of your files and folders and create the
Appx
folder before running the command):
DesktopAppConverter.exe -Installer "C:\_Temp\UWPAPIsUsedFromUnityEXEApp\UnityEXEApp\Builds" -AppExecutable "UnityEXEApp.exe" -Destination "C:\_Temp\UWPAPIsUsedFromUnityEXEApp\UnityEXEApp\Appx" -PackageName "UnityEXEApp" -Publisher "CN=sbovo" -Version "1.0.0.0" -MakeAppx -Sign -Verbose
This command will generate a .APPX package for being able to deploy your app for the Microsoft Store.
In order to test the app, you have to first install the
auto-generated.cer
certificate in the
Trusted People
container for local machine certificates.
Lastly, you can double-click on the .APPX file to install the app and test it!
As usual, all source code is available on the following GitHub repository -
https://github.com/Microsoft/Windows-AppConsult-Samples-DesktopBridge/tree/master/UWPAPIsUsedFro...
Good luck! :smirking_face:
@sbovo
for the :laptop_computer: :video_game: Windows AppConsult team.
--
References