NDK开发(一)————如何在Android Studio下进行NDK开发

2023-10-27

    在AS中进行NDK开发之前,我们先来简单的介绍几个大家都容易搞懵的概念:

        1. 到底什么是JNI,什么是NDK?

        2. 何为“交叉编译”?

    先看什么是JNI?JNI的全称就是Java Native Interface,即java本地开发接口。可能大家和我一样,一听到接口什么的就犯懵:“我也知道这是java本地开发接口的意思,但它具体是个什么意思我还是搞不明白。”其实JNI它就是一种协议,一说协议,那它就是对某种东西的一个规范和约束,说的好听一点就是标准化。如果你想用我这个东西,那你必须要遵守我这边的规范。像http协议一样,http作为超文本传输协议,它规范了我们上网时从客户端到服务器端等一系列的运作流程。正因为如此,我们才能畅通无阻的上网。那么换做JNI也一样,只不过JNI这个协议是用来沟通java代码和外部的本地代码(c/c++)。也就是说有了JNI这个协议,我们才能够随意的让java代码调用C/C++的代码,同样C/C++的代码也可以调用java的代码。如果没有这个协议作为支撑,那么java和C/C++代码想要相互调用是不可能的。下面通过两个图简单看一下JNI协议在系统架构中处于什么位置

                                     

    在上图中,上层绿色的部分一般都是用Java代码写的,下层橘黄色的部分一般都是用C/C++代码写的。可以看出,正式由于有了中间JNI的存在我们才可以在Application层通过JNI调用下层中的一些东西。了解了JNI的概念后,我们再看看NDK,NDK(Native Development Kit)就比较好理解了,它就是一个本地开发的“工具包”。Java开发要用到JDK,Android开发要用到SDK,那我们在Android中要进行native开发,也要用到它对应的工具包,即NDK。通俗的来讲,NDK就是帮助我们可以在Android应用中使用C/C++来完成特定功能的一套工具。 NDK的作用有很多,我们简单的列举两个,比如:

        1.首先NDK可以帮助开发者“快速”开发C(或C++)的动态库。

        2.其次,NDK集成了“交叉编译器”。使用NDK,我们可以将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。

    上面提到了“交叉编译”,我们最后再解释一下什么是交叉编译。大家都知道编译器在将中间代码连接成当前计算机可执行的二进制程序时,连接程序会根据当前计算机的CPU、操作系统的类型来转换。而根据运行的设备的不同,CPU的架构也是不同,大体有如下三种常见的CUP架构:

  • arm结构 :主要在移动手持、嵌入式设备上。我们的手机几乎都是使用的这种CUP架构。
  • x86结构 : 主要在台式机、笔记本上使用。如Intel和AMD的CPU 。
  • MIPS架构:多用在网关、猫、机顶盒等设备。
    若想在使用了基于x86架构CPU的操作系统上编译出可以在基于arm结构CPU的操作系统上运行的代码,就必须使用交叉编译。所以综上所述:交叉编译就是在一个平台下(比如:CPU架构为X86,操作系统为Windows)编译出在另一个平台上(比如:CPU架构为arm,操作系统为Linux)可以执行的二进制代码。Google提供的NDK就可以完成交叉编译的工作。
    好了,上面的基本概念介绍完以后,我们正式进入AS下NDK开发的讲解。
    1.首先,你需要把NDK下载下来NDK下载。下载完成后解压到任意目录即可(路径中不要带有中文字符)。我的就直接放在 D盘的ndk目录下:
                  
    2.在AS中为你的项目配置NDK。首先新建一个Android工程JNIDemo,Ctrl + shift + alt + s打开Project Structrue把我们刚才下载好的NDK 配置进去,点击OK。
    3.配置好NDK后,简单的为我们的项目布局文件添加一个TextView和一个Button,当点击Button的时候,我们通过调用底层自己写好的C/C++ 代码来返回一个字符串,最后呈现在TextView上。
activity_main.xml布局代码:
```
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        />
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="button"/>
</LinearLayout>
```
MainActivity.java
```
public class MainActivity extends AppCompatActivity {

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

        final TextView textview = findViewById(R.id.textview);
        Button button = findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textview.setText(JNIUtils.sayHelloFromJNI());
            }
        });
    }
}    	
```

上面代码中的JNIUtils.sayHelloFromeJNI()就是我们在与MainActivity相同的包中新建JNIUtils类后在里面编写的native方法。如下所示:

可以看到我们上面的sayHelloFromJNI()方法显示的是警告红色。把鼠标放到上面,它会提示我们对应的JNI头文件没有查找到。那么接下来我们要做的就是去生成与这个sayHelloFromJNI()方法所对应的头文件。
    4.生成头文件。快捷键alt + F12调出AS下的Terminal窗口,在Terminal命令行窗口中输入如下几条指令,回车:
