jni接口,jni接口 root环境

http://www.itjxue.com  2023-01-13 14:54  来源:未知  点击次数: 

浅谈如何用JNI的代码调用java接口

对于本地函数

JNIEXPORT void JNICALL Java_video1_TestNative_sayHello(JNIEnv * env, jobject obj)

{

cout"Hello Native Test !"endl;

}

JNIEnv类型代表Java环境。通过这个JNIEnv*指针,就可以对Java端的代码进行操作。如,创建Java类得对象,调用Java对象的方法,获取Java对象的属性等。

JNIEnv的指针会被JNI传送到本地方法的实现函数中来对Java端的代码进行操作

JNIEnv类中的函数:

NewObject/NewString/NewTYPEArray :new新对象

Get/SetTYPEField:获取属性

Get/SetStaticTYPEField :获取静态属性

CallTYPEMethod/CallStaticTYPEMethod

jni调用 java和c是同个线程吗

是的,jni调用时, java和c是同个线程。

检测方法:在java和c中分别把当前线程的id输出出来查看。

Java获取线程Id:

Thread.currentThread().getId();

C中获取线程Id:

GetCurrentThreadId();

如何在Android下使用JNI

方法步骤:

第一步:

使用Java编写HelloWorld 的Android应用程序:

代码如下

package com.lucyfyr;

import android.app.Activity;

import android.os.Bundle;

import android.util.Log;

public class HelloWorld extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

Log.v("dufresne", printJNI("I am HelloWorld Activity"));

}

static

{

//加载库文件

System.loadLibrary("HelloWorldJni");

}

//声明原生函数 参数为String类型 返回类型为String

private native String printJNI(String inputStr);

}

这一步可以使用eclipse来生成一个App;

因为eclipse会自动编译此Java文件,后面要是用到。

第二步:

生成共享库的头文件:

进入到eclipse生成的Android Project中 :/HelloWorld/bin/classes/com/lucyfyr/ 下:

可以看到里面后很多后缀为.class的文件,就是eclipse为自动编译好了的java文件,其中就有:

HelloWorld.class文件。

退回到classes一级目录:/HelloWorld/bin/classes/

执行如下命令:

javah com.lucyfyr.HelloWorld

生成文件:com_lucyfyr_HelloWorld.h

/* DO NOT EDIT THIS FILE - it is machine generated */

#include jni.h

/* Header for class com_lucyfyr_HelloWorld */

#ifndef _Included_com_lucyfyr_HelloWorld

#define _Included_com_lucyfyr_HelloWorld

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class: com_lucyfyr_HelloWorld

* Method: printJNI

* Signature: (Ljava/lang/String;)Ljava/lang/String;

*/

JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI

(JNIEnv *, jobject, jstring);

#ifdef __cplusplus

}

#endif

#endif

可以看到自动生成对应的函数:Java_com_lucyfyr_HelloWorld_printJNI

Java_ + 包名(com.lucyfyr) + 类名(HelloWorld) + 接口名(printJNI):必须要按此JNI规范来操作;

java虚拟机就可以在com.simon.HelloWorld类调用printJNI接口的时候自动找到这个C实现的Native函数调用。

当然函数名太长,可以在.c文件中通过函数名映射表来实现简化。

第三步:

实现JNI原生函数源文件:

新建com_lucyfyr_HelloWorld.c文件:

#include jni.h

#define LOG_TAG "HelloWorld"

#include utils/Log.h

/* Native interface, it will be call in java code */

JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI(JNIEnv *env, jobject obj,jstring inputStr)

{

LOGI("dufresne Hello World From libhelloworld.so!");

// 从 instring 字符串取得指向字符串 UTF 编码的指针

const char *str =

(const char *)(*env)-GetStringUTFChars( env,inputStr, JNI_FALSE );

LOGI("dufresne---%s",(const char *)str);

// 通知虚拟机本地代码不再需要通过 str 访问 Java 字符串。

(*env)-ReleaseStringUTFChars(env, inputStr, (const char *)str );

return (*env)-NewStringUTF(env, "Hello World! I am Native interface");

}

/* This function will be call when the library first be load.

* You can do some init in the libray. return which version jni it support.

*/

jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

void *venv;

LOGI("dufresne-----JNI_OnLoad!");

