2023-01-20 257
i有 .so (共享库)在C ++中,我们称其为功能./p>
1. unsigned long Initialize(void* userData);
2. unsigned long Uninitialize(void);
3. unsigned long DeviceOpen( unsigned long id, unsigned long* device);
4. unsigned long DeviceClose( unsigned long device );
等等…
我想在我的android应用程序中使用此库(功能)功能.为此,我在我的Android应用程序项目文件夹中创建JNI文件夹,然后放置该文件:
android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Test_library
LOCAL_SRC_FILES := Test_library.c
## Linking functionality library
LOCAL_LDLIBS := -lfunctionality
include $(BUILD_SHARED_LIBRARY)
test_library.c
#include <string.h>
#include <jni.h>
#include "Test_library.h"
jint Java_com_Dsm_Test_DsmLibraryTest_vtUninitialize(JNIEnv* env, jobject thiz) {
return Uninitialize( );
}
jint Java_com_Dsm_Test_DsmLibraryTest_vtDeviceClose(JNIEnv* env, jobject thiz, jint hDevice) {
return DeviceClose( hDevice );
}
test_library.h
初始化, , deviceOpen , deviceclose 功能.
>
之后,我运行 ndk-build 并创建一个test_library.so库并将其加载到我的Java应用程序中,然后使用它们:
// Some code
public native int Uninitialize( );
public native int DeviceClose( int hDevice );
static {
System.loadLibrary("Test_library");
}
一切正常.在我想添加其他两个功能
之后
1. unsigned long Initialize(void* userData);
2. unsigned long DeviceOpen( unsigned long id, unsigned long* device);
`
感谢您的帮助.
您可以使用jlong将指针(或指向指针或其他指针)传递给Java. Java代码将无法将其用于任何东西,除了将其作为参数传递给您的其他方法之一;但是通常这就是您真正想要的.另一方面,如果您希望使用Java中设置的数据来调用Initialize(),则void *不合适;您需要使用Java类,并在JNI中使用反射以获取所需的信息.
粗鲁,您可以包装malloc()和free():
jlong Java_c_utils_malloc(JNIEnv* env, jclass clazz, jint size) {
return (jlong) malloc(size);
}
void Java_c_utils_free(JNIEnv* env, jclass clazz, jlong ptr) {
free((void *) ptr);
}
然后在Java中使用它们(无效!):
long ptr = utils.malloc(100);
// Store ptr for a while
utils.free(ptr);
现在,如果我们包装了需要记忆块作为参数的其他功能,我们也可以包装它们,并让他们接受jlong参数,同样的方式free()也是如此. Java变量ptr代表一个内存地址的事实在Java中完全不透明,但是它仍然有用.
java(i,e.,awt,swt)的窗口系统实现使用了同样的东西将本机窗口小部件与Java组件相关联.
现在,如果您希望您的Initialize()能够从Java中获得有用的参数,那么A void *就不会剪切.您需要编写您的方法来接受Java对象作为参数;这是让您在Java中操纵对象的唯一方法.
我不想在这里复制所有代码,但是Sun的JNI教程是在这里/a>. 这是调用Java对象的任意方法的部分(要么 this 是访问对象字段的类似部分.
您想做的是:
对于void*函数,请使用直接字节缓冲区.在爪哇一侧:
native long initialize(java.nio.ByteBuffer userData);
调用该方法时,请确保分配直接的字节buffer(请参阅 java .nio.bytebuffer 和 jni nio用法):
ByteBuffer myData = ByteBuffer.allocateDirect(size);
long res = initialize(myData);
在C侧,您要这样做:
unsigned long res = Initialize(env->GetDirectBufferAddress(env, buffer));
return (jlong)res;
您用 bytebuffer 方法.
您也可以用env->NewDirectByteBuffer(env, ptr, size.
在C侧分配字节缓冲区
现在,对于第二个功能,我假设使用无符号的长*参数用于返回结果.您可以使用相同的方法(直接字节扣),但我建议您另一种不需要为如此小的值分配缓冲区的方法.
在爪哇一侧:
native long deviceOpen(long id, long[] device);
在C侧:
unsigned long c_device;
unsigned long res = DeviceOpen((unsigned long)j_id, &c_device);
env->SetLongArrayRegion(env, j_device, 0, 1, &c_device);
return (jlong)res;
然后您从Java调用该方法:
long[] deviceOut = new long[1];
long res = deviceOpen(id, deviceOut);
long device = deviceOut[0];
有关数组访问的更多信息,请参见 JNI数组操作
我考虑@pron回答到目前为止的最佳选择.
关于自动jni代码生成,考虑 jnigen
它非常简单且功能强大.
获取Javadocs,并寻找 nativecodegenerator 类.
它具有Java类型和本机CPP类型之间的应用映射,如字符串到char*,int []到int*,floatBuffer到float*,等等.
jnigen如GitHub上所述
jnigen是一个小库,可以在有或没有libgdx的情况下使用,允许使用Java源代码在线编写C/C ++代码.
jnigen有两个部分:
在特定文件夹中检查Java源文件,检测本机方法和随附的C ++实现,并吐出C ++源文件和标头,类似于您使用JNI手动创建的内容.
为蚂蚁构建脚本提供了一个生成器,该脚本为每个平台构建本地源.
示例:
这是您的Java本机方法,其所需的CPP代码在方法声明之后被定义为注释:
private static native ByteBuffer newDisposableByteBuffer (int numBytes); /*
char* ptr = (char*)malloc(numBytes);
return env->NewDirectByteBuffer(ptr, numBytes);
*/
private native static void copyJni (float[] src, Buffer dst, int numFloats, int offset); /*
memcpy(dst, src + offset, numFloats << 2 );
*/
运行jnigen生成器后,您将拥有带有C代码和绑定的 *.cpp文件. *.h也是自动创建的.
CPP看起来像这样:
JNIEXPORT jobject JNICALL
Java_com_badlogic_gdx_utils_BufferUtils_newDisposableByteBuffer
(JNIEnv* env, jclass clazz, jint numBytes) {
//@line:334
char* ptr = (char*)malloc(numBytes);
return env->NewDirectByteBuffer(ptr, numBytes);
}
JNIEXPORT void JNICALL
Java_com_badlogic_gdx_utils_BufferUtils_copyJni___3FLjava_nio_Buffer_2II
(JNIEnv* env, jclass clazz, jfloatArray obj_src, jobject obj_dst, jint numFloats, jint offset) {
unsigned char* dst = (unsigned char*)env->GetDirectBufferAddress(obj_dst);
float* src = (float*)env->GetPrimitiveArrayCritical(obj_src, 0);
//@line:348
memcpy(dst, src + offset, numFloats << 2 );
env->ReleasePrimitiveArrayCritical(obj_src, src, 0);
}
这就是Jnigen:
/**
* @param userData - a pointer. Assumed position() is Zero.
**/
public native static long initialize(Buffer userData);/*
return (jlong) Initialize( (void*) userData);
*/
public native static long uninitialize();/*
return (jlong) Uninitialize();
*/
/**
* Assumptions : id points to a unique device
* @param id - id
* @param device - a long[] with length 1, to return device pointer.
*/
public native static long deviceOpen(long id, long[] device);/*
return (jlong) DeviceOpen( (unsigned long) id, (unsigned long*) device);
*/
public native static long deviceClose(long device);/*
return (jlong) DeviceClose( (unsigned long) device);
*/
以上所述是小编给大家介绍的jni不支持void*, unsigned int*, ….等类型。该怎么做?,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!
原文链接:https://77isp.com/post/26068.html
=========================================
https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。
数据库技术 2022-03-28
网站技术 2022-11-26
网站技术 2023-01-07
网站技术 2022-11-17
Windows相关 2022-02-23
网站技术 2023-01-14
Windows相关 2022-02-16
Windows相关 2022-02-16
Linux相关 2022-02-27
数据库技术 2022-02-20
抠敌 2023年10月23日
嚼餐 2023年10月23日
男忌 2023年10月22日
瓮仆 2023年10月22日
簿偌 2023年10月22日
扫码二维码
获取最新动态