前面两个cd命令没什么好说的,就是先进入当前项目的app目录下,然后再进入Java目录下。我们重点说一下最后一条命令:javah -d ../jni com.example.zhangxudong.jindemo.JNIUtils。首先,要生成Java类对应的头文件我们就必须要用到javah这个命令,其次-d表示生成一个目录,那生成一个什么样的目录,具体又在哪里去生成这个目录呢?后面的../jni告示了我们。../表示在当前目录的上一层目录,我们当前在Java目录下,那么它的上层目录就是main目录了。而jni就表示我们生成的目录的名称。所以整个../jni就表示在main目录下生成一个名为jni的目录。最后一个com.example.zhangxudong.jindemo.JNIUtils就是我们在上面新建的JNIUtils的完整类名了。执行完这几天指令后,刷新一下目录我们就可以在main目录下看到jni这个目录,并且在它里面生成了我们JNIUtils类所对应的头文件。进入头文件中,代码是如下这个样子:
```
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_zhangxudong_jnidemo_JNIUtils */

#ifndef _Included_com_example_zhangxudong_jnidemo_JNIUtils
#define _Included_com_example_zhangxudong_jnidemo_JNIUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_zhangxudong_jnidemo_JNIUtils
 * Method:    sayHelloFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_zhangxudong_jnidemo_JNIUtils_sayHelloFromJNI
  (JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
```
    5.头文件生成以后,我们就需要编写我们的C/C++代码了。右键jni目录---->new--->C/C++ Source File

输入要新建的C/C++文件名称JNIHello,这里我们用C++来编写,所以Type为.cpp,如果你选择用C来编写,那么Type选为.c,点击ok。这里说一下,在我们进行NDK开发的时候,选择用C还是C++,在编写代码的时候除了C和C++基本的语法不同外,还是有许多不同地方需要注意。我们后续会慢慢介绍。这里先默认跟着我的步骤来。
                           
JNIHello.cpp代码如下:
#include "com_example_zhangxudong_jnidemo_JNIUtils.h"
JNIEXPORT jstring JNICALL Java_com_example_zhangxudong_jnidemo_JNIUtils_sayHelloFromJNI
        (JNIEnv *env, jclass jclass){
return env->NewStringUTF("Hello World From JNI!!!!!");
}

可以看到我们首先需要把原来生成的JNIUtlis对应的头文件引入进来,下面的代码基本都是从com_example_zhangxudong_jnidemo_JNIUtils.h中复制粘贴过来的一部分,然后稍加修改。修改的地方主要有sayHelloFromJNI的两个参数和里面的简单实现,参数方面就是加了env和jclass两个字段。函数里面的实现呢,就是简单的返回一个字符串“Hello World From JNI!!!!!”,至于为什么这么写,我会在下一篇文章进行讲解,大家现在就需要知道如果要在这里返回一个字符串就必须要通过env->NewStringUTF("xxxxxx");这行代码。
    6.上面的搞定以后,我们需要在app的build.gradle中的defaultConfig中加入如下代码。它表示项目在编译时生成的动态库的名字。
最后,我们还需在JNIUitls中加载我们生成的动态库:
```
public class JNIUtils {
    static {
        System.loadLibrary("JNIHello");
    }
    public static native String sayHelloFromJNI();
}
```
我们把加载动态库的代码放到静态代码块中,就是表示在JNIUtils这个类在加载的时候就去加载我们的动态库。
    7.经过上面的5步,关于如何在AS中进行简单的NDK所需要的步骤差不多就讲完了。不过还有最后一点需要注意。到这里我们基本就可以执行一下我们的项目了,现在运行一下项目试一试......不出意外的话项目是build不成功的,它会报如下的错误:
