项目或者应用的包名:com.ang.ndkdemo

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

//创建的本地方法,具体功能在C或者C++中实现
public native String fromJNIString();

}

四、手动创建本地方法 fromJNIString() 对应的. h 头文件

1,在电脑的 cmd 或者 AndroidStudio 的 Terminal 中输入 javah -d D:\Demo\NDKDemo\app\src\main\jni -classpath D:\Demo\NDKDemo\app\src\main\java com.ang.ndkdemo.MainActivity

javah -d D:\Demo\NDKDemo\app\src\main\jni -classpath D:\Demo\NDKDemo\app\src\main\java
com.ang.ndkdemo.MainActivity

  • a, -d  D:\Demo\NDKDemo\app\src\main\jni      创建 jni 文件夹并指定. h 输出目录
  • b, D:\Demo\NDKDemo\app\src\main\jni           要创建的. h 头文件输出的绝对路径
  • c, D:\Demo\NDKDemo\app\src\main\java  com.ang.ndkdemo.MainActivity    包含本地方法 (fromJNIString()) 的类路径;注意不要写成了 D:\Demo\NDKDemo\app\src\main\java\com\ang\ndkdemo\MainActivity(把包名中的点 “.” 写成了斜杠 “****”,这样写是不对的) **;**com.ang.ndkdemo.MainActivity(注意是包名 + 类名);
  • 参数说明

-classpath :类搜索路径,这里表示从当前的 D:\Demo\NDKDemo\app\src\main\java 目录下查找

-d :将生成的头文件放到当前的 jni 目录下

-o : 指定生成的头文件名称,默认以类全路径名生成(包名 + 类名. h)

注意:-d 和 - o 只能使用其中一个参数。

注意: -d D:\Demo\NDKDemo\app\src\main\jni 和 -classpath D:\Demo\NDKDemo\app\src\main\java  位置可以互换;一下写法和等价于上面的写法;

javah -classpath D:\Demo\NDKDemo\app\src\main\java -d D:\Demo\NDKDemo\app\src\main\jni com.ang.ndkdemo.MainActivity

补充:可以通过 - o 指定生成的头文件名称,如果不指定,默认以类全路径名生成(包名 + 类名. h)

javah -classpath E:\Demo\JNIDemo\app\src\main\java -o E:\Demo\JNIDemo\app\src\main\java\jni\JNITest.h com.ang.MainActivity

2,执行以上命令之后:就在项目的 main 文件夹下创建了 jni 文件夹,并且在 jni 文件夹下自动创建了. h 头文件;头文件名也是自动生成的,命名规则是 com_ang_ndkdemo_MainActivity.h(包名 + 类名. h)

3,自动生成的 com_ang_ndkdemo_MainActivity.h 头文件代码

/* DO NOT EDIT THIS FILE - it is machine generated /
#include <jni.h>
/
Header for class com_ang_ndkdemo_MainActivity */

#ifndef _Included_com_ang_ndkdemo_MainActivity
#define _Included_com_ang_ndkdemo_MainActivity
#ifdef __cplusplus
extern “C” {
#endif
/*

  • Class: com_ang_ndkdemo_MainActivity
  • Method: fromJNIString
  • Signature: ()Ljava/lang/String;
    */
    JNIEXPORT jstring JNICALL Java_com_ang_ndkdemo_MainActivity_fromJNIString
    (JNIEnv *, jobject);

/JNIEnv 是定义任意native函数的第一个参数(包括调用JNI的RegisterNatives函数注册的函数),指向JVM函数表的指针,函数表中的每一个入口指向一个JNI函数,每个函数用于访问JVM中特定的数据结构。*/

#ifdef __cplusplus
}
#endif
#endif

4,生成. h 头文件时候,如果出现 “找不到类文件” 的错误请参考  blog.csdn.net/ezconn/arti… 这篇文章

注意:

