JNI本意(Java Native Interface)Java本地接口,它是为了方便Java调用C,C++等本地代码所封装的一层接口。我们知道,Java的优点就是跨平台,但是作为优点的同时,其在本地交互的时候就出现了短板。Java的跨平台特性导致其本地交互的能力不够强大,一些和操作系统相关的特性Java无法完成,于是Java提供JNI专门用于和本地代码交互,这样就增强了Java语言本地交互能力。通过JavaJNI,用户可以调用用C,C++所编写的本地代码。
NDK是Android所提供的一个工具集合,通过NDK可以在Android中更加方便地通过JNI来访问本地代码,比如C或者C++.NDK还提供了交叉编译器,开发人员只需要修改mk文件就可以生成特定CPU平台的动态库。使用NDK的好处如下:
JNI和NDK比较适合在Linux环境下开发。
1.在java中 声明native方法
package com.aspsine.mobi.chapter14;
/**
* Created by hzf 2017/4/8 0008 on 上午 10:31.
* description :
*/
public class JniTest {
static {
System.loadLibrary("jni-test");
}
public static void main(String args[]){
JniTest test = new JniTest();
System.out.println(test.getStringFromJNI());
test.setStringToJNI("hello jni");
}
public native String getStringFromJNI();
public native void setStringToJNI(String s);
}
2.编译java源文件得到class文件,然后通过javah命令到处JNI的头文件
打开cmd
下面是文件生成的头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_aspsine_mobi_chapter14_JniTest */
#ifndef _Included_com_aspsine_mobi_chapter14_JniTest
#define _Included_com_aspsine_mobi_chapter14_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_aspsine_mobi_chapter14_JniTest
* Method: getStringFromJNI
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_aspsine_mobi_chapter14_JniTest_getStringFromJNI
(JNIEnv *, jobject);
/*
* Class: com_aspsine_mobi_chapter14_JniTest
* Method: setStringToJNI
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_aspsine_mobi_chapter14_JniTest_setStringToJNI
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
上面代码函数名遵循如下规则:
其他参数
1. JNIEXPORT 和JNICALL :他们是JNI中所定义的宏,可以在jni.h这个文件中 查找到。
2. JNIEnv *表示一个指向JNI环境的指针,可以通过它来访问JNI提供的接口方法。
3. jobject:表示java对象中的this.
3.实现JNI方法
JNI方法是指java中声明的native方法,这里可以用C或者C++来实现,他们实现过程类似,只有少量区别。
首先,在工程的主目录下创建一个子目录,名字随意,然后将之前的通过javah生成是文件复制到这个目录下,接着创建test.cpp和test.c两个文件
c++实现
//
// Created by Administrator on 2017/4/8 0008.
//test.cpp c++来实现
#include "com_aspsine_mobi_chapter14_JniTest.h"
#include
JNIEXPORT jstring JNICALL Java_com_aspsine_mobi_chapter14_JniTest_getStringFromJNI
(JNIEnv *env, jobject thiz){
printf("invoke get in c++\n");
return env->NewStringUTF("HOLLE FROM JNI");
}
JNIEXPORT void JNICALL Java_com_aspsine_mobi_chapter14_JniTest_setStringToJNI
(JNIEnv *env, jobject thiz, jstring string){
printf("invoke set from C++\n");
char* str = (char*)env->GetStringUTFChars(string,NULL);
printf("%s\n", str);
env->ReleaseStringUTFChars(string, str);
}
c实现
//
// Created by Administrator on 2017/4/8 0008.
//test.c c来实现
#include "com_aspsine_mobi_chapter14_JniTest.h"
#include
JNIEXPORT jstring JNICALL Java_com_aspsine_mobi_chapter14_JniTest_getStringFromJNI
(JNIEnv *env, jobject thiz){
printf("invoke get from C\n");
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
JNIEXPORT void JNICALL Java_com_aspsine_mobi_chapter14_JniTest_setStringToJNI
(JNIEnv *env, jobject thiz, jstring string) {
printf("invoke set from C\n");
char* str = (char*)(*env)->GetStringUTFChars(env,string,NULL);
printf("%s\n", str);
(*env)->ReleaseStringUTFChars(env, string, str);
}
不同之处:
4.编译so库并在java中调用
NDK的开发是基于JNI的,主要由以下几个步骤
1.下载并配置NDK
打开AS的SDK Manager,安装NDK插件:
整个NDK比较大,解压缩完2个G,自动安装到配置的sdk目录下:
安装完毕后,点开structure,配置NDK的路径:
配置NDK的环境变量:
验证是否配置成功:
在命令行输入ndk-build,如果显示以上内容,表示成功。
2.创建Android项目,并声明所需要的native方法
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
static {
System.loadLibrary("jni-test");
}
Button get ,set;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
get = (Button) findViewById(R.id.btn_get);
set = (Button) findViewById(R.id.btn_set);
get.setOnClickListener(this);
set.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_get:
break;
case R.id.btn_set:
break;
}
}
/**
* 声明get方法
* - 作用是从本地方法返回一个String
* @return 返回一个字符串
*/
public native String getStringFromJNI();
/**
* 声明set方法
* - 作用是向本地方法传递一个String
*/
public native void setStringToJNI(String s);
}
3.实现Android项目中所声明的native方法
//
// Created by Administrator on 2017/4/8 0008.
//
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
jstring Java_com_aspsine_mobi_chapter142_MainActivity_getStringFromJNI(JNIEnv *env, jobject thiz) {
printf("invoke get in c++\n");
callJavaMethod(env, thiz);
return env->NewStringUTF("Hello from JNI in libjni-test.so !");
}
void Java_com_aspsine_mobi_chapter142_MainActivity_setStringToJNI(JNIEnv *env, jobject thiz, jstring string) {
printf("invoke set from C++\n");
char* str = (char*)env->GetStringUTFChars(string,NULL);
printf("%s\n", str);
env->ReleaseStringUTFChars(string, str);
}
#ifdef __cplusplus
}
#endif
Android.mk
# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jni-test//模块的名称
LOCAL_SRC_FILES := test.cpp//要参与编译的源文件
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := armeabi//CPU架构的类型
4.切换到jni目录的父目录,然后通过ndk_build命令编译产生的so库
为了让Android studio自动编译JNI代码,首先需要在app的build.gradle的defalutConfig区域添加NDK选项,其中moduleName指定模块的名称,这个名称指定了打包后so库的文件名。
defaultConfig {
applicationId "com.aspsine.mobi.chapter142"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk{
moduleName "jni-test"
}
}
接着需要将JNI代码放在app/src/main/jni目录下,注意存放JNI代码的目录必须为jni,如果不用想用这个可以用以下方式指定JNI的代码路径
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jni']
}
}
这样Android Studio就可以自动编译JNI代码了,但是这种情况下是默认打包所有CPU平台的so库,我们可以自己设置
productFlavors{
arm{
ndk{
abiFilters "armeabi"
}
}
x86{
ndk{
abiFilters "x86"
}
}
}
见书484
见书486
http://blog.csdn.net/kevindgk/article/details/52813258
http://blog.csdn.net/jkan2001/article/details/54316375