序言: 做NDK开发也有一段时间了,还记得初学的时候各种找大神、搜教程,最后在诸多大神的帮助下,成功的做出了我的第一个NDK小玩意,很感谢他们,而后慢慢的越入越深(keng),今天在群里看到了很多像我之前那样各种找问题的哥们,感受颇多,遂写下此文章,给那些新入坑的哥们一些方向。
java Native Interface (JNI) 标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互(一般是C/C++、汇编语言)。
JNI是本地编程接口, 它使得Java虚拟机(VM)内部运行的Java代码能够与用其他编程语言编写的应用程序和库进行交互操作。
众所周知,由于Android 的应用层的类都市以Java写的, 这些Java类编译成dex形式的bytecode之后,必须依靠Dalvik虚拟机(vm)来执行。此外,在执行Java类的过程中,如果Java类需要与C组件进行沟通的话,那么jvm就会通过jni去调用c组件的函数,这就是jni的作用。
1.要求高精度、高敏感的需求;
2.代码的保密性;
3.图片的渲染;
4.游戏复杂算法的实现。
其实主要就是两点: 安全,效率, 最起码我认为是这样的,如果你有不同的想法,欢迎前来探(si)讨(bi),好了废话不多话了,一起来学习吧。
本文是基于 Android Studio 2.2+CMake实现的, 如果你不是的话也可以做个参考,仅限参考,出事概不负责哦。
首先去新建一个Android项目,注意填写好名称,下面的勾勾不要打。
然后填写完成之后,点击下一步,这个时候如果你是新手的话,就什么也不要选,有经验的我就不多说了。
然后再去选择一个空的,不要随意乱点,不然处理起来就会很麻烦,继续下一步。
继续下一步,这是给你的主界面起名字的,我们先叫这个。
然后你就来到了程序开发的主界面,点击新建folder→jnifolder
完成之后就会如下图所示,建议不要动,这意思是说,你的文件将产生在什么地方,我们就默认给他一个就好了。
然后点击确定你就会看到出现了一个新的文件夹(cpp):
然后选中此文件夹,右键新建;
随意起个名,我们给他起一个jni,建议你也起的跟我一样,后续还要进行一系列的操作,以防出现不必要的问题,要注意的是下面勾勾也要选上,这是生成头文件。
之后点击确定,会出现两个文件,现在我们不要去管他,去jni目录之下新建一个txt文件CMakeLists.txt
内容如下
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# 这个是jni编译生产的so库的名字
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# file are automatically included.
# 要编译的c/c++文件列表 文件路径想对于cmake文件路径
./jni.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# 依赖的系统so库
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib //要生成的名字so
# Links the target library to the log library
# included in the NDK.
${log-lib} )
完成之后,点击项目右键,选中link c++…
然后跳转到 如下界面,这个的意思主要是说,让你找到你刚才写的txt文件在哪, 然后点击确定,
然后等待系统同步完成,完成之后我们的jni算是构建完成了。
首先是java代码, 我们在main里面要写好;
private TextView Stram;
//静态代码块,会首先执行
static {
/*
加载生成的动态库,动态库加载的时候,Jni_onLoad 函数(c中的函数)会被调用
在C函数中,java虚拟机通过函数表的形式将JNI函数和java类中Native函数对应起来,(两个名字必须一致)
*/
System.loadLibrary("native-lib");//这个参数跟刚才我们写的txt文本中的native相同
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stram= (TextView) findViewById(R.id.Stram);
Stram.setText(getStramInfo());
}
// native 代表的就是本地方法
private static native String getStramInfo ();
然后是 cpp代码 :
//
// Created by chason on 2017/2/17 0017.
//
#include "jni.h"
// 尤其注意: 找到与之相关联的java代码。
#define JNI_AN_MainActivity "com/cn/chason/mndkdemo/MainActivity"
#define METHOD_NUM 1
JNINativeMethod g_nativeMethod[METHOD_NUM]={
{"getStramInfo","()Ljava/lang/String;",(void*)getStramInfo}
};
/*
* 被虚拟机自动调用, JNI_OnLoad 被虚拟机自动调用
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv *env;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK)
return JNI_ERR;
jclass jClass = env->FindClass(JNI_AN_MainActivity);
env->RegisterNatives(jClass,g_nativeMethod,METHOD_NUM);
env->DeleteLocalRef(jClass);
return JNI_VERSION_1_6;
}
void JNI_OnUnload(JavaVM* vm, void* reserved) {
JNIEnv *env;
int nJNIVersionOK = vm->GetEnv((void **)&env, JNI_VERSION_1_6) ;
jclass jClass = env->FindClass(JNI_AN_MainActivity);
env->UnregisterNatives(jClass);
env->DeleteLocalRef(jClass);
}
//具体实现
jstring getStramInfo(JNIEnv *env, jobject callObj)
{
return env->NewStringUTF("String From Jni With c++");
}
然后是 头文件 : .h
//
// Created by chason on 2017/2/17 0017.
//
#ifndef NDKDEMO_JNI_LIB_H
#define NDKDEMO_JNI_LIB_H
#include "jni.h"
//这个方法就是我们的本地方法,切记方法名要相同。
jstring getStramInfo(JNIEnv* env,jobject callObj);
#endif //NDKDEMO_JNI_LIB_H
然后去美美哒运行吧, 至此我们的基本认识算是完成了,如图;
github Demo 地址: https://github.com/ichason/NDKDemo