构建高效的Android应用 - 探索SO库的奥秘

发布时间:2023-12-08

构建高效的Android应用 - 探索SO库的奥秘

更新:2023-05-14 06:31

一、SO库是什么?

SO(Shared Object)库是一种动态库,它可以在程序运行时被动态地加载到内存中,并提供给应用程序使用。SO库通常使用C/C++编写,并且被编译成二进制可执行文件。SO库可以提供一些应用程序需要访问的功能,比如图形库、音频库等等。 在Android开发中,使用SO库可以使应用程序更加紧凑,同时还能提供更高的性能。通过使用SO库,可以将一些常用的、底层的功能模块封装成库的形式,供应用程序动态链接,并使用其中的功能,这可以降低应用程序本身的大小,同时提高代码的复用性。

二、如何使用SO库?

在Android中,可以使用Java Native Interface(JNI)实现Java代码与C/C++函数库之间的调用。JNI可以将Java代码编译为Native代码,并与Native库进行交互。下面是一个使用SO库的Java代码示例:

public class MyNativeLib {
    static {
        System.loadLibrary("my-lib"); // 加载名为"my-lib"的SO库
    }
    public native void nativeMethod(); // 声明Native方法
}

上面的代码中,静态块中使用System.loadLibrary()方法加载名为"my-lib"的SO库。在Java中声明了nativeMethod()本地方法,这个方法实际上是在SO库中实现的,Java运行时会通过JNI来调用SO库中的函数。

三、SO库的优势和劣势?

优势:

  1. 高性能:SO库编译成机器码,因此更加高效,能够提供更高的性能。
  2. 代码重用:将一些底层的功能模块封装成SO库,可以在多个应用程序中重复使用。
  3. 动态加载:SO库能够被动态地加载到内存中,因此可以在需要时再加载,可以节省内存资源。 劣势:
  4. 编译难度:编写C/C++代码的难度相对Java较大,编译过程也较为繁琐。
  5. 兼容性问题:不同的CPU架构可能需要不同的SO库,同时不同的Android版本也可能会有兼容性问题。

四、SO库的注意事项?

在使用SO库时,还需要注意以下几点:

  1. SO库只能包含C/C++代码,不能包含Java代码
  2. SO库编译需要使用对应CPU架构的编译器,比如armeabi-v7a架构需要使用armv7a编译器,则编译的SO库也需要以这个架构为目标
  3. 在使用SO库时,需要确保SO库的兼容性,避免出现兼容性问题
  4. 在动态加载SO库时,需要确保SO库已经被正确地安装到设备上 最后,展示一下使用Android Studio编写C/C++代码和编译SO库的示例:

1. 创建Native库

在Android Studio中,可以通过创建"C/C++"类型的Android工程,来创建Native库。具体步骤如下:

  1. 选择"File"->"New"->"New Module...",在弹出的窗口中选择"C/C++"->"JNI/Library"。
  2. 在下一步中,可以指定项目的名称、创建的Native库的名称等信息。
  3. 创建完成后,在项目的"app/src/main"下会生成一个命名为"java"和"jni"的文件夹。

2. 编写Native代码

在"jni"文件夹下可以创建一个"native_lib.c"文件,并编写C代码。例如,下面的代码将实现从Java代码调用的Native方法:

#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_mytestproject_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject obj) {
    return (*env)->NewStringUTF(env, "Hello from native code!");
}

3. 编写CMake配置文件

在"app/src/main/cpp"下创建一个CMake文件,指定编译配置等信息。例如,下面的CMake文件将创建一个名为"native-lib"的SO库,并将"native_lib.c"文件中的函数打包到该SO库中:

cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
             native-lib
             # Sets the library as a shared library.
             SHARED
             # Provides a relative path to your source file(s).
             native_lib.c )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
              log-lib
              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# same build directory. If the imported library has dependencies or
# transitive dependencies, they are automatically added to the link
# command.
target_link_libraries( # Specifies the target library.
                       native-lib
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

4. 构建Native库

在Gradle Script中的"build.gradle(Module:app)"文件下,添加如下配置,通过Sync Now来同步更新:

externalNativeBuild {
    cmake {
        path "src/main/cpp/CMakeLists.txt"
    }
}

然后,执行Build->Make Module 'app',即可生成SO库文件。