导入现有的C++库(.a或.so文件)NDK Android

17

我刚刚接触了Android的本地开发。我成功地使我的AndroidStudio 2.2.2准备好进行本地开发。

我还构建了示例hello-jni项目。

我要实现什么

我正在尝试使用一个已经设计好的c++库(我将获得静态库.a扩展名或.so文件)

对于本地开发,有一些困惑

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

2)我是否需要制作CMakeLists.text:就我查找到的来看,我的.a文件不是使用ndk-build生成的,所以我需要自己制作它。

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

CMakeLists.text会编译我的新开发的Android项目,还是我的现有.a文件?

3)在我的项目中,我应该把.a文件放在哪里?是在jni文件夹下吗?

4)我的Java类文件是否应该像c++文件中实现的方法一样使用native关键字定义方法(例如:在c++文件中方法名称getData(),Java类是否应该包含公共原生getData()方法)?

2个回答

23

注意:本答案不介绍如何在编写本地(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 或在将来学习它,请查看此答案:C/C++ with Android Studio version 2.2

  1. System.loadLibrary("my_native_lib");:在这里,您告诉 Java 运行时添加此给定库。这样,您就在 Java 代码和库内的 C++ 代码之间创建了链接。该行以下的方法应具有与 C++/C 代码中相同的名称。这样,Java 运行时将找到并打开库,并在加载的库中查找这些方法。更多详细信息请参见此处

非常感谢您的回答。我对“本地库”这个词非常困惑。1)我从jni文件夹中访问c++方法所编写的代码被称为本地库,还是我从c++库中使用的方法(如数学函数)被称为本地库,或者我的.so或.a文件被称为本地库....这行代码System.loadLibrary("my_native_lib");是什么意思?我正在加载什么? - karthik kolanji
1
我已经编辑了我的答案,以便为您提供更多细节。看看是否有帮助。 - ᴛʜᴇᴘᴀᴛᴇʟ
2
是的,要做到这一点,请查看此链接。http://stackoverflow.com/questions/40369382/c-c-with-android-studio-version-2-2?answertab=active#tab-top 这是最简单的解决方案。 - ᴛʜᴇᴘᴀᴛᴇʟ
这个答案中有额外的细节帮助了我。在我将.so文件移动到正确的架构文件夹之前,Gradle没有将它们打包到我的APK中。https://dev59.com/l2Af5IYBdhLWcg3wskiQ - Jacob Joel
如果我选择编译后的.so文件的选项1,我该如何在我的项目中使用它? - Daniel C Jacobs
显示剩余6条评论

2

这里开始

直接从APK文件中打开共享库

在API 23及以上版本中,可以直接从您的APK文件中打开.so文件。只需像平常一样使用System.loadLibrary("foo"),但在AndroidManifest.xml中设置android:extractNativeLibs="false"即可。在旧版本中,.so文件会在安装时从APK文件中提取出来。这意味着它们占用了您的APK空间,并且再次占用了您的安装目录(并且这被计入您的应用程序所占用的空间并向用户报告)。任何您想要直接从您的APK文件中加载的.so文件必须在zip文件中按页面对齐(在4096字节边界上)并存储为未压缩格式。当前版本的zipalign工具负责对齐。

请注意,在API 23及以上版本中,dlopen(3)将从任何zip文件中打开库,而不仅仅是您的APK文件。只需给dlopen(3)一个形式为"my_zip_file.zip!/libs/libstuff.so"的路径即可。与APK一样,此库必须按页面对齐并以未压缩格式存储才能正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接