最近学习了一下NDK的开发, 就来分享一下.
对一个新鲜事物, 我们先解决的无非就是三件事情: 是什么?为什么?怎么做?.
(英语:native development kit,简称NDK)是一种基于原生程序接口的软件开发工具。通过此工具开发的程序直接以本地语言运行,而非虚拟机。因此只有java等基于虚拟机运行的语言的程序才会有原生开发工具包。[维基百科]
NDK是一系列工具的集合
NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的.
NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。
NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。
上述文字致谢Devin Zhang提供理论支持
是什么和为什么我就先介绍到这儿, 接下来就具体看看如何进行NDK的开发
请大家务必升级到AS 2.2以上版本, 因为这个版本升级了很多内容, 详情请见 Android Studio 2.2 正式稳定版发布
大家可以直接打开SDK进行下载和安装
由于NDK的工具包较大, 大家也可以选择从网站中下载: http://wear.techbrood.com/tools/sdk/ndk/, 选择自己对应的版本使用迅雷等工具下载即可, 不过通过这种方法一定要修改local.properties文件, 在里面添加:
//后面改成自己下载后解压的路径名
ndk.dir=C\:\\Users\\Lulu\\AppData\\Local\\Android\\android-ndk-r13
关于CMake
- CMakeList.txt 是脚本文件, 需要指定包含哪些源代码;
- 可以写一些条件语句, 实现不同的代码包含
- 内部说明:
1). add_library 表示编译一个代码库, 内部包含了代码库的名称, 以及源代码有哪些
接下来通过几个案例来演示NDK的开发流程
step1: 为了使代码整洁, 咱们新建一个类 NativeHelper, 专门用于访问C语言代码的帮助类 并添加获取Appkey的方法
public class NativeHelper {
static {
// 加载C代码库, 库的名称, 必须是CMakeLists.txt中指定的名称
System.loadLibrary("native-lib");
}
//获取C中隐藏的AppKey
public static native String getAppKey();
}
Note: 一定要添加上面的静态代码块的内容, 否则无法加载C代码库
此时的getAppKey()方法标红, 不用管它, 继续….step2: 在cpp目录下右击创建C/C++ Source, 选择Type, 并勾选 Create an associated hader, 为保持对应, 名字命名为: com_lulu_ndkdemo_NativeHelper, 此时会出现, 在cpp目录下会出现两个文件, 如图:
step3: 在CMakeLists.txt中的add_library中添加依关系, 点击同步
src/main/cpp/com_lulu_ndkdemo_NativeHelper.c
Note:
C代码库生成的名称规则
1. 如果栈顶代码库名称为 “nh” 那么生成的文件必定是libnh.so
命名规则: lib库名.so
2. System.loadLibrary(库名); //此处不能包含前面的lib和后面的.sostep4: 在com_lulu_ndkdemo_NativeHelper.c文件中添加c语言代码
#include
JNIEXPORT jstring JNICALL
Java_com_lulu_ndkdemo_NativeHelper_getAppKey(JNIEnv *env, jclass type) {
//测试代码, 没有任何意义
char* app_key = "5465465416948";
//生成 Java 中的字符串对象
//指针的指针
// env <=> JNINativeInterface** C语言
return (*env)->NewStringUTF(env, app_key);
}
step5: 在MainActivity中获取AppKey, 查看结果 -> 成功
String appKey = NativeHelper.getAppKey();
Log.d(TAG, "onCreate: appKey => " + appKey);
Note: Java 调用C/C++代码
1. 任何一个类的方法, 如果声明了native修饰符, 那么就可以认为是一个C代码;
2. 可以用对象, 类直接调用
3. 创建C/C++文件; 如果一个类中有一个native的方法, 那么对应的C方法: Java_包名类名方法名(JNIEnv *env, …);
4. 当Java类中包含了native的方法, 那么这个类必须写一个静态初初始化块: System.loadLibrary(“库名”)
接下来, 只简单介绍核心代码, 不再赘述
step1: 在com_lulu_ndkdemo_NativeHelper.c中添加:
JNIEXPORT void JNICALL
Java_com_lulu_ndkdemo_NativeHelper_printLog(JNIEnv *env, jclass type, jstring str_) {
const char *str = (*env)->GetStringUTFChars(env, str_, 0);
//TODO: 显示Android 的日志
// 调用Android的代码
// 代码需要调用系统的日志库, 这个库已经在 CMakeList.txt添加了e,因此可以直接调用
const char *tag = "NativeHelper";
//jstring -> char*
jboolean b = JNI_FALSE;
const char* txt = (*env)->GetStringUTFChars(env, str_, b);
//打印log日志
__android_log_write(ANDROID_LOG_DEBUG, tag, txt);
//释放string
(*env)->ReleaseStringUTFChars(env, str_, str);
}
step2: NativeHelper中添加
//在C中打印log
public static native void printLog(String str);
step3: MainActivity中调用
//打印C语言中的Log
NativeHelper.printLog("测试Log");
至此, 咱们应该大致了解了一下NDK开发的简单流程, 鄙人菜鸟, 希望抛砖引玉, “引”出更好的文章
本文还有下篇, 将再写一些关于NDK开发的案例Demo, 希望大家喜欢和关注