Unity 中的原生 Android 库抛出 DllNotFound 异常

Native Android library in Unity throws DllNotFound exception

我用 C++ 编写了一个国际象棋库,并为 Windows(32 位和 64 位)和 Android(x86 和 armebi-v7)编译了它。

我的 Windows 构建完全正确,但是当我为 Android 构建它并且当我 运行 游戏时,我的 adb logcat -s Unity 收到以下异常:

11-23 16:39:37.278 22335 22352 I Unity   : DllNotFoundException: MatinChess
11-23 16:39:37.278 22335 22352 I Unity   :   at (wrapper managed-to-native) MatinChess.Net.ExternMethods:Initialize ()
11-23 16:39:37.278 22335 22352 I Unity   :   at MatinChess.Net.MatinChess..ctor () [0x00000] in <filename unknown>:0
11-23 16:39:37.278 22335 22352 I Unity   :   at Model.Awake () [0x00000] in <filename unknown>:0

当我解压缩我的 apk 文件时,我有:

lib
|_ armeabi-v7a
|  |_ libmain.so
|  |_ libMatinChess.so
|  |_ libmono.so
|  |_ libunity.so
|_ x86
   |_ libmain.so
   |_ libMatinChess.so
   |_ libmono.so
   |_ libunity.so

这是我的设置和脚本:

基于 here and here,我在我的 Assets 中创建了 Plugins 文件夹,并像这样放置我的库:

Plugins
|_ Android
|  |_ libs
|     |_ armeabi-v7a
|     |  |_ libMatinChess.so
|     |_ x86
|        |_ libMatinChess.so
|_ x64
|  |_ MatinChess.dll
|_ x86
   |_ MatinChess.dll

而且我确定 Inspector 中的 Platform Settings 配置正确。

我在我的脚本中使用了我的库并基于 here and here,而不是将 libMatinChess.so 用于 Android,我没有在开始时使用 lib.so 最后。所以是这样的:

class ExternMethods
{
#if UNITY_ANDROID
    const string dll = "MatinChess";
#else
    const string dll = "MatinChess.dll";
#endif

    [DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
    public extern static PlayState CheckState();

    [DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
    public extern static void Initialize();

    //
    // other extern methods
    //
}

因此,当我为 Windows 构建我的 Unity 游戏时,它可以正常工作。为了让它在编辑器中工作,我遵循 this link 并编写了以下脚本:

public class Model : MonoBehaviour
{    
    void Awake()
    {
#if UNITY_EDITOR_32
        var dllPath = Application.dataPath + Path.DirectorySeparatorChar + "Plugins" + Path.DirectorySeparatorChar + "x32";
#elif UNITY_EDITOR_64
        var dllPath = Application.dataPath + Path.DirectorySeparatorChar + "Plugins" + Path.DirectorySeparatorChar + "x64";
#else // Player
        var dllPath = Application.dataPath + Path.DirectorySeparatorChar + "Plugins";
#endif
        var currentPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process);
        if (currentPath != null && currentPath.Contains(dllPath) == false)
            Environment.SetEnvironmentVariable("PATH", currentPath + Path.PathSeparator + dllPath, EnvironmentVariableTarget.Process);
    }
}

因此它也适用于 Unity 编辑器。

可能会在 Environment.SetEnvironmentVariable("PATH",...) 之前调用方法 MatinChess.Net.ExternMethods.Initialize,这会导致 DllNotFoundException。

在调用 MatinChess.Net.ExternMethods.InitializeEnvironment.SetEnvironmentVariable 之前尝试打印日志消息。然后你可以检查这些方法的调用顺序。

如果这是原因,请添加,将 Environment.SetEnvironmentVariable("PATH",...) 移动到 MatinChess.Net.ExternMethods 的静态初始值设定项可能会解决您的问题。

编辑:
设置后尝试打印PATH,方法可能设置失败

编辑:
只是猜测.. android 共享库搜索路径应该是 LD_LIBRARY_PATH 而不是 PATH。尝试设置它。我不确定 Unity3D 是否处理了这个问题。

编辑:
除了 libMatinChess.so 之外,不包括所有库依赖项是一个可能的原因。一些信息 here.

目前能想到的就这些了

检查您是否确实导出了具有正确符号的有效 .so 文件。

还要检查您是否包含了 libMatinChess.so 的所有库依赖项,有时可能包括您的 C 运行时。尝试与标准库静态链接。