关于android:NDK开发-从入门到放弃一基本流程入门了解

27次阅读

共计 4722 个字符,预计需要花费 12 分钟才能阅读完成。

一、前言
● 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 开发具备以下长处:
我的项目须要调用底层的一些 C /C++ 的一些货色(java 无奈间接拜访到操作系统底层(如零碎硬件等)),或者曾经在 C /C++ 环境下实现了性能代码(大部分现存的开源库都是用 C /C++ 代码编写的。),间接应用即可。NDK 开发罕用于驱动开发、无线热点共享、数学运算、实时渲染的游戏、音视频解决、文件压缩、人脸识别、图片解决等。
为了效率更加高效些。将要求高性能的应用逻辑应用 C /C++ 开发,从而进步应用程序的执行效率。然而 C /C++ 代码尽管是高效的,在 java 与 C /C++ 互相调用时却增大了开销;
基于安全性的思考。避免代码被反编译,为了平安起见,应用 C /C++ 语言来编写重要的局部以增大零碎的安全性,最初生成 so 库(用过第三方库的应该都不生疏)便于给人提供方便。(任何无效的代码混同对于会 smail 语法反编译你 apk 是分分钟的事,即便你加壳也不能幸免高手的攻打)
便于移植。用 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++ 外面的办法名。上面是参数配置及其含意:

Program: JDKPath\bin\javah.exe 这里配置的是 JDK 目录下的 javah.exe 的门路。
Parametes: -classpath . -jni -d ModuleFileDir/src/main/jni FileClass 这里 FileClass 指的是要执行操作的类名(即咱们操作的文件),ModuleFileDir/src/main/jni 示意生成的文件保留在这个 module 目录的 src/main/jni 目录下。
Working: ModuleFileDir\src\main\java module 目录下的 src\main\java 目录(不是很了解)。
应用形式:选中 java 文件—> 右键—>External Tools—>javah-jni,将生成 jni 文件夹以及文件夹下的 包名. 类名的.h 头文件(名字过长,咱们能够本人重命名)。
ndk -build 命令,是依据 C /C++ 文件生成 so 文件的。上面是参数配置及其含意:

Program: F:\apk\sdk\ndk-bundle\ndk-build.cmd 这里配置的是 ndk 下的 ndk-build.cmd 的门路(依据理论状况填写)。
Working: ModuleFileDir\src\main
应用形式:选中 C /C++ 文件—> 右键—>ExternalTools—>ndk-build,将在 main 文件夹下生成 libs 文件夹以及多个 so 文件,咱们能够挪动至 jniLibs 目录上来。
三、简略实例
接下来咱们创立一个拜访本地 C /C++ 办法的 java 类。

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)

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 的包名了。

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/vide…
欢送大家一起交流学习,能够给博主点个关注哦,及时看到音讯。

正文完
 0