a. 包名或类名或方法名中含下划线 _ 要用 _1 连接;

b. 重载的本地方法命名要用双下划线 __ 连接;

c. 参数签名的斜杠 “/” 改为下划线 “_” 连接,分号 “;” 改为 “_2” 连接,左方括号 “[” 改为 “_3” 连接;

另外,对于 Java 的 native 方法,static 和非 static 方法的区别在于第二个参数,static 的为 jclass,非 static 的 为 jobject;JNI 函数中是没有修饰符的。

五、在 jni 目录下创建 c 或者 c++ 文件;

文件名可以随意写,但需要注意文件类型;Hello.c 文件(.c 后缀的文件为 C)代表内容是 C 代码;Hello.cpp(.cpp 后缀的文件为 C++)文件代表内容是 C++ 代码;

C++ 代码(注意 C 和 C++ 代码是有区别),以下分别给出 C 和 C++ 两种实现方式:

  • a,Hello.c 文件。在 C 中没有引用,传递的 env 是个两级指针,用(*env)-> 调用方法且方法中要传入 env.

#include <jni.h>
#include “com_ang_ndkdemo_MainActivity.h”
JNIEXPORT jstring JNICALL
Java_com_ang_ndkdemo_MainActivity_fromJNIString(JNIEnv* env, jobject obj) {
return (*env)->NewStringUTF(env,“I am From Native C”);
}

  • b, Hello.cpp 文件。C++ 中 env 为一级指针,用 env-> 调用方法,无需传入 env;C++ 语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而 C 语言则不会,因此会造成链接时找不到对应函数的情况,此时 C 函数就需要用 extern “C” 进行链接指定,这告诉编译器,请保持我的名称,不要给我生成用于链接的中间函数名;exter  “C”{jni 代码}。

#include <com_ang_ndkdemo_MainActivity.h>
#include <stdio.h>

JNIEXPORT jstring JNICALL
Java_com_ang_ndkdemo_MainActivity_fromJNIString(JNIEnv *env, jobject obj)
{
return env->NewStringUTF(“I am From Native C”);
}

Java 的 native 方法是如何链接 C/C++ 中的函数的呢?可以通过静态和动态的方式注册 JNI。 以上是通过静态注册的方式。

静态注册:根据函数名建立 Java 本地方法和 JNI 函数的一一对应关系。

动态注册:直接告诉 Java native 方法其在 JNI 中对应函数的指针。

六、配置 build.gradle(Model:App)

也可以不配置 ndk{}, 这里只是指定编译出哪几种对应的 abi 架构的. so 库,如果不配置,会根据 ndk-build 默认输出对应的 abi 架构的. so 库;最好配置,不然不能编译出自己想要的对应 ABI 架构的. so,如果自己的项目中已经引用其他的. so 库还要做适配;

defaultConfig {
applicationId “com.ang.demo”
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName “1.0”
testInstrumentationRunner “android.support.test.runner.AndroidJUnitRunner”

//ndk编译生成.so文件
ndk{
moduleName “Java2c” //生成的so名字,Android.mk文件中已经指定了,这里可以不写
abiFilters “armeabi”, “armeabi-v7a”, “x86” //输出指定三种abi体系结构下的so库。
}
}

七、编写 Android.mk 文件

Android.mk 文件一般包含如下信息就够了,差不多可算得上一个模板;根据自己的. so 库名和 C 或者 C++ 文件名修改一下就可以用了;

LOCAL_PATH:= $(call my-dir)#不用修改

include $(CLEAR_VARS)#不用修改

LOCAL_MODULE:= hello #动态库名称
LOCAL_SRC_FILES:= hello.c #C文件,里面就是我们写的C代码

include $(BUILD_SHARED_LIBRARY)#生成.so动态库

#include $(BUILD_STATIC_LIBRARY) 编译出.a的静态库

还有一种方式,就是让 androidstudio 自动生成;如下是我获取自动生成的 Android.mk 文件的方式:

a, 紧接着步骤六之后,点击 Androidstudio 菜单栏 Build ->ReBuildProject

报错:

b, 在 app ——> build ——>intermediater——>ndk(自动创建) 目录下自动创建了一个 Android.mk 文件

Android.mk 文件如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := Java2c
LOCAL_LDFLAGS := -Wl,–build-id
LOCAL_SRC_FILES :=
D:\Demo\NDKDemo\app\src\main\jni\Hello.cpp \

LOCAL_C_INCLUDES += D:\Demo\NDKDemo\app\src\debug\jni
LOCAL_C_INCLUDES += D:\Demo\NDKDemo\app\src\main\jni

include $(BUILD_SHARED_LIBRARY)

八、修改默认编译工具

鼠标右键项目,点击 Link C++ Project with Gradle 修改 Androidstudio 默认编译工具, 在 BuildSystem 栏选择 ndk—build, 在 ProjectPath 选项栏,找到刚才创建的 Android.mk 文件(其实就是 Android.mk 文件路径),点击 OK 之后就在 build.gradle(Model:App)的 android{} 中自动生成了 externalNativeBuild { ndkBuild { path ‘src/main/jni/Android.mk’} }

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5d3a984900664469aff1ed02e6016f3d~tplv-k3u1fbpfcp-zoom-1.imag

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

开源分享完整内容戳这里

e)

