将更新的共享本机库(.so 文件)添加到 Android Studio 应用会导致 UnsatisfiedLinkError

Adding an updated shared native library (.so file) to an Android Studio app leads to an UnsatisfiedLinkError

我有一个用 Android Studio 3.0.1 和 compileSdkVersion 26 编写的 android 应用程序。此应用程序依赖于用本机代码 (c++) 编写的模块。模块中的本机代码依赖于第三方共享库 (.so) 文件。在 Cmake 文件中,这个第三方库是使用标准方法包含的,例如:

add_library( my-module-lib

             SHARED

             src/main/cpp/file1.cpp
             src/main/cpp/file2.cpp )

add_library( libthird_party_library SHARED IMPORTED )
set_target_properties( libthird_party_library PROPERTIES IMPORTED_LOCATION ${pathToProject}/src/main/jniLibs/${ANDROID_ABI}/libthird_party_library.so)

target_link_libraries( my-module-lib libthird_party_library )

然后我的模块作为依赖项添加到主应用程序,并使用以下方式加载本机代码:

System.loadLibrary("my-module-lib");

一切正常,但是我需要更新第三方库。我认为这就像用新文件替换旧的 .so 文件一样简单。但这会导致 UnsatisfiedLinkError:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libthird_party_library.so.2" not found
                                                                                          at java.lang.Runtime.loadLibrary0(Runtime.java:989)
                                                                                          at java.lang.System.loadLibrary(System.java:1567)

应该注意 android 现在搜索“.so.2”文件而不是“.so”文件。所以我认为由于某种原因,旧的仍然包含在某个地方,并且由于名称冲突,新的被重命名为“*.2”。所以我尝试了这些东西来摆脱它:

1) [不工作] 删除所有内容,重新编译所有内容

只是删除所有内容,即:

并重建一切,即:

但这仍然会导致同样的 UnsatisfiedLinkError

2) [不起作用] 更改 .so 文件的名称

将更新库的名称更改为"libthird_party_library_NEW.so"并更改cmake文件:

set_target_properties( libthird_party_library PROPERTIES IMPORTED_LOCATION ${pathToProject}/src/main/jniLibs/${ANDROID_ABI}/libthird_party_library_NEW.so)

同样的错误

3) [有效,不是一个好的解决方案] 重命名旧的“.so”文件并包含新文件

一个有效的 "solution" 是使用 refactor > rename 将旧的“.so”文件重命名为 "libthird_party_library_OLD.so" 然后使用标准名称 "libthird_party_library.so" 复制新的第三方库。但这当然不是一个很好的解决方案,因为旧的不需要的库将包含在 apk 中。

原来是在 android studio 中链接版本化共享库时出现问题。与 this question and as described here 类似。

问题是“libthird_party_library.so”的内部版本号实际上是“libthird_party_library.so.2”。这个可以通过.so文件上linux下的运行objdump找到,即:

objdump -p libthird_party_library.so | grep so

输出:

libthird_party_library.so:     file format elf64-little
  NEEDED               libm.so
  NEEDED               libc.so
  NEEDED               libdl.so
  SONAME               libthird_party_library.so.2
  required from libdl.so:
  required from libm.so:
  required from libc.so:

由于 android 看到的文件名是“libthird_party_library.so”并且 android 尝试加载“ libthird_party_library.so.2” 显然找不到需要的库。

解决方案

一个明显的解决方案是将文件名更改为“libthird_party_library.so.2”,但这不起作用,因为 android studio 仅包含apk 中以 .so 结尾的库(aaargh)。

解决方法是将内部版本号改为“libthird_party_library_2.so”,将文件重命名为“libthird_party_library_2.so" 并更改 Cmake 文件以反映此更改。

1) 可以在 linux 下通过以下方式更改内部版本号:

rpl -R -e libthird_party_library.so.2 libthird_party_library_2.so libthird_party_library.so

第一个参数是内部版本号,第二个是我们需要更改的版本号,第三个是文件名。确保旧内部版本号的长度与新版本相同!!

2) 使用您喜欢的工具将文件名更改为“libthird_party_library_2.so

3) 将 CMake 文件中的这一行更改为

set_target_properties( libthird_party_library PROPERTIES IMPORTED_LOCATION ${pathToProject}/src/main/jniLibs/${ANDROID_ABI}/libthird_party_library_2.so)

希望对您有所帮助!