If you’ve followed any of my earlier blog posts, you know that I tend to explore areas like NFC and Bluetooth Low Energy from a BlackBerry 10 developer’s perspective – usually in conjunction with my colleague Martin Woolley.
So you may be wondering why I’m writing about Unity 3D today. Well, if you weren’t already aware, Unity 3D is a phenomenal framework that allows you to develop amazing games on multiple platforms, including BlackBerry 10. What’s more, it contains a very flexible plugin framework that allows you to extend your game’s capabilities down into native capabilities of BlackBerry 10!
So naturally, I wondered if I could add the capability to a Unity 3D game to interact with, say, a Bluetooth Smart device. Imagine influencing gameplay through data streamed from a Heart Rate Monitor worn by the player. (Hold that thought for a bit!)
Because I already know how to interact with Bluetooth Smart devices, it’s just a case of embedding the Bluetooth functionality in a native shared library and plugging it into the Unity 3D framework. I’ll share how to do just that in future blog post.
However, today I’d like to share with you what, as a Unity 3D newbie, I had to do to get to the root-cause of a particularly opaque error I encountered when testing my plugin in and application on a BlackBerry 10 device. I kept on seeing “DllImportException” errors, which suggested that my plugin couldn’t be found by the running application.
Background on Unity 3D Plugins
Unity 3D plugins are basically shared libraries. For example, libBtHrmPlugin.so (my embryonic Bluetooth Low Energy Heart Rate Monitor Plugin) exposes a set of “C” functions something like this:
So, all is looking good and we run the application on the BlackBerry 10 device:
Whoops! Bang! Something went wrong and we see a DllImportException when we look at the log file:
How annoying! So, how do you deal with this issue? Here’s what I’ve found to be a logical set of steps that I’ll outline below:
- Ensure that the plugin is added to the correct path in the Unity 3D project.
- Switch on Mono debugging via the bar-descriptor.xml file to understand what actual file names Mono is attempting to use to locate the shared library.
- Switch on QNX dynamic library logging to understand how the underlying dlopen() service is searching for the shared library.
Ensure that the plugin is in the correct path in the Unity 3D project
This may seem obvious but it caught me out. Your plugin (libBtHrmPlugin.so in my case) needs to go here in your Unity 3D project’s Assets folder. It won’t be included in the project’s “.bar” file as an asset unless it goes here:
As a sanity check, you can check the “.bar” file, which you can find here:
Open the “.bar” file with a tool like “7-zip” and there it is in the “native\lib” folder. So, we verified that the plugin has been included in the “.bar” file as an asset and it will be installed onto the device as party of the application.
Check to see where Mono is looking for the file on the device
When Unity 3D builds a project for BlackBerry 10, it assembles all the project assets in a “StagingArea” folder. Here is where it’s located:
We’re interested in the “bar-descriptor.xml” file that is created by Unity 3D. The part of this file that is of interest to us is the following:
Here, the environment variable LD_LIBRARY_PATH, which determines the search location for shared libraries at run-time for BlackBerry 10 applications, is correctly set to include the “native/lib” path. If we add the following line to the “bar-descriptor.xml”, this will switch on additional logging when Mono tries to locate the shared library at run-time:
Then we need to rebuild the “.bar” file using the command line something like this, using “BlackBerry-nativepackager.bat”, since Unity 3D would just re-create the “bar-descriptor.xml” file if you used the Unity 3D IDE to rebuild the project. Notice we were careful to delete the old “.bar” file since we didn’t want it included in the new one.
If we install this on the device, again using, say, the “blackberry-deploy.bat” command line tool, we can look at the log once again. This time we see something like the following:
What we see now is that Mono is reporting on the various permutations of names that it is attempting to use from the base name of “BtHrmPlugin” to locate the underlying shared library file. Perhaps this is able to shed some light on why we’re seeing a problem? If not, then maybe the next step will help.
Switch on QNX dynamic library logging to see what QNX thinks is happening
We follow exactly the same process as in the previous section but add two additional statements, which are described in the QNX documentation for “dlopen()”, to the “bar-descriptor.xml” file, thus:
When we look at the log file this time, we see a lot of information regarding how the search for the unresolved external references is taking place. We see that the “libBtHrmPlugin.so” shared library is being located correctly in the “native/lib” folder in the application.
If we were to look in more detail, we’d see that the issue was not that the shared library was not found, but rather, there were unresolved external references in the shared library itself, which give rise to the “DllImportException” being reported. The real problem was back in the plugin NDK project itself:
The reference to the external library “libbtapi.so” (Bluetooth API library) was missing from the project’s link step! Remember that we’re building a shared library, and missing external references are quite legitimate at build-time since they would be resolved at run-time, but we still need to identify the external library to the linker when the project is built.
Adding this fixed the problem:
I hope that my own experience has given you some insight into how to logically track down this sort of issue in any Unity 3D plugin you may write, and how it could be used in a more general context to find the root cause of unresolved references in your application.
I’ll be following up this post with one on the Unity 3D Bluetooth Low Energy Heart Rate Monitor plugin I’m currently writing, so watch this space!
- If you want to know more about Bluetooth Low Energy, then look here at the index of material produced by John Murray and Martin Woolley.