```
Error:Execution failed for task ':app:compileDebugNdk'.
> Error: Flag android.useDeprecatedNdk is no longer supported and will be removed in the next version of Android Studio.  Please switch to a supported build system.
  Consider using CMake or ndk-build integration. For more information, go to:
   https://d.android.com/r/studio-ui/add-native-code.html#ndkCompile
   To get started, you can use the sample ndk-build script the Android
   plugin generated for you at:
   E:\JNIDemo\app\build\intermediates\ndk\debug\Android.mk
  Alternatively, you can use the experimental plugin:
   https://developer.android.com/r/tools/experimental-plugin.html
  To continue using the deprecated NDK compile for another 60 days, set 
  android.deprecatedNdkCompileLease=1515317190556 in gradle.properties
```
因为我这里用的是Android Studio3.0,报出的这个错误很可能和原来版本的AS不同,以前出现类似错误的时候,我们的解决方案一般都是在gradle.properties中添加一行这样的代码:android.useDeprecatedNdk=true就搞定了。但是AS换为3.0后你可以再试一下这种方案,肯定是不行的,它会提示你“Flag android.useDeprecatedNdk is no longer supported and will be removed in the next version of Android Studio.  Please switch to a supported build system.”大体意思就是最新的AS已经不支持useDeprecatedNdk这个标记了,并且在后续版本的AS中,它将被移除。所以我们新的解决方案就是按照它的提示在gradle.properties中添家android.deprecatedNdkCompileLease=1515317190556这行代码。
    最后我们运行一下项目,点击button,效果如下。可以看到,我们成功的通过java代码调用了C++的代码,并返回Hello World From JNI!!!!!这个字符串。
                                       


   