//增加之后如下信息之后,右键项目的时候Link C++ Project with Gradle选项不再显示;
externalNativeBuild {
ndkBuild {
path ‘src/main/jni/Android.mk’
}
}

注意:有的时候需要再次显示 Link C++ Project with Gradle 选项,删掉 externalNativeBuild {ndkBuild {   path ‘src/main/jni/Android.mk’} } 点击 sync now 同步一下;再次右键项目就可以出现了;

**相关知识:**要将 Gradle 关联到原生库,需要提供一个指向 CMake 或 ndk-build 脚本文件的路径。在构建应用时,Gradle 会以依赖项的形式运 CMake 或 ndk-build,并将共享的. so 库打包到 APK 中。externalNativeBuild 就是配置的脚本路径;
{ndkBuild {   path ‘src/main/jni/Android.mk’} } 点击 sync now 同步一下;再次右键项目就可以出现了;**

**相关知识:**要将 Gradle 关联到原生库,需要提供一个指向 CMake 或 ndk-build 脚本文件的路径。在构建应用时,Gradle 会以依赖项的形式运 CMake 或 ndk-build,并将共享的. so 库打包到 APK 中。externalNativeBuild 就是配置的脚本路径;

Android NDK开发,使用ndk-build编译,写的太详细了相关推荐

  1. 【Android NDK 开发】NDK 交叉编译 ( Ubuntu 中交叉编译动态库 | Android Studio 中配置使用第三方动态库 )

    文章目录 I . 动态库 与 静态库 II . 编译动态库 III. Android Studio 使用第三方动态库 IV . Android Studio 关键代码 V . 博客资源 I . 动态库 ...

  2. Android 高级开发 JNI NDK 介绍与使用

    Android 高级开发 JNI & NDK 介绍与使用 前言 对于没接触过的领域,即是挑战也是机遇,不仅能够提升自己的能力.还能够学习到新的技术知识 而学习新的技术的时候,最好是从头开始按照 ...

  3. Android NDK开发一 NDK环境搭建及cmake简介

    1 前言 关于NDK的介绍可以查看官方的介绍: https://developer.android.com/ndk/guides/index.html 一句话总结NDK:NDK(Native Deve ...

  4. 【Android NDK 开发】NDK C/C++ 代码崩溃调试 - Tombstone 报错信息日志文件分析 ( 使用 addr2line 命令行工具查找动态库中的报错代码位置 )

    文章目录 一.从 Tombstone 报错日志中查找报错动态库 二.addr2line 命令行工具使用 64 位动态库使用的 aarch64-linux-android-addr2line.exe 工 ...

  5. 【Android NDK 开发】NDK 交叉编译 ( NDK 函数库目录 | Linux 交叉编译环境搭建 | 指定头文件目录 | 指定函数库目录 | 编译 Android 命令行可执行文件 )

    文章目录 I . NDK platforms 目录下的 函数库 II . Ubuntu 配置 NDK 交叉编译环境 III . 同时指定编译的头文件和库文件 IV . 指定编译的头文件 V . 指定编 ...

  6. 【Android NDK 开发】NDK C/C++ 代码崩溃调试 - Tombstone 报错信息日志文件分析 ( 获取 tombstone_0X 崩溃日志信息 )

    文章目录 一.崩溃信息描述 二.手机命令行操作 三.电脑命令行操作 四.Tombstone 内容 Tombstone 报错信息日志文件被保存在了 /data/tombstones/ 目录下 , 先 R ...

  7. Android NDK开发配置NDK

    在Android的官网下载android NDK 地址点击下载 下载之后解压到自己的目录下,我的是/home/zhycheng/ 然后在终端执行 chmod 777 android-ndk-r8 这条 ...

  8. Android Studio开发配置NDK环境

    今天使用Fresco的一个demo,但是build失败,去网上搜了一下,发现是NDK环境没配置好,见如下链接: 导入Fresco后build失败 配置NDK见如下链接: 配置NDK环境 转载于:htt ...

  9. Android软件开发实例:用客户端写博客

    标题:在Android上通过客户端写博客软件开发实例 作者:肖凤斌 binsweet@gmail.com 关注Android很久了,年初买了G4,但一直没有机会尝试Android上的软件开发. 自己有 ...

  10. Android内核开发 Goldfish Linux Kernel编译及安卓虚拟机测试

    本文出处: http://blog.csdn.net/leytton/article/details/52736549 1.配置交叉编译环境 作者用的是android-ndk的/交叉编译工具 方法一: ...

最新文章

  1. C 函数别名简单记录
  2. Spring Boot 项目如何做性能监控?
  3. new 开始转向PHP
  4. boost::hana::overload用法的测试程序
  5. MySQL 高级 - 语法 - if判断
  6. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 2丨连续出现的数字【难度中等】
  7. 获取freemarker处理后的内容
  8. oracle jinitiator版本太旧,Oracle Jinitiator 版本太旧或过低怎么办
  9. Eclipse没有的工程原型或模板创建maven失败
  10. java 7 Reflection详解(二),获取class对象信息
  11. JavaEE Tutorials (7) - 在会话bean中使用异步方法调用
  12. epoll和poll的C++11多线程练习
  13. 外边距合并(HTML、CSS)
  14. IAT 注入ImportInject(dll)
  15. ORACLE SQL日期函数
  16. 智慧城管系统提高城市综合管理水平
  17. dorado7.x控制显示隐藏
  18. 二级域名和一级域名的区别
  19. Navicat Premium使用教程
  20. MySQL学习(一)脏读、不可重复读、幻读(鸣人和佐助上学的故事)

热门文章

  1. SEGGER调试利器RTT,替代串口,高速数据上传
  2. MVVM框架原理浅析
  3. mvvm框架 android,Android MVVM 框架 MVVMFramework
  4. setting-mirrorO以及下载jar包流程简介
  5. 用计算机进行进制换算方法,计算机进制怎么转换?计算机进制换算方法
  6. python xlwt写excel_Python使用xlwt写excel并设置写入格式
  7. Python 库学习 —— Excel存储(xlwt、xlrd)
  8. PCI-E接口的学习
  9. 信息系统项目管理师计算题(进度管理总浮动时间、自由浮动时间、工期)
  10. 笔记本计算机的连接无线网络,笔记本电脑连接无线网络受限解决方法