前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >NDK开发 从入门到放弃(一:基本流程入门了解)

NDK开发 从入门到放弃(一:基本流程入门了解)

原创
作者头像
te大大
修改于 2021-11-18 07:00:50
修改于 2021-11-18 07:00:50
85700
代码可运行
举报
文章被收录于专栏:技术分享记技术分享记
运行总次数:0
代码可运行

一、前言

● NDK Native Development Kit(NDK)是一系列工具的集合。它提供了一系列的工具,帮助开发者快速开发C/C++的动态库,并能自动将so和java一起打包成apk。

● JNI Java Native Interface(JNI)标准是java平台的一部分,JNI是Java语言提供的Java和C/C++相互沟通的机制,Java可以通过JNI调用C/C++代码,C/C++的代码也可以调用java代码。

● JNI与NDK的关系 NDK可以为我们生成了C/C++的动态链接库,JNI是java和C/C++沟通的接口,两者与android没有半毛钱关系,只因为安卓是java程序语言开发,然后通过JNI又能与C/C++沟通,所以我们可以使用NDK+JNI来实现“Java+C”的开发方式。

● 为什么要NDK开发

NDK开发具有以下优点:

  1. 项目需要调用底层的一些C/C++的一些东西(java无法直接访问到操作系统底层(如系统硬件等)),或者已经在C/C++环境下实现了功能代码(大部分现存的开源库都是用C/C++代码编写的。),直接使用即可。NDK开发常用于驱动开发、无线热点共享、数学运算、实时渲染的游戏、音视频处理、文件压缩、人脸识别图片处理等。
  2. 为了效率更加高效些。将要求高性能的应用逻辑使用C/C++开发,从而提高应用程序的执行效率。但是C/C++代码虽然是高效的,在java与C/C++相互调用时却增大了开销;
  3. 基于安全性的考虑。防止代码被反编译,为了安全起见,使用C/C++语言来编写重要的部分以增大系统的安全性,最后生成so库(用过第三方库的应该都不陌生)便于给人提供方便。(任何有效的代码混淆对于会smail语法反编译你apk是分分钟的事,即使你加壳也不能幸免高手的攻击)
  4. 便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。

二、安装与配置

首先我们在Android Studio下新建一个安卓项目。然后打开Project Structure界面,如下:

SDK Location目录下,有SDK和NDK的路径,而这里我们暂时还未下载配置过NDK,故我们需要点击Download Android NDK来进行下载(Android Studio还是很强大的,相比Eclipse能省不少事)。这里Android Studio会下载最新版本的NDK进行安装,默认会下载保存在SDK的路径下。我们在上图中还能看到有一段介绍文字,说SDK以及NDK的路径配置会保存在local.properties文件内,安装完成后我们刷新Project,进local.properties文件查看也能看到SDK与NDK的路径。

NDK下载配置完成之后,需要在gradle.properties文件中加上一行:

android.useDeprecatedNdk=true 1 接下来,我们借助强大的Android Studio的插件功能,在External Tools下配置两个非常有用的插件。进入Settings–>Tools–>ExternalTools,点击+号增加。

javah -jni命令,是根据java文件生成.h头文件的,会自动根据java文件中的类名(包含包名)与方法名生成对应的C/C++里面的方法名。下面是参数配置及其含义:

三、简单实例

接下来我们创建一个访问本地C/C++方法的java类。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class JniTest {
    /**
     * 将用C++代码实现,在android代码中调用的方法:获取当前app的包名
     * @param o
     * @return
     */
    public static native String getPackname(Object o);

    /**
     * 加载so库或jni库,在使用到该库之前加载就行,不一定非要写在这个类内
     * 系统自己会判断扩展名是dll还是so,这里加载libJNI_ANDROID_TEST.so
     */
    static {
        System.loadLibrary("JNI_ANDROID_TEST");
    }
}