那我们生成的动态库(.so文件)都在哪里呢?点开app--->build--->intermediates--->ndk--->debug--->libs,可以看到各个平台对应的动态库都已经生成了。
                                  
    关于NDK在Android Studio下的开发先讲到这里,希望大家多多支持可怜
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NDK开发(一)————如何在Android Studio下进行NDK开发 的相关文章

  • Android WebView使用技巧

    1 不使用WebView缓存 使用场景 通过WebView输入用户名和密码进行登录 退出登陆后 再进行登录会默认是之前输入的用户名和密码登录 那么使用如下方式可以设置webview的缓存模式 WebSettings seting web v
  • Android Studio下载、安装和配置+SDK+tools下载(无敌超级详细版本)

    下载 Anderson Studio是Google为Android提供的官方IDE工具 下载地址 http www android studio org 此处下载3 4 1版本 安装环境要求 其中JDK的最低版本是1 7 所以系统空闲内存至
  • Adroid游戏开发实例讲解(四)-电子白板附源码

    Adroid游戏开发实例讲解 四 电子白板附源码 程序之美 电子白板 在很多Android设备中经常会用到 比如说Android电视 触摸屏用上手写笔 轻松在上面写字 比如视频教学Android设备 有很多培训教学机构 都放有Android
  • compileDebugKotlin FAILED Unresolved reference: xxxx

    Task client compileDebugKotlin FAILED e MainActivity kt 64 13 Unresolved reference CommendUtils A项目引用了library 但是一直报错 解决
  • Android中ImageView控件scaleType属性详解

    ImageView的具体属性 1 显示在ImageView的中心的属性 分别为 centerCrop center centerInside fitCenter 2 ImageView全部的属性 3 具体属性分析 android scale
  • Android Studio中SVN重新关联项目,使其文件变色

    一般我们的项目中文件夹中通过svn关联 通过Android Studio打开按道理的话 可算是关联了 这里先普及下 SVN的文件的颜色所代表的意思 如下 绿色 已加入VCS 但未提交 红色 未加入VCS 白色 已提交 蓝色 有修改 问题 在
  • AndroidStudio显示Minimum supported Gradle version is 6.5

    AndroidStudio显示Minimum supported Gradle version is 6 5错误的解决办法 其实就是你导入的项目使用的Android gradle 插件 与当前你的Android studio 的Androi
  • Android Studio开发环境的搭建

    Android Studio开发环境的搭建 一 实验目的及任务 Windows下掌握Android Studio的安装和配置 模拟器的创建 Activity的创建和注册 二 实验环境 Jdk Android Studio 三 实验步骤 An
  • Android NDK 编译 三方库记录 及 jni库封装问题

    因工作需求 要将原先的c 库跨平台编译 在Android上运行 其依赖了几个第三方库 也需要一起编译 在此做个记录 所需工具 centos 系统上完成 1 cmake 3 15 6 2 ndk android ndk r21e NDK 下载
  • AGPBI: {“kind“:“error“,“text“:“Program type already present: android.support.v4.os.ResultReceiver$1“

    使用环境 遇见 解决方法 第一步 object下的build gradle文件中build gradle版本号修改 第二步 object下的Gradle版本号修改 具体对应版本 没有一个固定的对应关系 取决于创建项目时创建者当时的AS环境
  • 【Android】Android ANR产生过程与分析方法

    前言 Android ANR问题一直是比较难解决的问题 一来它比较难以复现 二来复现后也不太好分析 这篇文章梳理一下ANR产生的过程以及出现ANR拿到日志文件如何定位原因 其实关于ANR线上监控也是比较棘手的 看了这篇文章我们再去看一些AN
  • android通过JNI用C/C++创建本地文件

    通过jni在本地创建文件 1 在android studio创建基本的jni工程 并且在APP界面成功显示 Hello from C 不会的可以看android studio使用jni 2 在native lib cpp文件中创建文件 为了
  • 《0基础学安卓逆向》第1集:什么是安卓逆向及环境搭建

    1 安卓逆向是什么 安卓逆向是什么 目前百度知道都没有收录安卓逆向这个词条 大部分能搜索到的资料都是技术人员写的偏技术类的文章 往往充斥着代码和各类工具集合 非技术人员一看就比较懵逼 简单地来说 安卓逆向是对已经打包好的APP进行反编译 源
  • android studio3.1调试

    快捷键 ctrl alt left或者ctrl alt right 回退 前进 双击快捷键 shift 全局搜索 快捷键 shift F9 开始调试 快捷键 F6 单步执行程序 快捷键 F5 单步执行程序 遇到方法时进入 快捷键 F8 调到
  • 开发百度地图定位APP(LBS)

    一 注册成为百度地图开发者 并获取开发密钥 获取密钥时需要进入Android studio使用keytool文件获取SHA1码 二 下载开发包解压并导入Android studio 选择自己需要的开发包下载 这里我选择的是基础地图基础定位J
  • 使用NDK编译C/C++文件生成在安卓中的可执行文件

    使用NDK编译C C 文件生成在安卓中的可执行文件 需求 要编译一个C文件 然后将他运行到安卓手机中 通过这个可执行文件可以获取一些硬件的参数信息 或者对已经有的信息进行修改 从而达到我们想要的效果 相关知识点记录 NDK Native D
  • Android Studio卸载以及安装教程

    手把手教学安卓安装 一 卸载教程 如果是第一次安装 直接看往下翻 1 先把Android Studio卸载2 将安装残余一起卸载 一定要卸载干净 否则在二次安装时会出现一大堆问题 a b c 好啦 到这里 所有的残余都已经删除干净 下面进入
  • 安装 Android Studio

    安装 Android Studio 只需轻松点击几下 您需要已下载 Android Studio Windows 如需在 Windows 系统中安装 Android Studio 请执行以下操作 启动您下载的 exe 文件 根据安装向导的指
  • Android发送POST网络请求

    参考链接 Android 网络请求 网络请求 Okhttp 51CTO博客 android 网络请求 项目中需要通过发送网络请求获取需要显示的数据内容 请求地址和requestbody如上图所示 网络请求用 implementation c
  • Android Studio Android Flutter问题记录 - UNABLE TO FIND BUNDLED JAVA VERSION

    前言 有个紧急问题需要修复 本以为很快就能解决继续休假 没想到项目打开运行后Android端跑不起来了 iOS端正常运行 这就有点莫名其妙 明明放假前还是没问题的 难道我拉取的最新代码有问题 不会吧 谁放假还敲代码啊 樂 看了下最新的提交记

随机推荐

  • C# 数据库存储过程的讲解应用

    在使用VS 2012 SQL Server做简单的销售系统中 通常会遇到一些使用存储过程的情况 那究竟什么是存储过程 它的好处是什么呢 如果在SQL Server中创建一个存储过程 C 中怎样联系存储过程呢 一 存储过程 存储过程 Stor
  • C++类和对象上篇

    面向过程和面向对象的初步认识 C语言是面向过程的 关注点在于过程 分析出求解问题的步骤 通过函数调用逐步解决问题 C 是面向对象的 关注点在于对象 将一件事拆分成不同的对象 靠对象之间的交互完成 我们就外卖系统来看看面向过程和面向对象之间的
  • RabbitMQ提示错误:java.net.SocketException socket closed

    RabbitMQ提示错误 java net SocketException socket closed问题 原因是配置的用户权限问题 rabbitmq包括很多种权限 需要把在项目中配置的账户修改为management类型 权限规则 http
  • flutter开发实战-MethodChannel实现flutter与iOS双向通信

    div class markdown views div
  • 对于cin提取输入流遇到空格的问题

    引子老谭CPP教材 流提取符 gt gt 从流中提取数据时通常跳过流中的空格 tab键换行符等空白字符 P430页倒数第10行 13 3 1 cin流 用cin gt gt 读取数据时遇到空白字符 包括空格 tab键和回车 作为终止字符 P
  • Eigen学习教程(三)

    Eigen学习教程 三 3 稠密线性问题与分解 本节说明了如何求解线性系统 计算各种分解 例如LU QR SVD 本征分解 阅读此节后 请不要错过我们的密集矩阵分解目录 基本线性求解 Ax b 该解决方案 可将各种分解之间进行选择 取决于你
  • 计算机英特尔显卡在哪找,Win10英特尔显卡设置在哪里 英特尔核芯显卡控制面板六大功能详解...

    Win10系统用户体验相比以前的系统更好 有些用户为了让显卡发挥作用 会在win10里设置显卡功能 显卡设置在哪里 显卡控制面板 显卡控制面板有Intel AMD NVADIA三种 我们通过显卡的控制面板进行显卡更为高级的设置 这时我们就需
  • MATLAB快速入门(一)

    一 简介 本篇参考官方入门文档编写 前提准备 MATLAB 二 快速入门 一 1 桌面基础知识 启动 MATLAB 时 桌面会以默认布局显示 桌面包括下列面板 当前文件夹 访问您的文件 命令行窗口 在命令行中输入命令 由提示符 gt gt
  • c++--标准模板库(STL)

    要看懂STL相关 必须了解c 模板 目录 STL是什么 c 标准模板库包含三个组件 算法 迭代器 迭代器的种类 示例程序 容器 常用的容器 编程练习 string 字符串容器 vector 向量 list 双向链表容器 queue 队列容器
  • Excel 的那些事儿啊

    RIGHT 函数 功能 可以对数值 字符串 进行截取 是从后面开始截取的 语法 RIGHT 截取的数值 截取的个数 使用 例如我们想提前 ID 列中数值的后面的数字 可以使用该函数 1 书写函数 RGIHT A3 3 对 A3 单元格进行截
  • mysql中on duplicate key update用法(批量操作数据、存在更新,不存在则新增),附mybatis配置

    1 应用场景 日常开发中 对于一个数据想做到存在即更新 不存在则新增 通常的做法是先查询数据库中是否存在对应的数据 如果存在就使用更新的方法 不存在就使用新增的方法 如果是单个数据 倒也没什么问题 但如果是批量数据的话 会消耗大量的资源来进
  • 字符串截取之substring_index

    substring index str delim count str 要处理的字符串 delim 分隔符 count 计数 例子 str www wikidm cn substring index str 1 结果是 www substr
  • 自主开发悟空crm增加 公文管理功能 二次开发代码披露

    1 招聘需求 2 审核刚刚创建的招聘需求内容 3 编辑内容 4 简历管理 5 面试记录时间轴 6 offer管理
  • golang interface判断为空nil

    一个接口包括动态类型和动态值 如果一个接口的动态类型和动态值都为空 则这个接口为空的 func IsNil i interface bool vi reflect ValueOf i if vi Kind reflect Ptr retur
  • 【性能测试】性能测试之性能测试指标详解(详细)

    目录 导读 前言 一 Python编程入门到精通 二 接口自动化项目实战 三 Web自动化项目实战 四 App自动化项目实战 五 一线大厂简历 六 测试开发DevOps体系 七 常用自动化测试工具 八 JMeter性能测试 九 总结 尾部小
  • 华为数通方向HCIP-DataCom H12-831题库(单选题:21-40)

    第21题 R3与R1的IS IS邻居没有建立 根据本图的信息 可能的原因是 A R3与R1的IIH认证失败 B R3与R1的System ID重复 C R3与R1的IS Level不匹配 D R3与R1的互连接口circuit type不匹
  • 1282、用户分组

    题目描述 有 n 位用户参加活动 他们的 ID 从 0 到 n 1 每位用户都 恰好 属于某一用户组 给你一个长度为 n 的数组 groupSizes 其中包含每位用户所处的用户组的大小 请你返回用户分组情况 存在的用户组以及每个组中用户的
  • 不同文件类型转base64后的前缀

    写在前面 最近在做office文件上传 需求是这样的 若前端用户上传的是PDF文件 则后端将PDF的第一页转成图片返给前端 若用户上传的是word Excel文件 前端将文件的base64传给后端 后端将文件转成PDF 并将第一页转成图片返
  • 数字医疗“疫”外增长,梅斯健康上市抢跑?

    马云曾说 中国下一个首富 一定在大健康领域 如他所判断的 当下医疗健康领域存在的投资机会逐渐清晰 2021中国大健康趋势发展报告 也称 未来十年 最好的医疗健康产业机会在中国 与这个论点相对应 国内医疗行业发展迅速 港交所官网显示 2021
  • NDK开发(一)————如何在Android Studio下进行NDK开发

    在AS中进行NDK开发之前 我们先来简单的介绍几个大家都容易搞懵的概念 1 到底什么是JNI 什么是NDK 2 何为 交叉编译 先看什么是JNI JNI的全称就是Java Native Interface 即java本地开发接口 可能大家和