NDK开发入门终极教程
文章目录
- 0 前言
- 1 准备工作
- 1.1 下载 NDK
- 1.2 添加NDK依赖
- 1.3 添加cmake支持
- 2 新建支持NDk工程
- 3 给工程添加NDK支持
- 3.1 cmake
- 3.2 ndk-build
- 4 实践
- 4.1 生成头文件
- 4.2 编写 C 源码
- 4.3 运行截图
- 5 源码获取
0 前言
同NDK
技术的渊源始于3年前,使用so
文件的时候了解到NDK
技术,并且C
语言一直是强项,就鼓捣起NDK
开发。在AndroidStduio
还没推广的年代,基于eclipse
搭建NDK
开发环境需要安全依赖开发工具,并且调试起来具备难度。随后AndroidStudio
也先后支持nkd-build
和cmake
使用NDK
开发。
参见之前的博客:
eclipse下使用NDK开发so库
AndroidStudio配置NDK开发环境
1 准备工作
1.1 下载 NDK
当前 NDK 稳定版已经 发布到 r15c
。附上各个平台的下载地址:
android-ndk-r15c-windows-x86
android-ndk-r15c-windows-x86_64
android-ndk-r15c-darwin-x86_64
android-ndk-r15c-linux-x86_64
1.2 添加NDK依赖
解压下载好的文件在本地,在 AndroidStudio 工程配置(注意不是 AndroidStudio 工具配置)中指定 NDK 路径。
或者在local.properties
文件中指定NDK路径。
1.3 添加cmake支持
在 AndroidStudio 工具配置中,选择 Android SDK -> SDK Tools 中,勾选CMake并安装。
2 新建支持NDk工程
现在的AndroidStduio
更支持一种极简方式集成NDK
开发支持,即在下图中勾选include C++ support
。然后选择C++
标准。如C++ 11
。建选默认的ToolChain Default
。
之后正常 run 即可将 C 语言部分生成出 so 文件并打包到 apk 文件中。
3 给工程添加NDK支持
上述方式适合在新的工程中添加 NDK 支持。如何要在现有的项目中添加 NDK 支持,现提供 cmake
和 ndk-build
两种方式。
由于在同一个工程中,同时支持 cmake
和 ndk-build
两种方式编译 so 文件,因此将 C 源码单独放在 cpp-src
目录。且将 cmake
、ndk-build
区分不同的module
进行编译。
3.1 cmake
这是目前最受欢迎的集成方式,AndroidStduio 在创建新工程时默认使用该方式添加 NDK 支持。但在现有的工程中添加 NDK支持,需要手动配置。
创建 cmake module 添加个三个文件。
- CMakeLists.txt cmake编译配置文件
cmake_minimum_required(VERSION 3.4.1)add_library(hello-jni # so 库的名称 libhello-jni.soSHARED # 设置为分享库# 指定C源文件的路径,指向公共cpp-src目录../../../../cpp-src/hello-jni.c
)find_library(log-lib # 设置路径变量名称log # 指定CMake需要加载的NDK库
)# 链接hello-jni库依赖的库,注意下面变量名的配置
target_link_libraries(hello-jni${log-lib}
)
- AndroidManifest.xml 每个module必须的配置文件,指定packageName。
<?xml version="1.0" encoding="UTF-8" ?>
<manifest package="com.flueky.cmake"></manifest>
- Build.gradle 每个module必须的配置文件,用于构建项目。
apply plugin: 'com.android.library'android {compileSdkVersion 28defaultConfig{externalNativeBuild {cmake {// 指定配置参数,更多参数设置见 https://developer.android.google.cn/ndk/guides/cmakearguments "-DCMAKE_BUILD_TYPE=DEBUG"// 添加CPP标准
// cppFlags "-std=c++11"}}}externalNativeBuild {cmake {// 指定CMake编译配置文件路径path "src/main/cpp/CMakeLists.txt"}}
}
关于 CMake 编译参数的设置,更多内容请阅读官方资料。
眼尖的小伙伴已经发现两处配置了 externalNativeBuild
。其中第二处的externalNativeBuild
配置是生成Gradle Task
可以不运行工程,直接在 ndk-cmake -> Tasks -> other 找到编译 so 文件有关的四个任务。
双击 exeternalNativeBuildDebug
执行任务,如图:
根据路径即可找到生成的so文件。
3.2 ndk-build
这是最传统的 ndk 编译方式。在配置得当的情况下,可以在不打开 AndroidStudio 情况下完成so文件的编译和输出。
创建 ndk-build module ,添加4个文件。
- Android.mk
# 讲真,这个参数我看不懂。从 官方demo 抄来的。用于指定源文件的时候使用
abspath_wa = $(join $(filter %:,$(subst :,: ,$1)),$(abspath $(filter-out %:,$(subst :,: ,$1))))# 指定当前路径
LOCAL_PATH := $(call my-dir)# 指定源文件路径
JNI_SRC_PATH := $(call abspath_wa, $(LOCAL_PATH)/../../../../cpp-src)# 声明 clear 变量
include $(CLEAR_VARS)# 指定 so 库的名称 libhello-jni.so
LOCAL_MODULE := hello-jni
# 指定 c 源文件
LOCAL_SRC_FILES := $(JNI_SRC_PATH)/hello-jni.c
# 添加需要依赖的NDK库
LOCAL_LDLIBS := -llog -landroid
# 指定为分享库
include $(BUILD_SHARED_LIBRARY)
关于 Android.mk 编译参数的设置,更多内容请阅读官方资料
- Application.mk
# 指定编译的的so版本
APP_ABI := all
# 指定 APP 平台版本。比 android:minSdkVersion 值大时,会有警告
APP_PLATFORM := android-28
关于 Application.mk 编译参数的设置,更多内容请阅读官方资料
- AndroidManifext.xml
<?xml version="1.0" encoding="UTF-8" ?>
<manifest package="com.flueky.ndk"></manifest>
- build.gradle
apply plugin: 'com.android.library'android {compileSdkVersion 28externalNativeBuild {ndkBuild {// 指定mk文件路径path 'src/main/jni/Android.mk'}}defaultConfig {}
}
上面的externalNativeBuild
作用同 CMake
方式的一样,用于编译生成 so 文件。
但是 ndk-build 还支持使用命令ndk-build
编译 so 文件。 需要将 NDK 路径添加至环境变量。
需要在jni
目录下执行该命令:
最后生成的so文件路径如图;
4 实践
4.1 生成头文件
在主 module 中的 MainActivity中添加 native 方法 。使用 javah 编译出头文件。 使用 -d
参数指定头文件的输出目录。
public class MainActivity extends Activity {static {// 加载 JNI 库System.loadLibrary("hello-jni");}......// 声明 Native 方法private native String hello();
}
在 app/src/main/java
目录下执行命令 javah
4.2 编写 C 源码
在hello-jni.c
文件引用生成的头文件,并编写测试代码。
#include <string.h>
#include <jni.h>
#include "com_flueky_demo_MainActivity.h"
#include "util/log.h"/*** JNI 示例,演示native方法返回一个字符串,Java 源码见** ndk-sample/app/src/main/java/com/flueky/demo/MainActivity.java*/
JNIEXPORT jstring JNICALL
Java_com_flueky_demo_MainActivity_hello( JNIEnv* env,jobject thiz )
{
#if defined(__arm__)#if defined(__ARM_ARCH_7A__)#if defined(__ARM_NEON__)#if defined(__ARM_PCS_VFP)#define ABI "armeabi-v7a/NEON (hard-float)"#else#define ABI "armeabi-v7a/NEON"#endif#else#if defined(__ARM_PCS_VFP)#define ABI "armeabi-v7a (hard-float)"#else#define ABI "armeabi-v7a"#endif#endif#else#define ABI "armeabi"#endif
#elif defined(__i386__)#define ABI "x86"
#elif defined(__x86_64__)#define ABI "x86_64"
#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */#define ABI "mips64"
#elif defined(__mips__)#define ABI "mips"
#elif defined(__aarch64__)#define ABI "arm64-v8a"
#else#define ABI "unknown"
#endifLOGD("日志输出示例");return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI ".");
}
4.3 运行截图
页面截图:
日志截图:
5 源码获取
工程源码已开放在GitHub,下载地址。如果您有多余的CSDN积分,不防从这里下载。可以直接编写 C 源码并进行调试和生成 so 文件。
Google 官方资料需要翻墙才可以阅读。想了解翻墙方法,请点SSR。
觉得有用?那打赏一个呗。我要打赏
此处是广告:Flueky的技术小站
NDK开发入门终极教程相关推荐
- 【飞秋】Android开发——NDK开发入门
注:本文并非原创,参考了几位前辈的文章,本文只是稍作整理. 参考1:Eclipse配置NDK_R4开发环境(集成Cygwin .CDT) 分别介绍了在window和linux下配置eclipse自动化 ...
- Android NDK开发入门学习笔记(图文教程,极其详尽)
以前也简单用过JNI,但是只是简单用一下,好多都不明白.最近在看源码部分,有涉及到JNI调用的,所以这次打算彻底把它搞定. 先普及一下JNI的调用关系:JAVA-------------------- ...
- Android入门简书,android ndk开发入门随笔(一)
ndk,jni入门随笔 因为工作缘故最近在研究jni,ndk方面知识,在此总结入坑以来的一些问题. 配置环境可以在下面geogle官方看.下面是链接 我一说ndk,jni可能小伙伴要问了这是什么,在此 ...
- ndk开发入门!对Android开发的现状和未来发展的思考,灵魂拷问
前言 从2010年开始Android市场开始需要大量的Android开发人员,招聘市场上也开始大量招Android开发人员,大量java开发者开始学习Android开发,招聘市场面试要求上只要有一定j ...
- Windows驱动开发入门系列教程
从事驱动开发也有一段时间了,从最初的无头苍蝇到懵懵懂懂,到入门,直至今天,感觉一路走来,走了不少的弯路,只因为没有人引导.前几天,一个朋友问到我怎么学习Windows驱动开发,我就想到把我学习Wind ...
- Java学习开发入门基础教程系列
ava是一种跨平台的语言,一次编写,到处运行,在世界编程语言排行榜中稳居第二名(第一名是C语言). Java用途广泛,可以用来开发传统的客户端软件和网站后台,也可以开发如火如荼 Android 应用和 ...
- web前端开发入门基础教程系列
前端工程师是互联网时代软件产品研发中不可缺少的一种专业研发角色.从狭义上讲,前端工程师使用 HTML.CSS.JavaScript 等专业技能和工具将产品UI设计稿实现成网站产品,涵盖用户PC端.移动 ...
- Flutter实现微信支付和iOS IAP支付,ndk开发入门
} } 页面端是这样调用的 WechatPayment paymentUtils = new WechatPayment(); paymentUtils.wxPay( state.model.wxPa ...
- 手把手教你开发galgame 游戏(galgame 游戏引擎开发入门经典教程)
首先要给大家说明的是:软件工程知识,就是利用好现有游戏引擎这样省时省力 比如吉利吉利系统就是开源免费的,做自己的引擎也是好主意,这样可以充分享受DIY的乐趣! 我最近回味魔兽学院 MAN AT ...
最新文章
- 自己写的Python数据库连接类和sql语句拼接方法
- 千万级游标_在一个千万级的数据库查寻中,如何提高查询效率
- 27岁的张一鸣教给我们工作上的那些事
- java cache详解,Java内存缓存详解
- 疼恨皇明热水器的无耻!
- vba 修改access表的链接地址_神奇的VBA编程:禁止修改Excel工作表名称
- Product Overview page data loss handling
- Java:伪造工厂的闭包以创建域对象
- [react-router] React-Router的<Link>标签和<a>标签有什么区别
- 给你一碗孟婆汤,你会忘记什么?
- 精悍的Python代码段-转
- Markdown-Latex全称量词和存在量词(对于全体、存在)
- 图像局部特征(十六)--SimpleBlobDetector
- opencv计算机视觉学习笔记一
- 方案:软件集成测试工作流程指南
- Atitit Data Matrix dm码的原理与特点
- 模型预测控制的缺点_开发者说丨Apollo代码学习—模型预测控制(MPC)
- 我个人中意的VS2017/VS2019插件,推荐给大家(#^.^#)
- 如何从零学习游戏开发
- html中左三角怎么写,css3三角形怎么写?
热门文章
- java7java8 集合中对象的某一个字段分组
- 什么是多态?为什么要使用多态?什么时候用多态?多态是如何实现的?使用多态有什么好处?
- 掩膜裁剪tif步骤_ENVI中掩膜掩膜操作及影像分类教程(转)
- 【Linux】创建、修改和删除用户(useradd | usermod | userdel)
- 协议和协议栈的区别?
- Error evaluating expression ‘’. Return value () was not iterable.
- commit your changes or stash them before you can merge 解决方法
- 使用arduino mega2560制作一台超简易的假机械臂!
- 实现微信支付(Native支付),使用WebSocket进行推送——3.创建支付订单,接收付款结果
- 关于解决 Failed to prepare partial IU: