【问题标题】:Import existing c++ library (.a or .so file) ndk android导入现有的 c++ 库(.a 或 .so 文件)ndk android
【发布时间】:2017-03-17 20:45:09
【问题描述】:

我刚刚完成了 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 类文件是否应该使用 keyword native 定义与在 c++ 文件中实现的方法相同的方法(例如:在 c++ 文件方法名称 getData() 中,java 类是否应该包含 public native getData( ) )

【问题讨论】:

    标签: android android-ndk java-native-interface .a .so


    【解决方案1】:

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


    好的,所以你有很多问题。其中一些问题是个人偏好类型,但我将提供它们作为我个人的选择。

    #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 运行时将找到并打开库并在您加载的库中查找那些方法。查看更多here

    【讨论】:

    • 非常感谢您的回答。我对“本地图书馆”这个词感到非常困惑。 1) 我为从 .so 文件(在“jni”文件夹中)访问 c++ 方法而编写的代码称为本地库,或者我从 c++ 库中使用的方法(如数学函数)称为本地库或我的 .so 或 .a文件被称为本机库......这一行所说的 System.loadLibrary("my_native_lib");我正在加载什么?
    • 我已经编辑了我的答案,以便为您提供更多详细信息。看看有没有帮助
    • 我的原生项目是使用 VisulaStudio 完成的。有什么方法可以将 c++ 源文件添加到 Android Studio 并生成 .so ? .如果发生这种情况,那就太好了
    • 是的,请查看此链接。 stackoverflow.com/questions/40369382/…这是最简单的解决方案
    • 你能帮我看看我的 Android.mk 文件应该怎么样?按照你的模式
    【解决方案2】:

    来自here

    直接从 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 一样,该库必须与页面对齐并以未压缩的形式存储才能正常工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多