×

jni

android 怎么调用jni里面的方法?android 怎么封装jni

admin admin 发表于2023-09-06 10:58:37 浏览31 评论0

抢沙发发表评论

本文目录

android 怎么调用jni里面的方法

调用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. */@Overridepublic 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 __cplusplusextern "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文件:

android 怎么封装jni

一、底层实现:c文件:hardware/libhardware_legacy/power/power.c以其中set_screen_state(int)函数为例其Android.mk中添加: LOCAL_MODULE:= libpower 编译成lib LOCAL_SRC_FILES += power.chardware/libhardware_legacy/power/power.c 1: int 2: set_screen_state(int on) 3: { 4: QEMU_FALLBACK(set_screen_state(on)); 5: 6: LOGI("*** set_screen_state %d", on); 7: 8: initialize_fds(); 9: 10: //LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime, 11: // systemTime(), strerror(g_error)); 12: 13: if (g_error) 14: goto failure; 15: 16: char buf; 17: int len; 18: if(on) 19: len = snprintf(buf, sizeof(buf), "%s", on_state); 20: else 21: len = snprintf(buf, sizeof(buf), "%s", off_state); 22: 23: buf = ’\0’; 24: len = write(g_fds, buf, len); 25: if(len 《 0) { 26: failure: 27: LOGE("Failed setting last user activity: g_error=%d\n", g_error); 28: } 29: return 0; 30: }其头文件power.h中: 1: #if__cplusplus 2: extern "C" { //注1 3: #endif 4: enum { 5: PARTIAL_WAKE_LOCK = 1, // the cpu stays on, but the screen is off 6: FULL_WAKE_LOCK = 2 // the screen is also on 7: }; 8: 9: // while you have a lock held, the device will stay on at least at the 10: // level you request. 11: int acquire_wake_lock(int lock, const char* id); 12: int release_wake_lock(const char* id); 13: 14: // true if you want the screen on, false if you want it off 15: int set_screen_state(int on); 16: 17: // set how long to stay awake after the last user activity in seconds 18: int set_last_user_activity_timeout(int64_t delay); 19: 20: 21: #if __cplusplus 22: } // extern "C" 23: #endif 注1:注1:extern表示其他的类已经定义了这段代码里面的内容,这里只是做声明。"C”表示的一种编译和连接规约,这里为下一步c++调用其做准备.比如void foo(int,int);该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字用来支持函数重载和类型安全连接。由于编译后的名字不同,C++程序不能直接调用C函数。因此C++提供了一个C连接交换指定符号extern“C”来解决这个问题而不是一种语言。C表示这段代码可以是符合C语言的编译和连接规约的任何语言,如Fortran、assembler等。二、cpp构成jni桥梁一个CPP文件调用之,则需添加其头文件,比如frameworks/base/core/jni/android_os_Power.cpp. 1: #include "JNIHelp.h" 2: #include "jni.h" 3: #include "android_runtime/AndroidRuntime.h" 4: #include 《hardware_legacy/power.h》 5: namespace android{ 6: .... 7: 8: //定义函数: 9: static int setScreenState(JNIEnv *env, jobject clazz, jboolean on) 10: { 11: return set_screen_state(on);//以此实现cpp到c的调用 12: } 13: 14: static JNINativeMethod method_table = {//此处实现java对cpp的调用转化 注2 15: { "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock }, 16: { "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock }, 17: { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout }, 18: { "setScreenState", "(Z)I", (void*)setScreenState }, 19: { "shutdown", "()V", (void*)android_os_Power_shutdown }, 20: { "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot }, 21: }; 22: int register_android_os_Power(JNIEnv *env) //此处注册jni 23: { //向VM(即AndroidRuntime)登记 gMethods表格所含的本地函数 24: return AndroidRuntime::registerNativeMethods( 25: env, "android/os/Power", 26: method_table, NELEM(method_table)); 27: } 28: }; 注2:typedef struct { const char* name; //Java中函数的名字 const char* signature; //用字符串是描述了函数的参数和返回值 void* fnPtr; //函数指针,指向C函数} JNINativeMethod; 其中比较难以理解的是第二个参数,例如 "()V" "(II)V" "(Ljava/lang/String;Ljava/lang/String;)V" 实际上这些字符是与函数的参数类型一一对应的。 "()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func(); "(II)V" 表示 void Func(int, int); 具体的每一个字符的对应关系如下 字符 Java类型 C类型 V void void Z jboolean boolean I jint int J jlong long D jdouble double F jfloat float B jbyte byte C jchar char S jshort short 数组则以"["开始,用两个字符表示 上面的都是基本类型。如果Java函数的参数是class,则以"L"开头,以";"结尾中间是用"/" 隔开的包及类名。而其对应的C函数名的参数则为jobject. 一个例外是String类,其对应的类为jstring Ljava/lang/String; String jstring Ljava/net/Socket; Socket jobject 如果JAVA函数位于一个嵌入类,则用$作为类名间的分隔符。 例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"三、java的封装实现frameworks/base/core/java/android/os/Power.java //此处路径跟cpp中注册jni处的路径是一致的.待细研究是否有关系 1: package android.os; 2: public class Power 3: { 4: ... 5: public static native int setScreenState(boolean on); //被native修饰的表示调用了非java语言的本地方法 6: ... 7: }四、java中对其调用frameworks/base/services/java/com/android/server/PowerManagerService.javaimport android.os.Power;public class PowerManagerService extends IPowerManager.Stub implements LocalPowerManager, Watchdog.Monitor { ... int err = Power.setScreenState(on); ...}

请问jni技术到底是什么能不能简单的阐述一下

jNi就是java调用本地方法的技术,最简单的来说,java运行一个程序需要要和不同的系统平台打交道,在windows里就是和windows平台底层打交道,mac就是要和mac打交道,jvm就是通过大量的jni技术使得java能够在不同平台上运行。而使用了这技术的一个标志就是native,如果一个类里的一个方法被native修饰,那就说明这个方法是jni来实现的,他是通过本地系统api里的方法来实现的。当然这个本地方法可能是c或者C++,当然也可能是别的语言。jni是java跨平台的基础,jvm通过在不同系统上调用不同的本地方法使得jvm可以在不同平台间移植。当前你自己也可以用jni来写一些程序,这种基本上是你以前使用了其他语言完成了一些功能,但是你有要用java来重复这些功能的时候,就可以使用jni来完成了。不过带来的问题就是,如果你的那个本地方法是依托于本地操作系统的话,那就意味着你的java程序也只能在这一个系统上运行了。所以jni就使得java很容易限定在了一个系统平台上,而jdk的作用在于他提供一个规范,这个规范就是包含了很多native方法,这些方法都是要本地操作系统来实现的,而实现了这些本地方法的操作系统就可以移植java平台了。