Android:JNI 与 NDK到底是什么?(含实例教学)
前言
在
android
开发中,使用NDK
开发的需求正逐渐增大;很多人搞不懂
JNI
与NDK
到底是怎么回事?今天我们先介绍
JNI
与NDK
之间的区别,手把手进行NDK
的使用教学,希望你们会喜欢;
目录:
1. JNI介绍
1.1 简介
定义:
Java Native Interface
,即Java
接口作用:使得
Java
与 本地其他类型语言(如C、C++
)交互
特别注意:
JNI
是Java
调用Native
语言的一种特性JNI
是属于Java
的,与Android
无直接关系
1.2 为什么要有JNI
1.3 实现步骤
如
Java
需要与C++
交互,那么就用C++
实现Java
的Native
方法
2. NDK介绍
2.1 简介
定义:
Native Development Kit
,是Android
的一个工具开发包
NDK是属于
Android
的,与Java
并无直接关系
特点
额外注意
2.2 使用步骤
配置
Android NDK
环境创建
Android
项目,并与NDK
进行关联
比如
Android
需要与C++
交互,那么就用C++
实现Java
的Native
方法
3. NDK与JNI关系
4. 具体使用
本文根据版本的不同介绍了两种在Android Studio
中实现 NDK
的方法:Android Studio2.2
以下 & 2.2以上
4.1 Android Studio2.2 以下实现NDK
步骤如下
配置
Android NDK
环境关联
Andorid Studio
项目 与NDK
步骤详解
步骤1:配置 Android NDK环境
具体请看文章 : 手把手教你配置Android NDK环境
步骤2: 关联Andorid Studio项目 与 NDK
当你的项目每次需要使用
NDK
时,都需要将该项目关联到NDK
此处使用的是
Andorid Studio
,与Eclipse
不同还在使用
Eclipse
的同学请自行查找资料配置
具体配置如下
a. 在Gradle的 local.properties中添加配置
ndk.dir=/Users/Carson_Ho/Library/Android/sdk/ndk-bundle
若
ndk
目录存放在SDK
的目录中,并命名为ndk-bundle
,则该配置自动添加
b. 在Gradle
的 gradle.properties
中添加配置
android.useDeprecatedndk=true // 对旧版本的NDK支持
c. 在Gradle
的build.gradle
添加ndk
节点
至此,将
Andorid Studio
的项目 与NDK
关联完毕下面,将真正开始讲解如何在项目中使用NDK
此处采用
C++
作为展示
test.cpp:
# include <jni.h> # include <stdio.h> extern C { JNIEXPORT jstring JNICALL Java_scut_carson_1ho_ndk_1demo_MainActivity_getFromJNI(jnienv *env,jobject obj ){ // 参数说明 // 1. jnienv:代表了VM里面的环境,本地的代码可以通过该参数与Java代码进行操作 // 2. obj:定义JNI方法的类的一个本地引用(this) return env -> NewStringUTF(Hello i am from JNI!); // 上述代码是返回一个String类型的Hello i am from JNI!字符串 } }
此处需要注意:
JNIEXPORT jstring JNICALL
中的JNIEXPORT
和JNICALL
不能省关于方法名
Java_scut_carson_1ho_ndk_1demo_MainActivity_getFromJNI
如我的包名是:
scut.carson_ho.ndk_demo
,则需要改成scut_carson_1ho_ndk_1demo
最后,将创建好的test.cpp
文件放入到工程文件目录中的src/main/jni
文件夹
若无jni
文件夹,则手动创建。
下面我讲解一下JNI类型与java类型对应的关系介绍
步骤4:创建Android.mk文件
作用:指定源码编译的配置信息
具体使用
Android.mk
LOCAL_PATH := $(call my-dir) // 设置工作目录,而my-dir则会返回Android.mk文件所在的目录 include $(CLEAR_VARS) // 清除几乎所有以LOCAL——PATH开头的变量(不包括LOCAL_PATH) LOCAL_MODULE := hello_jni // 设置模块的名称,即编译出来.so文件名 // 注,要和上述步骤中build.gradle中NDK节点设置的名字相同 LOCAL_SRC_FILES := test.cpp // 指定参与模块编译的C/C++源文件名 include $(BUILD_SHARED_LIBRARY) // 指定生成的静态库或者共享库在运行时依赖的共享库模块列表。
步骤5:创建Application.mk文件
作用:配置编译平台相关内容
具体使用
Application.mk
APP_ABI := armeabi // 最常用的APP_ABI字段:指定需要基于哪些cpu平台的.so文件 // 常见的平台有armeabi x86 mips,其中移动设备主要是armeabi平台 // 默认情况下,Android平台会生成所有平台的.so文件,即同APP_ABI := armeabi x86 mips // 指定cpu平台类型后,就只会生成该平台的.so文件,即上述语句只会生成armeabi平台的.so文件
// 步骤1:进入该文件夹 cd /Users/Carson_Ho/AndroidStudioProjects/NDK_Demo/app/src/main/jni // 步骤2:运行NDK编译命令 ndk-build
步骤7:在src/main/
中创建一个名为jniLibs
的文件夹,并将上述生成的so文件夹放到该目录下
步骤8:在Andoird Studio项目中使用NDK实现JNI功能
public class MainActivity extends AppCompatActivity { // 步骤1:加载生成的so库文件 // 注意要跟.so库文件名相同 static { System.loadLibrary(hello_jni); } // 步骤2:定义在JNI中实现的方法 public native String getFromJNI(); // 此处设置了一个按钮用于触发JNI方法 private Button Button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 通过Button调用JNI中的方法 Button = (Button) findViewById(R.id.button); Button.setonClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Button.setText(getFromJNI()); } }); }
主布局文件:activity_main.xml
<RelativeLayout xmlns:android=http://schemas.android.com/apk/res/android xmlns:tools=http://schemas.android.com/tools android:layout_width=match_parent android:layout_height=match_parent android:paddingBottom=@dimen/activity_vertical_margin android:paddingLeft=@dimen/activity_horizontal_margin android:paddingRight=@dimen/activity_horizontal_margin android:paddingTop=@dimen/activity_vertical_margin tools:context=scut.carson_ho.ndk_demo.MainActivity> // 此处设置了一个按钮用于触发JNI方法 <Button android:id=@+id/button android:layout_centerInParent=true android:layout_width=300dp android:layout_height=50dp android:text=调用JNI代码 /> </RelativeLayout>
结果展示