Using NDK, I built a shared library to run some algo code on output from GazeRecognition. The simple version of this library (lib-plus-nlopt.so) that contained only native c++ code worked fine sending and receiving data from the Unity app. Then, the trouble started.
I tried to include code that made optimization calls from an open source library called nlopt. I followed the steps in the Android NDK documentation to include libnlopt.so as a shared prebuilt library, and everything built cleanly. I included both of the the .so files (lib-plus-nlopt.so which is the main library, libnlopt.so which is the dependency that contains the optimization calls) in Assets/Plugins/Android. For some reason, when the app runs on the device, it reports that the dependency libnlopt.so is not found and everything crashes. The error line is pasted in below.
My question is this: how do I properly inform Unity about the prebuilt library that needs to be included as a dependency? Any pro tips here would be greatly appreciated. THANKS!!!
Unity Editor version: 2922.2.0b16.112.5806
ML2 OS version:
Android API Level 29
Host OS: Windows 11 for Unity Editor
Error messages from logs (syntax-highlighting is supported via Markdown):
2023-01-18 17:13:19.614;10117;9970;9992;Error;Unity;DllNotFoundException: Unable to load DLL 'lib-plus-nlopt.so'. Tried the load the following dynamic libraries: Unable to load dynamic library 'lib-plus-nlopt.so' because of 'Failed to open the requested dynamic library (0x06000000) dlerror() = dlopen failed: library "libnlopt.so.0" not found;
@dliston sorry to hear that you’re running into this problem. Can you try the following :
- Change the apk extension to .zip and open the archive. Check if the .so file was packaged into your Unity application
- Move your .so file under Plugins/Android/x86_64/
- Using your file browser, delete the .meta file associated with the .so file.
- Once deleted, go back to unity and select the .so file, then make sure that Android x86_64 is selected under the compatible platforms in the inspector.
Let me know if the problem persists.
@kbabilinski, thanks for these steps. Both .so files are included in the zipped .apk under /lib/x86_64 when the project is built, which occurs whether they are located in Assets/Plugins/Android or Assets/Plugins/Android/x86_64. Deleting .meta files had no effect, either, they show up as x86_64 in the inspector when the project is opened back up. The error line that crashes the app is the same:
2023-01-21 01:17:47.055;10107;5961;5982;Error;Unity;DllNotFoundException: Unable to load DLL 'lib-COBRA-algos.so'. Tried the load the following dynamic libraries: Unable to load dynamic library 'lib-COBRA-algos.so' because of 'Failed to open the requested dynamic library (0x06000000) dlerror() = dlopen failed: library "libnlopt.so.0" not found;
The error seems to indicate that the executable is looking for libnlopt.so.0 and I tried to add a library with that name in that same x86_64 folder, but Unity seemed to rename it to something else. I'll try any other steps you provide, thanks for looking into it.
Can you try building a simple x86_64 app without Magic Leap support? Then you can test if it’s an issue on Android or if its an issue with our platform by testing it in Android Studio’s emulator.
Unfortunately, since the library isn’t found there is little we can do to test it on our end without recompiling the plugin and the c# wrapper.
Do you mind testing one more thing ? Try is recompiling the lib for arm64 and testing it in the Android Studio Emulator to see if it loads correctly.
Thanks for those suggestions @kbabilinski. I think we were on the right track with the subfolder under Plugins/Android as there seems to be a long history of issues surrounding unresolved library dependencies in Unity, with quirks and variability related to the runtime environment.
Rather than testing out builds that could introduce more variability, are there any further tests we could try to specify where the Magic Leap apk assumes library dependencies will be located? Could we load the dependent library separately in code? Do we know whether libraries with dependencies work on ML2? Just thinking through the options here.
Was able to build a library with a simple dependency that loaded fine, so that piece checks out. It may be that the precompiled x64 library I had tried to include will not load on device for some reason and the "not found" error message is incorrect. Working on that.
@dliston happy to hear that you were able to get a simple demo working. The issues I’ve seen most frequently are:
The library is compiled for x86 and not x86_64
The library targets x86_64 desktop instead of Android (Linux/ Mac)
The library was compiled with dependencies to chrome OS instead of android
The library was compiled but an error occurred during compilation that prevented all of the files from being packaged correctly.
Do you mind sharing a link to the plugin you are trying to load?
The error says that library libnlopt.so.0 can’t be found. Notice the 0 at the end. The library you copied into the plug-in directory is libnlopt.so.
@jaime.cisneros that's a good lead to follow up on, thanks for pointing that out. I did try to include a file called libnlopt.so.0 in Assets/Plugins/Android but Unity renamed it to something else and threw the same error. On PC, the compiled C++ code works fine as a standalone executable referencing libnlopt.so, but the apk fails on ML2 with the error above, still working out why that is. Could be that the error message might be misleading about the root cause of the error; I don't know how Unity assigns the names for dependencies but I'll test out any ideas you have. I did build a dependency with NDK that worked, so I'm following up on that now.
@kbabilinski the library target is indeed x86_64 desktop instead of Android, I started building that same library using NDK and will try to pare it down to work around the NDK build system's complaints. Just out of curiosity, why don't the desktop x86_64 libraries work on device?
I have built C++ libs (.so) for the ML2, using NDK 21.4.7075529, and have used the compiled libraries in Unity apps, after creating the appropriate C# bindings. When you say desktop libraries, what do you mean? Are those linux libraries?
Yes, the Linux x86_64 .so libraries gave that strange "not found" error. Following Krystian's suggestion about the difference between Android x86_64 and Linux x86_64 I rebuilt the .so using NDK's Cmake support. The library built with a few minor warnings, it loads on device, but isn't working properly in that the numerical results differ from the Linux .so version (looks like the optimizations aren't running at all).
Unfortunately, compiling a plugin for Android is outside the scope of our forum. For testing, you can remove a variable by using Android Studio’s emulator to test on a virtual device that targets Android 10, x86_64, without google play services.
Remember that the Linux and Android kernels aren't the same, so I don't expect a library compiled for a Linux distribution to work on an Android device.
Yes, that was one lesson here. Another turns out to be that even libraries compiled for Android don't necessarily work on Android devices.