if ((*vm)-GetEnv(vm, (void**)venv, JNI_VERSION_1_4) != JNI_OK) {

LOGE("dufresne---ERROR: GetEnv failed");

return -1;

}

return JNI_VERSION_1_4;

}

OnLoadJava_com_lucyfyr_HelloWorld_printJNI

函数里面做一些log输出 注意JNI中的log输出的不同。

JNI_OnLoad函数JNI规范定义的,当共享库第一次被加载的时候会被回调,

这个函数里面可以进行一些初始化工作,比如注册函数映射表,缓存一些变量等,

最后返回当前环境所支持的JNI环境。本例只是简单的返回当前JNI环境。

第四步:

编译生成so库

编译com_lucyfyr_HelloWorld.c成so库可以和app一起编译,也可以都单独编译。

在当前目录下建立jni文件夹:HelloWorld/jni/

下建立Android.mk ,并将com_lucyfyr_HelloWorld.c和 com_lucyfyr_HelloWorld.h 拷贝到进去

编写编译生成so库的Android.mk文件:

LOCAL_PATH:= $(call my-dir)

# 一个完整模块编译

include $(CLEAR_VARS)

LOCAL_SRC_FILES:=com_lucyfyr_HelloWorld.c

LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)

LOCAL_MODULE := libHelloWorldJni

LOCAL_SHARED_LIBRARIES := libutils

LOCAL_PRELINK_MODULE := false

LOCAL_MODULE_TAGS :=optional

include $(BUILD_SHARED_LIBRARY)

系统变量解析:

LOCAL_PATH - 编译时的目录

$(call 目录,目录….) 目录引入操作符

如该目录下有个文件夹名称 src,则可以这样写 $(call src),那么就会得到 src 目录的完整路径

include $(CLEAR_VARS) -清除之前的一些系统变量

LOCAL_MODULE - 编译生成的目标对象

LOCAL_SRC_FILES - 编译的源文件

LOCAL_C_INCLUDES - 需要包含的头文件目录

LOCAL_SHARED_LIBRARIES - 链接时需要的外部库

LOCAL_PRELINK_MODULE - 是否需要prelink处理

include$(BUILD_SHARED_LIBRARY) - 指明要编译成动态库

JNI和NDK的区别

字面理解:JNI表示Java Native Inteface,是Java中定义的一种用于连接Java和C/C++接口的一种实现方式。NDK表示Native Development Kit,是Google在Android开发中提供的一套用于快速创建native工程的一个工具。使用这个工具可以很方便的编写,调试JNI的代码。

如何得到JavaVM,JNIEnv接口

JavaVM接口

第一种方式,在加载动态链接库的时候,JVM会调用JNI_OnLoad(JavaVM* jvm, void* reserved)(如果定义了该函数)。第一个参数会传入JavaVM指针。

第二种方式,在native code中调用JNI_CreateJavaVM(jvm, (void**)env, vm_args)可以得到JavaVM指针。

两种情况下,都可以用全局变量,比如JavaVM* g_jvm来保存获得的指针以便在任意上下文中使用。

Android系统是利用第二种方式Invocation interface来创建JVM的。

JNIEnv接口

JNI开发最常见的错误就是滥用了JNIEnv接口。需要强调的是JNIEnv是跟线程相关的。

在native method中,JNIEnv作为第一个参数传入。那么在JNIEnv不作为参数传入的时候,该如何获得它?JNI提供了两个函数:(*jvm)-AttachCurrentThread(jvm, (void**)env, NULL)和(*jvm)-GetEnv(jvm, (void**)env, JNI_VERSION_1_2)。两个函数都利用JavaVM接口获得JNIEnv接口,上面已经讲到如何获得JavaVM接口。

JNI规范也说明,可以将获得JNIEnv封装成一个函数。

1

2

3

4

5

6

JNIEnv* JNU_GetEnv()

{

JNIEnv* env;

(*g_jvm)-GetEnv(g_jvm, (void**)env, JNI_VERSION_1_2);

return env;

}

? android中,请简述jni的调用过程

1)安装和下载Cygwin,下载 Android NDK

2)在ndk项目中JNI接口的设计

3)使用C/C++实现本地方法

4)JNI生成动态链接库.so文件

5)将动态链接库复制到java工程,在java工程中调用,运行java工程即可

(责任编辑:IT教学网)

更多

相关服务器空间文章

推荐服务器空间文章