注意JNI_ANDROID_TEST这个Library名字,之后还会需要用到,要保持一致。该类提供了一个static的native方法,该方法将用来获取app的包名。然后对该文件执行javah -jni操作,生成对应的.h头文件。

如图,已经根据我们的java类生成了对应的.h文件,文件名为包名类名.h,我们可以手动改名为jnitest.h,里面只有一个方法,返回值为String(jstring),方法名为Java类的包名类名方法名(包名中的分级不是用.而是_),前面两个参数是C++里面必须有的(JNIEnv代表指向JVM的指针,jclass是调用该方法的java对象),第三个就是我们java类的方法里面的参数Object。注意,这是java函数与C++函数对应的静态注册方法,即通过特定的规则来写,此处方法名可以随意起名字,然后还可以用动态注册的方式关联两个方法(显然,静态注册要简单一些)。 然后我们新建一个C++文件,取名为jnitest.cpp,写上需要include的文件,从.h文件中复制方法过来(方法名、参数类型、返回值等必须一致!血与泪的教训)。

至此,.h文件和c++文件均已完成,接下来还需要在这个jni目录下增加两个文件,Android.mk和Application.mk。 Android.mk,注意LOCAL_MODULE的值与之前的名字相对应,LOCAL_SRC_FILES的值写c++文件的名字,这两个值成对设置,可设置多组。(:=是赋值的意思,$是引用某变量的值。)

里面的符号正确的应该是:=,代码中已更正,图片里面的更换麻烦就没改了。很奇怪,我当初写的时候编译运行好像是没出错是正常的…(Tips.20170519)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
LOCAL_PATH := $(call my-dir)     // 设置当前的编译目录(Android.mk所在的目录) 

include $(CLEAR_VARS)            // 清除LOCAL_XX变量(LOCAL_PATH除外)
LOCAL_MODULE := JNI_ANDROID_TEST  // 指定当前编译模块的名称  
LOCAL_SRC_FILES := jnitest.cpp    // 编译模块需要的源文件
include $(BUILD_SHARED_LIBRARY) // 指定编译出的库类型,BUILD_SHARED_LIBRARY:动态库;BUILD_STATIC_LIBRARY:静态库, BUILD_EXECUTEABLE指:可执行文件

在一个Android.mk文件中配置多个Module的方式如下(include$(CLEAR_VARS)、include $(BUILD_SHARED_LIBRARY)两个语句也需要加上):

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := JNI_STATIC_ANDROID_TEST
LOCAL_SRC_FILES := jnistaticutils.cpp
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := JNI_DYNAMIC_ANDROID_TEST
LOCAL_SRC_FILES := jnidynamicutils.cpp
include $(BUILD_SHARED_LIBRARY)

Application.mk,APP_ABI有四种类型(默认armeabi),armeabi、armeabi-v7a、x86、mips,设置时以空格隔开,all表示所有。该文件中有个可选配置的APP_MODULES,类似于上面Android.mk文件中的LOCAL_MODULE,以空格隔开,且会覆盖掉Android.mk文件中的LOCAL_MODULE设置(比如Android.mk文件中的写了两个jni库的配置,LOCAL_MODULE := JNI1、LOCAL_MODULE := JNI2,而Application.mk中设置的APP_MODULES := JNI1,则只能生成JNI1的so文件,要生成JNI2的so文件的时候会报错,除非写成APP_MODULES := JNI1 JNI2,这里我们直接省略默认使用Android.mk中的)。

APP_ABI := all 1 接下来我们需要对C++文件执行ndk-build操作,生成相应的so文件。

如图,在main/libs目录下生成了多个so文件,名字为lib+我们指定的库名(同时还生成了obj文件夹,不知是什么东西)。 这时候我们可以在main目录下新建jniLibs文件夹,把生成的libs文件夹内的东西均复制过去,删除新生成的jni、libs、obj三个文件夹。然后在Activity中测试调用,在TextView上显示我们通过C++代码实现的方法getPackname获取app的包名了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = (TextView) findViewById(R.id.tv_app_package_name);
        tv.setText("packageName: " + JniTest.getPackname(MainActivity.this));
    }
}

