导入现有的 c++ 库(.a 或 .so 文件)ndk android

Import existing c++ library (.a or .so file) ndk android

我刚刚在 android 完成了本机开发。我成功地让我的 AndroidStudio 2.2.2 准备好进行本地开发

我也构建示例hello-jni项目

我想要实现的目标

我正在尝试使用用 c++ 设计的现有库(我将获得静态库 .a 扩展或 .so文件)

关于原生开发的一些困惑

1) 我应该使用现有 c++ 库的 .cpp 和 .h 文件而不是 .a.so 文件吗?

2) Do I need to make CMakeLists.text :据我搜索我的 .a files 没有生成使用 ndk-build ,所以我需要制作它。

如果我使用 .cpp & .h 文件 ,我应该制作 Android.mk & Application.mk

CMakeLists.text 将我新开发的 android 项目编译为库还是我现有的 .a 文件?

3) 我应该把 .a 文件放在我项目的什么地方。是在jni文件夹下吗?

4) 我的 java class 文件是否应该使用 关键字 native 定义方法,就像在 c++ 文件中实现的一样(示例:在 c++ 文件方法中名称 getData() ,应该 java class 包含 public 原生 getData() )

注意:此答案并未显示在编写本机 (C++) 代码后如何使用 CMake。对于该设置,请阅读下面的答案以全面了解该设置,然后查看 .


好的,你有很多问题。其中一些问题是个人偏好类型,但我会根据个人选择提供它们。

#1 这是你的选择。我个人会使用编译后的 .so 文件。这样我就永远不必担心 NDK 和 CMake 以及 .mk 文件。如果您有该文件,您只需将文件添加到 libs 文件夹(而不是 lib 文件夹),然后对 build.gradle 文件稍作更改。就是这样。

改为build.gradle:

sourceSets {
    main {
        manifest.srcFile 'AndroidManifest.xml'
        java.srcDirs = ['src']
        res.srcDirs = ['res']
        assets.srcDirs = ['assets']
        jniLibs.srcDirs = ['libs']
    }
}

#2 & 3 这些与此选项无关。

#4 无论您使用文件还是编译的库,您都必须这样做:

@SuppressWarnings("JniMissingFunction")
public class MyNativeMethods {
    static {
        System.loadLibrary("my_native_lib");
    }

    public native int native_method_1(int fd);
    public native int native_method_2(int fd);
    public native void native_method_3(int fd, int arr[]);
    public native int[] native_method_4(int fd);
}

然后,您可以从 Activity/Fragment.

中调用这些方法

希望这已经够清楚了。


编辑(基于以下评论)

  1. .so.a 文件是您的原生库。

  2. .cpp.c 等文件只是您的本机源代码文件。如果要在项目中使用这些文件,则必须使用构建系统(例如 CMake)来使用它们。 CMake 将获取您的源代码文件并制作一个 .so 库,该库又是本机库。这就是为什么我建议使用 .so 文件的原因,因为为什么在不需要的时候在项目中执行 CMake 的工作?

如果以后想尝试或学习CMake,请查看此答案:

  1. System.loadLibrary("my_native_lib");:这里是告诉 Java 运行时添加这个给定的库。这样您就在 Java 和库中的 C++ 代码之间创建了一个 link。该行下面的方法的名称应与它们在 C++/C 代码中的名称相同。这样 Java 运行时将找到并打开库并在您加载的库中查找那些方法。查看更多 here

来自 here

Opening shared libraries directly from an APK

In API level 23 and above, it’s possible to open a .so file directly from your APK. Just use System.loadLibrary("foo") exactly as normal but set android:extractNativeLibs="false" in your AndroidManifest.xml. In older releases, the .so files were extracted from the APK file at install time. This meant that they took up space in your APK and again in your installation directory (and this was counted against you and reported to the user as space taken up by your app). Any .so file that you want to load directly from your APK must be page aligned (on a 4096-byte boundary) in the zip file and stored uncompressed. Current versions of the zipalign tool take care of alignment.

Note that in API level 23 and above dlopen(3) will open a library from any zip file, not just your APK. Just give dlopen(3) a path of the form "my_zip_file.zip!/libs/libstuff.so". As with APKs, the library must be page-aligned and stored uncompressed for this to work.