Android Studio NDK详解:加速移动应用的原生代码开发
更新:2023-05-14 00:58 移动应用开发中,各种开发框架和语言多种多样,常用的有Java、Kotlin和Swift等。但有时候,我们需要使用C或C++语言编写一些性能更高的原生代码,以获取更好的用户体验。Android Studio的NDK(Native Development Kit)提供了一种实现这种需求的方法。
一、什么是NDK?
NDK是Android Studio提供的一个工具集,旨在帮助开发者编写C/C代码来优化Android的应用程序,包括增加应用程序的性能,处理自定义任务和更多。目前,NDK支持的ABI主要包括 armeabi-v7a、arm64-v8a、x86、x86_64以及mips和mips64。 在没有NDK时,开发者的代码只能以Java和Kotlin等二进制代码的方式运行。而有了NDK之后,可以将一些紧耦合的功能和代码转化为C/C代码,然后以库的形式提供给Java和Kotlin等高级语言使用。这样不仅可以提高性能,还可以在代码共享方面实现更好的跨平台性。
二、如何在Android Studio中使用NDK?
Android Studio提供了NDK插件,让开发者轻松地设置和配置NDK的开发环境。在使用NDK之前,需要完成以下步骤:
1、下载NDK:
在Android Studio中,点击“Tools->SDK Manager->SDK Tools”选项卡,然后在右边的主窗口区域找到和选中“NDK”即可下载。
2、配置Jni目录
在Java工程的根目录下构建JNI接口需要的目录结构,例如:app/src/main/jni
。然后在app
下新建.buildozer
文件(目的是为了让gradle加载NDK配置)。
# app/.buildozer.gradle.kts
android {
defaultConfig {
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
arguments "-DANDROID_STL=c++_shared"
}
}
}
}
3、创建.so库文件
在jni
目录下创建一个C或C++源文件,然后使用编译器创建.so
文件,将其复制到应用程序的libs
目录中。在libs
目录下可以分别为每种CPU架构创建目录,以job目录为例:
app/libs/armeabi-v7a/
app/libs/arm64-v8a/
app/libs/x86/
app/libs/x86_64/
在完成上述步骤之后,你可以像其他库一样在Java代码中使用自定义的C/C++库文件。如下所示:
System.loadLibrary("natives-lib");
这里的natives-lib
就是.so
文件的名称,它需要和C/C++源文件中的名称相同。
三、如何在NDK中使用静态库?
在C和C++中,静态库非常重要,它们被用作重复代码和可重用代码的共享。在Android NDK中,添加本机静态库和可执行文件也很简单:
1、编写C++源代码
// test.cpp
#include "test.h"
int add(int a, int b) {
return a + b;
}
2、编写C头文件
// test.h
#ifndef TEST_H
#define TEST_H
#ifdef __cplusplus
extern "C"{
#endif
int add(int a, int b);
#ifdef __cplusplus
}
#endif
#endif // TEST_H
3、编写Android.mk文件
Android.mk文件用于配置如何构建NDK应用程序。它定义了源代码文件、库等,告诉编译器如何处理这些文件,并包含使用这些文件创建动态库的指令。Android.mk文件应在jni
目录下创建。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := test.cpp
include $(BUILD_STATIC_LIBRARY)
4、在.buildozer.gradle.kts文件中增加编译选项
defaultConfig {
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
arguments "-DANDROID_STL=c++_shared", "-DANDROID_TOOLCHAIN=clang" // 添加这一行
}
}
}
需要注意的是,要使用静态库时,需要使用clang作为工具链才能编译通过。
5、在.buildozer.gradle.kts中导入静态库
android {
sourceSets {
main {
jniLibs.srcDir 'libs'
}
}
}
这个操作主要是告诉gradle在哪里可以找到静态库,实现导入了so库中。
6、在Java代码中使用静态库
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("test");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int result = Test.add(1, 2); //调用静态库函数
TextView textView = findViewById(R.id.tv_result);
textView.setText("result = " + result);
}
}
以上就是使用静态库的完整步骤。在Jni目录中,需要有Android.mk文件,它告诉编译器如何构建静态库。编译器会将静态库转换为.so
文件,并将其打包在APK应用包中。在Java代码中可以通过System.loadLibrary
方法加载本地库,就像之前加载普通的so库一样。
四、NDK开发常见问题及解决方案
1、如何解决不同CPU架构的兼容性问题
Android系统支持多种CPU架构的设备,并且支持同时安装多个.so
库的版本。这种格式通常是“/lib/libname.so”或“/lib/architecture/libname.so”。为了实现多架构支持,你需要在构建过程中生成多个库版本。可以将结果位置指定到每个configure的ANDROID_ABI的不同子目录中,如下所示:
app/
jni/
Android.mk
Application.mk
foo.c
libs/
armeabi/
libfoo.so
armeabi-v7a/
libfoo.so
x86/
libfoo.so
2、如何解决debug版本无法正常工作的问题
默认情况下,NDK构建出的.so
库的标志为release版本,而非debug版本,如果需要在NDK调试过程中使用debug版本,需要在Gradle中设置:
android {
defaultConfig {
externalNativeBuild {
cmake {
arguments "-DCMAKE_BUILD_TYPE=DEBUG"
}
}
}
}
3、如何解决NDK开发过程中出现的其他问题
可以将以下项目添加到build.gradle文件中查看调试级别。项目和gradle.properties文件中都有这些内容。
android {
buildTypes{
debug {
debuggable true
jniDebuggable true
}
}
}
4、如何解决NDK中遇到的链接错误
常见的原因包括C++代码插入C语言源代码、未定义的全球变量等,可以试着把链接器的日志打开,检查被外部问题导致的链接错误。
LOCAL_LDLIBS += -Wl,--trace-symbol=foo
五、总结
在移动应用开发中,NDK是为开发者提供高性能的编程接口的一种方法。它能帮助开发者编写C/C++代码,优化Android应用程序的性能,实现自定义任务等操作。本文介绍了如何使用NDK的详细步骤和常见问题的解决方法,希望对你在移动应用开发中使用NDK起到一定的帮助。