网站首页 > 技术文章 正文
愿关注我们的人都能找到
属于自己的皮球
NDK简介
NDK 全称 Native Development Kit,可以让您在 Android 应用中调用 C 或 C++ 代码的工具。
NDK的优点
1、NDK 可以生成 .so 文件, 方便代码共享;
2、增加反编译的难度;
3、提高性能。
NDK是如何构建的
版本说明
Android Studio:3.0.1
Android Plugin for Gradle: com.android.tools.build:gradle:3.0.1
Gradle:4.1
效果预览
如图是使用命令 ndk-build,生成对应的 so 文件。
开始
一开始我们需要在 jni 目录下新建 Android.mk、Application.mk、HelloCPP.cpp 文件。
Android.mk
必须在 jni 文件夹内创建 Android.mk 配置文件, ndk-build 脚本将查看此文件,其中定义了模块及其名称、要编译的源文件、版本标志以及要链接的库。
# 构建系统提供的宏函数 my-dir 将返回当前目录(包含 Android.mk 文件本身的目录)的路径,基本上是固定的,不需要去动LOCAL_PATH := $(call my-dir)# 会清除很多 LOCAL_XXX 变量,不会清除 LOCAL_PATH,基本上是固定的,不需要去动include $(CLEAR_VARS)# 需要构建模块的名称,会自动生成相应的 libNDKSample.so 文件,每个模块名称必须唯一,且不含任何空格LOCAL_MODULE := NDKSample# 包含要构建到模块中的 C 或 C++ 源文件列表LOCAL_SRC_FILES := HelloCPP.cpp# 指定这个模块里会用到哪些原生 API,详见:https://developer.android.google.cn/ndk/guides/stable_apis.htmlLOCAL_LDLIBS := -llog# 帮助系统将所有内容连接到一起,固定的,不需要去动include $(BUILD_SHARED_LIBRARY)
Application.mk
用于描述应用需要的原生模块,模块可以是静态库、共享库或可执行文件。Application.mk 通常也位于 jni 目录下。
# 选择不同的 ABI,多个使用空格作为分隔符,全部是allAPP_ABI := all# 指定要使用的运行时APP_STL := gnustl_static
接下来调用 C 或 C++
配置好 Android.mk 和 Application.mk,有两种方法可以调用 C 或 C++ 代码。现在我们写个方法,然后演示下 Android 这边的调用。
HelloCPP.cpp
简单返回一个字符串,C 或 C++ 这块我也不是很懂,能看懂大概意思,会调用就好了。
#include <jni.h>extern "C"JNIEXPORT jstring JNICALL Java_com_wuxiaolong_ndksample_HelloLibrary_sayHello(JNIEnv *env, jobject instance) { //从 C++ 传字符串到 Java return env->NewStringUTF("Hello from C++"); }
说明:
1、extern “C”:实现 C 和 C++ 的混合编程,用于 C++ 代码调用 C 的函数;
2、JNIEXPORT 和 JNICALL,用于标识函数用途的两个宏;
3、jstring,JNI 中的数据类型,对应 Java 中 String 类型,还有 8 种基本数据类型 jbyte、jchar、jshort、jint、jlong、jfloat、jdouble、jboolean,引用数据类型 jintArray、jshortArray、jlongArray 等。
4、函数命名规则:Java类全路径方法名,这里的类是那个调用 C 或 C++ 的类,像这里的 Java_com_wuxiaolong_ndksample_HelloLibrary_sayHello ;
5、函数至少有两个参数,第一个参数 :JNIEnv* 是定义任意 native 函数的第一个参数(包括调用 JNI 的 RegisterNatives 函数注册的函数),指向 JVM 函数表的指针,函数表中的每一个入口指向一个 JNI 函数,每个函数用于访问 JVM 中特定的数据结构;第二个参数:调用 Java 中 native 方法的实例或 Class 对象,如果这个 native 方法是实例方法,则该参数是 jobject,如果是静态方法,则是 jclass。
自动编译 C 或 C++ 代码
直接调用 C 或 C++ 代码,也可用于调试。
build.gradle
android { compileSdkVersion 27 defaultConfig { //…… externalNativeBuild { ndkBuild { //指定 Application.mk 的路径 arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk" //指定生成哪些平台的 so 文件 //abiFilters "armeabi-v7a", "armeabi" //cFlags 和 cppFlags 是用来设置环境变量的, 一般不需要动 cFlags "-DTEST_C_FLAG1", "-DTEST_C_FLAG2" cppFlags "-DTEST_CPP_FLAG2", "-DTEST_CPP_FLAG2" } } } externalNativeBuild { ndkBuild { //指定 Android.mk 的路径 path "src/main/jni/Android.mk" } } }
Sync Now,会看见项目多了 .externalNativeBuild 文件夹:
so 文件输出目录
app/build/intermediates/ndkBuild/debug/obj/local/arm64-v8a/libNDKSample.so
NDK 编译
使用命令 ndk-build,也可以生成对应的 so 文件,然后项目中调用。弊端 C 或 C++ 代码改动了,需要再次编译。
下载 NDK
配置环境变量
下载后 NDK 地址:/Users/wuxiaolong/Library/Android/sdk/ndk-bundle,进行 NDK 环境变量配置。
NDK 编译
进入 jni 目录,运行命令 ndk-build,如下:
so 文件输出目录
会在 jni 同一目录生成 libs,里面有对应的 abi。
build.gradle
需要 app/build.gradle 指定 so 文件路径方可调用。
android { //…… sourceSets.main { jni.srcDirs = [] jniLibs.srcDir 'src/main/libs' } }
以上两种方式可选其一。
HelloLibrary
创建 HelloLibrary 用于调用 C 或 C++ 代码。
public class HelloLibrary { static { //这里对应 Android.mk 里的 LOCAL_MODULE := NDKSample System.loadLibrary("NDKSample"); } //使用 native 关键字指示以原生代码形式实现的方法 public native String sayHello(); }
调用 HelloLibrary
可以在自己的 Activity 调用。
TextView text = findViewById(R.id.text); text.setText(new HelloLibrary().sayHello());
调试
如果 C 或 C++ 那边代码出问题了,调试起来要命的,之前只能 log,现在 Android Studio 提供了打断点来 debug C 或 C++ 代码,需要使用 LLDB 来检测到 C 或 C++ 代码中的断点,这里要使用 externalNativeBuild 方式自动编译 C/C++ 代码,才能进入断点进行调试。
Native 模式
选择 run 下拉 item,选 Edit Configurations,弹出配置窗体,1、添加;
2、命令app-native,专门调试 C/C++;
3、Module 还是选择 app;
4、Debugger 选择 Native,只想使用 LLDB 来调试代码,忽略 Java 代码中的断点。
我们致力于打造为广大的Android爱好者提供一个网络免费技术分享学习平台,每天进步一点点,每天收获一点点,关注本微信公众号,海量的学习视频资料等着你 ,大家也可以加下我们的Android免费学习群:517269161
本头条号还在不断创新和完善中,分享我们的文章到微信朋友圈 QQ空间 可以截图发我们领取Android开发实战精美学习资料,只要分享越多,学习干货更多!
猜你喜欢
- 2024-10-27 NDK开发——FFmpeg视频解码 ffmpeg ndk
- 2024-10-27 Camera基本代码架构 camera calibrator
- 2024-10-27 android 功耗分析方法和优化(1) 功耗app
- 2024-10-27 Cocos Creator v2.3.2 发布了!全新 Launcher 效率飞起!
- 2024-10-27 如何androd动态注册编写计算器 淘宝动态评分计算器在线
- 2024-10-27 高通平台OV8856 Camera的bring up总结
- 2024-10-27 高通平台移植GC2145 Camera驱动 高通驱动安装
- 2024-10-27 《坎公骑冠剑》光炮Android Mk.99技能与背景故事
- 2024-10-27 ubuntu移植libwebp到Android平台 ubuntu移植到arm
- 2024-10-27 步步为营,十分钟学会 Native JNI(附带彩蛋)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)