-
2021-02-27 11:40:30
可以通过JNI从Java调用的每个C函数都有一个JNIEnv *类型的第一个参数.在C端,这是一个指向具有多个函数指针的结构的指针.这些功能是您与Java世界的接口. FindClass,GetMethodID和其余的都在其中.
因此,当您想从C端调用FindClass时,方法如下:
void Java_com_mypackage_MyClass_MyMethod(JNIEnv *jniEnv, jobject thiz)
{
jclass *clazz = (*(*jniEnv)->FindClass)(jniEnv, "com/mypackage/SomeClass");
jmethodID MethodID = (*(*jniEnv)->GetStaticMethodID)(jniEnv, clazz, "SomeMethod", "(I)I");
int result = (*(*jniEnv)->CallStaticIntMethod)(jniEnv, clazz, MethodID, 18);
依此类推.该行取消了jniEnv参数的引用,获取了一个函数指针,并通过它调用了函数.自然,类和方法名完全是伪造的.我怎么知道你的
注意:我在这里说的是函数指针,但与您的意思不同.这些是指向JNI提供的功能的函数指针,而不是指向您的函数的函数指针.
调用语法的冗长程度与C的局限性有关.在C中,您可以改写
jclass *cl = jniEnv->FindClass("com/mypackage/SomeClass");
因为C通过虚拟函数本地支持这种函数表指针.
您可能会沿途采取一些捷径.如果要在与C入口点相同的类中调用方法,并且它恰好是静态的,则第二个参数已经是类对象指针.如果您具有要在其上调用方法的对象的this指针,则可以使用GetObjectClass.
更多相关内容 -
ndk 开发(ndk层调用java层方法)
2021-05-31 20:04:551、ndk层修改java层的对象的成员 package com.yuanxuzhen.testnative; public class UserData { public String name; public String sex; public int age; public UserData(String name, String sex, int ...1、ndk层修改java层的对象的属性
package com.yuanxuzhen.testnative; public class UserData { public String name; public String sex; public int age; public UserData(String name, String sex, int age) { this.name = name; this.sex = sex; this.age = age; } public UserData(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "UserData{" + "name='" + name + '\'' + ", sex='" + sex + '\'' + ", age=" + age + '}'; } }
public native UserData callNativeUserData(UserData data);
JNIEXPORT jobject JNICALL Java_com_yuanxuzhen_testnative_MainActivity_callNativeUserData(JNIEnv *env, jobject thiz, jobject data) { // TODO: implement callNativeUserData() jclass cls = (*env)->GetObjectClass(env, data); jfieldID jfieldId = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;"); jstring jstring1 = ((*env)->GetObjectField(env, data, jfieldId)); const char* c = (*env)->GetStringUTFChars(env,jstring1, 0); LOGE("native name = %s", c ); (*env)->ReleaseStringUTFChars(env,jstring1, c); jstring jstring2 = (*env)->NewStringUTF(env,"yuanping"); (*env)->SetObjectField(env,data, jfieldId, jstring2); return data; }
2、ndk层访问java层的静态方法
public static void testStaticJniCallJava(String name){ Log.e("xxxx", "testJniCallJava name="+name); } public native void jniCallJava(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); jniCallJava(); }
JNIEXPORT void JNICALL Java_com_yuanxuzhen_testnative_MainActivity_jniCallJava(JNIEnv *env, jobject thiz) { jclass cls = (*env)->GetObjectClass(env, thiz); jmethodID jmethodId = (*env)->GetStaticMethodID(env, cls, "testStaticJniCallJava", "(Ljava/lang/String;)V"); (*env)->CallStaticVoidMethod(cls, jmethodId, (*env)->NewStringUTF(env,"yuanjingyao")); }
thiz代表调用的对象
3、ndk层调用对象的方法
public native void callInterface(ITest test);
//extern "C" JNIEXPORT void JNICALL Java_com_yuanxuzhen_testnative_MainActivity_callInterface(JNIEnv *env, jobject thiz, jobject test) { LOGE("callInterface 1111111"); jclass cls = (*env)->GetObjectClass(env, test); jmethodID methodId = (*env)->GetMethodID(env,cls, "printUserData", "(Lcom/yuanxuzhen/testnative/UserData;)V"); jstring name = (*env)->NewStringUTF(env,getYuanxzh()); jstring sex = (*env)->NewStringUTF(env, "female"); jint age = 2; jclass userDataClass = (*env)->FindClass(env,"com/yuanxuzhen/testnative/UserData"); jmethodID useGenId = (*env)->GetMethodID(env,userDataClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;I)V"); jobject useObject = (*env)->NewObject(env,userDataClass, useGenId, name, sex, age); (*env)->CallVoidMethod(env,test, methodId, useObject); LOGE("callInterface 222222"); }
4、ndk层创建java层对象
jclass userDataClass = (*env)->FindClass(env,"com/yuanxuzhen/testnative/UserData"); jmethodID useGenId = (*env)->GetMethodID(env,userDataClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;I)V"); jobject useObject = (*env)->NewObject(env,userDataClass, useGenId, name, sex, age); (*env)->CallVoidMethod(env,test, methodId, useObject);
5 ndk 层方法调用java接口
public interface ITest { void printUserData(UserData data); }
public native void callInterface(ITest test);
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); binding.sampleText.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { callInterface(new ITest() { @Override public void printUserData(UserData data) { Log.e("xxxx", "printUserData data = " + data); } }); } }); }
Java_com_yuanxuzhen_testnative_MainActivity_callInterface(JNIEnv *env, jobject thiz, jobject test) { LOGE("callInterface 1111111"); jclass cls = (*env)->GetObjectClass(env, test); jmethodID methodId = (*env)->GetMethodID(env,cls, "printUserData", "(Lcom/yuanxuzhen/testnative/UserData;)V"); jstring name = (*env)->NewStringUTF(env,getYuanxzh()); jstring sex = (*env)->NewStringUTF(env, "female"); jint age = 2; jclass userDataClass = (*env)->FindClass(env,"com/yuanxuzhen/testnative/UserData"); jmethodID useGenId = (*env)->GetMethodID(env,userDataClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;I)V"); jobject useObject = (*env)->NewObject(env,userDataClass, useGenId, name, sex, age); (*env)->CallVoidMethod(env,test, methodId, useObject); LOGE("callInterface 222222"); }
从上面可以知道java层的接口到了ndk层就成了对象
6、ndk层调用java的构造函数
jclass userDataClass = (*env)->FindClass(env,"com/yuanxuzhen/testnative/UserData"); jmethodID useGenId = (*env)->GetMethodID(env,userDataClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;I)V"); jobject useObject = (*env)->NewObject(env,userDataClass, useGenId, name, sex, age);
-
ndk之C调用java方法以及动态注册
2022-01-30 16:53:15ndk开发需要在java层和native层相互调用代码,如何确定native方法与jni函数之间的映射关系呢?这就涉及到jni函数的注册,注册方式有两种:静态注册和动态注册。 静态注册采用基于约定的命名规则(Java_开头,后接类...一、静态注册和动态注册
ndk开发需要在java层和native层相互调用代码,如何确定native方法与jni函数之间的映射关系呢?这就涉及到jni函数的注册,注册方式有两种:静态注册和动态注册。
静态注册采用基于约定的命名规则(Java_开头,后接类的全限定名加下划线,方法名这三个组成部分组成,如下代码所示),可以通过javah或IDE自动生成native方法对应的函数声明。
优点是简单;缺点是不灵活,修改java类名或jni方法名时,需要同步修改对应的native函数命名。extern "C" JNIEXPORT jint JNICALL Java_com_shan_dynamicndk_MainActivity_jniCallAdd(JNIEnv *env, jobject thiz, jint num1, jint num2) { // TODO: implement jniCallAdd() }
动态注册通过JNINativeMethod函数和JNI_OnLoad函数的编辑可以在native代码中自由定义jni函数与native函数的映射。优点是灵活,缺点可能会由于无法使用javah和IDE自动补全功能而相对麻烦些。
二、C代码调用java代码(静态注册)
以native层调用java层方法获取uuid的方法为例
java层代码MainActivity.java如下//MainActivity.java package com.shan.ndkapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import com.shan.ndkapp.databinding.ActivityMainBinding; import java.util.UUID; public class MainActivity extends AppCompatActivity { private static final String TAG = "ndk_test_java"; // Used to load the 'ndkapp' library on application startup. static { System.loadLibrary("ndkapp"); } private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); // Example of a call to a native method TextView tv = binding.sampleText; tv.setText(getUUidFromJava()); } public String getUuid() { String uuid = UUID.randomUUID().toString(); Log.d(TAG, "getUuid:"+uuid); return uuid; } public native String getUUidFromJava(); }
native层代码native-lib.cpp如下:
//native-lib.cpp #include <jni.h> #include <string> #include <android/log.h> #define LOG_TAG "ndk_test_c" #define LOGD(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) extern "C" JNIEXPORT jstring JNICALL Java_com_shan_ndkapp_MainActivity_getUUidFromJava(JNIEnv *env, jobject thiz) { // TODO: implement getUUidFromJava() jclass j_class = env->GetObjectClass(thiz);//根据jobject获取jclass jmethodID j_methodId = env->GetMethodID(j_class,"getUuid","()Ljava/lang/String;");//最后一个参数方法签名可以通过javap -s className得到 jobject j_uuid = env->CallObjectMethod(thiz, j_methodId); const char* uuid = env->GetStringUTFChars(static_cast<jstring>(j_uuid),NULL); //jstring转化为char*才可以在C语言打印 LOGD("Java_com_shan_ndkapp_MainActivity_getUUidFromJava,uuid=%s",uuid); env->ReleaseStringUTFChars(static_cast<jstring>(j_uuid),uuid); //回收字符串 return static_cast<jstring>(j_uuid); }
上面native代码的第13行获取方法签名时,如果忘记了签名规则,可以在当前工程目录下面找到
build/intermediates/javac/debug/classes/com/shan/ndkapp/MainActivity.class,在该目录下打开命令行,通过javap -s MainActivity.class获取该类所有签名信息。三、动态注册
以java层调用native层代码获取字符串以及native层代码调用java层add函数为例,这两个函数都采用动态注册实现。
java代码MainActivity.java如下//MainActivity.java package com.shan.dynamicndk; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; import com.shan.dynamicndk.databinding.ActivityMainBinding; public class MainActivity extends AppCompatActivity { // Used to load the 'dynamicndk' library on application startup. static { System.loadLibrary("dynamicndk"); } private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); // Example of a call to a native method TextView tv = binding.sampleText; tv.setText(stringFromJNI()+":"+jniCallAdd(2,3)); } public int add(int num1,int num2) { return num1+num2; } /** * A native method that is implemented by the 'dynamicndk' native library, * which is packaged with this application. */ public native String stringFromJNI(); public native int jniCallAdd(int num1,int num2); }
native层代码如下
#include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL c_getString( JNIEnv* env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } extern "C" JNIEXPORT jint JNICALL c_callAdd( JNIEnv* env, jobject thiz,jint num1, jint num2) { jclass j_class = env->GetObjectClass(thiz);//根据jobject获取jclass jmethodID j_methodId = env->GetMethodID(j_class,"add","(II)I");//最后一个参数方法签名可以通过javap -s className得到 jint j_add = env->CallIntMethod(thiz, j_methodId,num1,num2); //调用java层的add方法 return j_add; } static JNINativeMethod methods[] = { { "stringFromJNI", "()Ljava/lang/String;", (void*)c_getString}, { "jniCallAdd", "(II)I", (void*)c_callAdd}, }; JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv *env = NULL; // 获取JNI env变量 if (vm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) { // 失败返回-1 return JNI_ERR; } // 获取native方法所在类 jclass clazz = env->FindClass("com/shan/dynamicndk/MainActivity"); //包名类名必须完全一致,否则匹配失败 if (clazz == NULL) { return JNI_ERR; } // 动态注册native方法 if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) { return JNI_ERR; } // 返回成功 return JNI_VERSION_1_6; }
动态注册分为三步:1、定义JNINativeMethod结构体确定映射关系 2、调用JNI_OnLoad函数去加载 3、具体实现native函数。
JNINativeMethod结构体中记录了java层函数名称name、函数签名signature以及native层代码的函数指针fnPtr,JNINativeMethod结构体定义在jni.h中,有兴趣的话可以查看一下jni.h文件。//jni.h typedef struct { char *name; char *signature; void *fnPtr; } JNINativeMethod;
-
android NDK(java调用C)
2016-11-15 09:54:35java调用C的方法 相关博客http://blog.csdn.net/lang523493505/article/details/53163679 -
GitHub - WxHlin/JavaCallC: JNI/NDK java调用c
2021-04-18 04:09:54JavaCallCJNI/NDK java调用c开发流程1、在java写native代码public class JNI {{System.loadLibrary("app");}/***定义native代码* 调用C代码对于的方法* com.loadingbar.demo.demondk.JNI#sayHello()* @return*/...JavaCallC
JNI/NDK java调用c
开发流程
1、在java写native代码
public class JNI {
{
System.loadLibrary("app");
}
/**
*定义native代码
* 调用C代码对于的方法
* com.loadingbar.demo.demondk.JNI#sayHello()
* @return
*/
public native String sayHello();
/**
* 让c代码做加法运算,把结果返回
* @param x
* @param y
* @return
*/
public native int add(int x,int y);
/**
*从java传入字符串,c代码拼接后返回
* @param s
* @return
*/
public native String sayHi(String s);
/**
* 让C代码给数组的每个元素加上10
* @param array
* @return
*/
public native int[] increaseArrayEles(int[] array);
/**
* c代码检查密码是否正确 正确返回200 错误返回400
* @param pwd
* @return
*/
public native int checkPwd(String pwd);
}
2、生成头文件.h
在AS下Terminal进入到app/src/main/java下,使用命令javah+全类名生成头文件
3、配置动态链接库的名称
ndk{
moduleName "Hello" //so文件:lib+moduleName+.so
abiFilters "armeabi","armesbi-v7a","x86" //cpu的类型
}
4、加载动态链接库
{
System.loadLibrary("app");
}
5、调用
-
JNI之java调用c库简单实例
2022-01-17 14:23:57因为架构迁移或者开发需要,有时候需要在android应用开发中,调用已有的c语言开发库,此时可能需要用到JNI。 -
安卓java调用c语言(手机编写)
2021-10-25 15:38:33如果安装不了NDK可以看这篇文章:android-ndk-aide,NDK安装教程20180605 步骤: 注:我编写的应用包名为"com.nativeapp",文件路径为"/sdcard/AppProjects/Nativeapp" 1、编写一个java(需带有native声明) Native... -
Android NDK开发——C回调Java中的方法
2014-12-11 17:40:02详情请参考我的博客 http://blog.csdn.net/allen315410/article/details/41862479 -
NDK技术,Java项目调用C代码
2021-02-25 19:59:23安装Cygwin解压android-ndk-r5c-windows.zip解压cygwin package.rarCygwin安装步骤运行setup.exe,选第三项从本地安装cygwin设置cygwin安装到那里指定安装程序位置选中安装的内容,只选devel就可以了cygwin与Ndk集成... -
NDK开发案例 | C/C++调用java层代码
2020-07-21 18:38:03NDK开发(三)——C/C++代码如何调用java层代码 E:\AndroidProject\TheTestPro\NDKDemo\app\build\intermediates\javac\debug\classes>javap -s -p com.lwp.ndkdemo.MainActivity Compiled from "MainActivity.... -
使用NDK实现Android中C与Java交叉编译
2021-03-24 01:24:13android中的java依托于java虚拟机,运行效率是比较低的,最近在做高效大数乘法中,发现了JNI或者NDK可以实现C与Java混编,并且引用c的动态库,而且android中的C语言不需要依托java虚拟机,效率还是非常高的。... -
NDK_C调用java demo
2015-09-24 14:53:45NDK中使用C代码调用java中的方法事例demo -
NDK开发之C语言调用java方法和获取属性
2018-03-30 15:22:13详细介绍了NDK开发中C语言如何获取java层对象的属性,如何调用java层的方法。 -
安卓JAVA JNI NDK 基础使用样例 附实现的详细步骤
2021-07-30 10:14:48安卓JAVA JNI NDK 基础使用样例 附实现的详细步骤开发环境实现步骤 最近做安卓项目需要使用到JNI的知识调用C文件,在网上搜寻了近两天的资料踩了很坑,总结了一套在安卓中使用JNI的步骤,记录在这里顺便提供给像我... -
Android JNI 和 NDK
2021-02-28 17:11:31JNI (Java Native Interface) 和 NDK (Native Development Kit):jni 是java调用...jni 的目的是java调用c、c++写的本地方法;android下是用JNI时需要的.so文件,是通过ndk-build生成的。Java Native Interface(J... -
ndk开发,在c中调用java中的代码
2013-12-03 15:15:03ndk开发,在c中调用java中的代码 -
Android中Java代码与C的互相调用(JNI的简单使用)
2021-05-21 05:46:05JNI(Java Native Interface):java本地开发接口,JNI是一个协议,这个协议用来沟通java代码和外部的本地代码(c/c++),外部的c/c++代码也可以调用java代码。我们为什么要使用JNI呢,可以从效率和安全性两方面... -
Android NDK 开发入门详解(三) ---- Java和C++方法相互调用
2021-10-20 15:37:36一、Java调用C++方法 -
NDK中JAVA和C互相调用
2013-04-07 15:38:29JAVA调用C, C调用JAVA创建一个按钮 这个按钮点击后,又调用一个C函数 改编自NDK例子 -
android studio 下集成ndk 通过java jni调用c
2016-10-19 10:17:05自己在android studio 环境下集成ndk 、 cmake 、LLDB 等插件 开发的一个demo ; 可以直接debug到c端代码,eclipse一般追踪不到,遇到c端出问题手机直接一个crash,,,想要了解android studio 下如何进行c 开发的... -
NDK开发之Java-C互相传值
2018-01-15 14:59:37简书链接 在平时的NDK开发中,我们通常使用C/C++封装好so库,然后客户端调用so库以完成我们的需求,在上一遍入门中(NDK开发之初入门-Hello Word)我们在So库方法中实现返回字符串Hello Word,然后在Java中进行... -
Android Studio NDK开发-JNI调用Java方法
2020-12-23 14:49:15Android Studio NDK开发-JNI调用Java方法 相对于NDK来说SDK里面有更多API可以调用,有时候我们在做NDK开发的时候,需要在JNI直接Java中的方法和变量,比如callback,系统信息等.... 如何在JNI中调用Java方法呢?就... -
安卓app开发之NDK入门教程,JAVA代码通过JNI接口调用NDK代码(C语言编写的linux android功能).zip
2021-01-12 17:10:46安卓app开发之NDK入门教程,JAVA代码通过JNI接口调用NDK代码(C语言编写的linux android功能).zip -
Android NDK Java 调用C
2011-09-26 18:19:23Android NDK Java 调用C~~~~~~~~~~~~~ -
Android Studio NDK开发之一(Java调用C的方法)
2016-11-15 09:52:35学习NDK开发的过程中查找了很多资料很多博客,也实验了很多次,觉得还是自己整理一下比较好。省略部分:添加一个button设置监听用于调用native方法。。。开始—– 1、先配置一下NDK环境 2、添加一个专门放... -
NDK开发之C语言调用Java构造方法、父类方法、返回中文字符串乱码问题案例
2018-04-02 14:40:00NDK开发之C语言调用Java构造方法、父类方法、返回中文字符串乱码问题案例详细解析。 -
使用AndroidNDK重用现有的C代码
2021-03-02 05:17:22在本教程中,您将在Java中创建一个图像处理应用程序,并通过NDK使用C代码执行基本的图像处理操作。首先,了解Android原生开发工具包(NDK)的动机之一是得以利用开源项目,大多数项目都是用C语言编写的。完成本教程... -
NDK使用方法(Java调用C)
2019-07-22 21:27:22在Android Studio3.3版本后 ,我们直接就可以调用C语言 如图: 定义方法: 方法内写C就ok了 -
Android NDK 调用C
2021-06-05 18:30:13一.环境准备:1.Cygwin:对于网速较慢的孩子,可以直接下载一个简约版:http://www.wishdown.com/soft/52987.html2.安装完毕后(笔者安装路劲为:E:\Android\Cygwin\setup)1) 修改 E:\...profile增加2行:NDK=/cygdri... -
Android NDK:JNI开发之Java调用C、C++方法:Hello word
2019-09-05 11:58:55首先下载好对应的NDK,解压目录配置到...ndk.dir=C\:\\Users\\aibo\\AppData\\Local\\Android\\Sdk\\ndk-bundle sdk.dir=C\:\\Users\\aibo\\AppData\\Local\\Android\\Sdk 方式一: 新建项目时选择最后一个...