测试能正确得到包名,说明调用成功了。我们可以把JniTest类以及so文件给别人去使用,这样别人是看不到我们的代码实现的,能很好的保护我们的源码。 B站学习链接:https://www.bilibili.com/video/BV11S4y1d7Dg/

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android Studio 4.0.+NDK .so库生成打包
以Android studio 4.0.2来分析讲解,gradle=6.1.1,如图文和网上其他资料不一致,可能是别的资料版本较低而已
全栈程序员站长
2022/06/25
1.7K0
Android Studio 4.0.+NDK .so库生成打包
★ Android基础篇 初步NDK开发 .SO文件生成与JIN调用
就是生产个so文件,并且可以调用C里面的方法。但为什么要写一篇满论坛多的是的文章呢,就是因为我踩了N多个坑,希望可以帮助大家,让大家少走弯路。 要加上这句代码:android.useDeprecatedNdk=true 很重要!很重要!
全栈程序员站长
2021/04/07
1.1K0
Android NDK Makefile相关与示例
Android Studio 3之前,需要编写Android.mk和Application.mk文件。
AnRFDev
2021/02/01
8430
AndroidStudio创建JNI 工程与调用
MakeProject或者 RebuildProject之后,到 app下的 build⽂件夹找到 class所在⽬ 录; 进⼊到包名的上级⽬录,运⾏:javah -jni com.example.jnitest.JNITools ⽣成⼀个 com_example_jnitest_JNITools.h⽂件,com.example.jnitest.JNITools是 你 JNI⼯具类所在引⽤,可根据实际情况修改。
毛大姑娘
2020/09/15
1.2K0
AndroidStudio创建JNI 工程与调用
Android中JNI与NDK
JNI的定义:Java Native Interface 也就是Java本地的接口。它的作用就是使Java与本地的其他语言(C C++)交互。
全栈程序员站长
2021/04/07
8350
深入理解使用ndk-build编译NDK程序
上一篇文章我给大家介绍了如何在Linux下进行Android程序的交叉编译(Linux/Mac 交叉编译 Android 程序)。 这种方式比较原始,技术门槛稍高,对之前没有做过嵌入式开发的同学来说难度还是蛮大的。
音视频_李超
2020/04/01
3.3K0
深入理解使用ndk-build编译NDK程序
android 之ndk开发
1、Android NDK简介 NDK全称为native development kit本地语言(C&C++)开发包。而对应的是经常接触的Android-SDK,(software development kit)软件开发包(只支持java语言开发)。 简单来说利用NDK,可以开发纯C&C++的代码,然后编译成库,让利用Android-SDK开发的Java程序调用。NDK开发的可以称之为底层开发或者jni(java  native interface)层开发,SDK开发可以称为上层开发。 2、为何要用NDK
xiangzhihong
2018/01/29
8730
android studio JNI使用
Step: 1. 添加native接口注意写好native接口和System.loadLibrary()即可了,并无特别之处。 Step: 2.执行Build->Make Project 生成了.class文件..class文件的生成路径是在 app_path/build/intermediates/classes/debug下的. 这个在android studio里面看不到, 到文件管理器里面翻到的, 里面还有好多东西。 Step: 3.javah生成c头文件 点击"View->To
xiangzhihong
2018/02/01
7850
Android:JNI 与 NDK到底是什么?(含实例教学)
本文根据版本的不同介绍了两种在Android Studio中实现 NDK的方法:Android Studio2.2 以下 & 2.2以上
Carson.Ho
2019/02/22
3.4K0
Android 增加JNI
本文根据版本的不同介绍了两种在Android Studio中实现 NDK的方法:Android Studio2.2 以下 & 2.2以上
233333
2022/05/10
1.5K0
Android 增加JNI
Android Studio开发so库实践
前言 因为工作需要可能要用到JNI开发,本篇文章就分享一下我在这方面的实践,以前我们使用Eclipse做NDK开发,非常麻烦,需要配cygwin的编译环境,后面NDK功能完善才逐渐简单点,如果想了解Eclipse如何配置NDK编译环境可以参考我以前发表的旧文: Cocos2d-x 2.2.3 使用NDK配置编译环境 JNI_Android项目中调用.so动态库 Eclipse的如何通过NDK生成so库就不多说了,目前已经不适用于Android开发,建议使用AS进行开发,本篇也是基于AS来进行讲解。 什么是J
巫山老妖
2018/07/20
1.5K0
NDK 的开发流程
1、NDK开发所需要的工具 windows   需要在windows下的环境 把c代码打包成 手机能用的函数库   首先模拟手机的环境 1 NDK   .sh linux 批处理文件   .bat windows   头文件 stdio.h 编译器 interface   库函数 连接器 class 实现类   由于ndk有很多linux的批处理文件   最早基于linux开发 2 工具
mukekeheart
2018/02/27
7100
Android Ndk and Opencv Development 2
本节主要介绍的内容是Android NDK开发的核心内容和开发总结(包括很多常见问题的解决方案)。
宅男潇涧
2018/08/01
8190
Android.mk各种文件编译汇总
升级到Android 4.0。 原来我们在3.2 版本号以下编译的程序有些不能编译通过。
全栈程序员站长
2022/02/03
2.1K0
Mac下Android Studio 3.x的NDK开发环境搭建
目录 前言 CMake 用CMake向已有AS项目添加C/C++代码 ndk-build 最后 ---- 前言 mac上安装软件真的很简单, 一路下一步就可以安装好android studio. 这里有一篇旧文-Mac下安装配置Android Studio 2.x和3.x并配置使用adb可供参考. 而写这篇的目的, 主要是我发现之前的ndk开发方式已经过时了, 需要更新一下新的流程. ---- CMake CMake的方式是官方默认的ndk构建方式, 先从默认栗子开始看吧. 新建一个项
sean_yang
2019/03/05
1.2K0
Android.mk语法解析
Android.mk是Android提供的一种makefile文件,用来指定诸如编译生成so库名、引用的头文件目录、需要编译的.c/.cpp文件和.a静态库文件等。
李小白是一只喵
2020/04/23
1.8K0
Android.mk语法解析
Android NDk环境配置
概论 NDK全称是Native Development Kit,NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。NDK集成了交叉编译器(交叉编译器需要UNIX或LINUX系统环境),并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。 JNI的全称是Java Native Interface,它提供了若干的API实现了Java和其他语言的通信
xiangzhihong
2018/02/05
9680
Android NDk环境配置
Android NDK Hello
Android应用程序访问android的根文件系统中的文件时,由于应用程序的权限限制,无法访问这些文件,怎么办?
阳光岛主
2019/02/19
9330
Android NDK Hello
Android NDK层编译OpenCV代码开发详解
Android NDK层编译OpenCV代码开发详解 使用Android NDK开发编译OpenCV C++代码,这个在OpenCV4Android开发中会经常遇到的要求,因为OpenCV4Android SDK多数Java代码都是基于JNI调用,如果对于实时性与应用要求比较高的场合来说,多次频繁调用JNI层本身就会导致很大的资源开销,这个时候就需要将全部的处理封装在C++层,在C++中调用OpenCV相关API函数,同时通过在JNI层面定义本地方法,力争做到每次处理图像,只调用JNI一次,这样就会达到比较
OpenCV学堂
2018/04/04
3.3K0
Android NDK层编译OpenCV代码开发详解
NDK开发_编译的cpp引用到 其它so, Android.mk 的写法
如果我们编译的so文件需要引用到其它的so文件,那我们来看下这时候的Android.mk 文件如何写。
小驰行动派
2021/04/30
1.2K0
相关推荐
Android Studio 4.0.+NDK .so库生成打包
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文