Aer*_*alo 17 c++ java java-native-interface android android-ndk
我正在构建一个正在构建Android应用程序的项目的C++方面.我需要传递给Java应用程序(通过JNI)的一些信息(通过字符串和字符串数组).我以前从未这样做过,反向工作的人没有C++经验,并承认他们无法真正帮助.
我确实找到了以下代码(从这里)
#include <jni.h>
#include "ArrayHandler.h"
JNIEXPORT jobjectArray JNICALL Java_ArrayHandler_returnArray (JNIEnv *env, jobject jobj){
jobjectArray ret;
int i;
char *message[5]= {"first","second","third","fourth","fifth"};
ret= (jobjectArray)env->NewObjectArray(5,env->FindClass("java/lang/String"),env->NewStringUTF(""));
for(i=0;i<5;i++) {
env->SetObjectArrayElement(ret,i,env->NewStringUTF(message[i]));
}
return(ret);
}
Run Code Online (Sandbox Code Playgroud)
但这对我来说毫无意义.大多数情况下,我不确定我应该如何将其纳入程序的C++方面,而我却无法确切了解其工作原理.代码是否在执行该return(ret);行时发送消息?或者在for循环中执行行期间?
理想情况下,我希望字符串/字符串数组在行中"实时"发送,而不是在函数的末尾发送,这样我就不必合并新函数.
我发现的代码能否满足我的需求(通过一些改编)?我正在寻找甚至可能吗?如果是这样,我该怎么办?
编辑/更新: 花了一天时间研究JNI和术语,我想我无法正确地传达我想要在这里实现的内容以及对@ jogabonito的回答/回复的评论.
话虽如此.我正在处理的代码是一个IM客户端,需要将消息和状态更新推送到Android Java应用程序(通过JNI),以便Android应用程序不会轮询更新.我已经设法学习如何设置java代码的函数来调用requrest信息.但是,我不知道如何将新消息或状态信息(jabber节字符串)推送到java代码中.所有关于如何执行此操作的代码(请参阅下面的示例)似乎需要从java代码(env,class,methodid等)获取信息.
当我不是调用函数的java代码,而是我的c ++代码时,这对我来说是不可能的.任何解释/帮助将非常感谢.
#include <string.h>
#include <stdio.h>
#include <jni.h>
jstring Java_the_package_MainActivity_getJniString( JNIEnv* env, jobject obj){
jstring jstr = (*env)->NewStringUTF(env, "This comes from jni.");
jclass clazz = (*env)->FindClass(env, "com/inceptix/android/t3d/MainActivity");
jmethodID messageMe = (*env)->GetMethodID(env, clazz, "messageMe", "(Ljava/lang/String;)Ljava/lang/String;");
jobject result = (*env)->CallObjectMethod(env, obj, messageMe, jstr);
const char* str = (*env)->GetStringUTFChars(env,(jstring) result, NULL); // should be released but what a heck, it's a tutorial :)
printf("%s\n", str);
return (*env)->NewStringUTF(env, str);
}
Run Code Online (Sandbox Code Playgroud)
Tom*_*get 14
在@Sam的请求下,这是一种避免使用修改的UTF-8的方法,因为我们不知道这样做是安全的.
NewStringUTF根据其修改的UTF-8编码创建一个字符串.将它与用户数据一起使用是不正确的 - 它不太可能用修改后的UTF-8编码.我们可以希望数据中的字符被限制以保持兼容.相反,我们可以正确地转换它.
JNI在其API中使用修改后的UTF-8字符串.我们可以使用我们知道兼容的字符串,特别是Java标识符的文字(除非所有货币符号除外).
以下是两个本机方法实现.第二种在大多数方面都更好.
对于这种原生方法:
private static native String getJniString();
Run Code Online (Sandbox Code Playgroud)
这是一个实现:
JNIEXPORT jstring JNICALL
Java_the_Package_MainActivity_getJniString(JNIEnv *env, jclass)
{
std::string message = "Would you prefer €20 once "
"or ?10 every day for a year?";
int byteCount = message.length();
jbyte* pNativeMessage = reinterpret_cast<const jbyte*>(message.c_str());
jbyteArray bytes = env->NewByteArray(byteCount);
env->SetByteArrayRegion(bytes, 0, byteCount, pNativeMessage);
// find the Charset.forName method:
// javap -s java.nio.charset.Charset | egrep -A2 "forName"
jclass charsetClass = env->FindClass("java/nio/charset/Charset");
jmethodID forName = env->GetStaticMethodID(
charsetClass, "forName", "(Ljava/lang/String;)Ljava/nio/charset/Charset;");
jstring utf8 = env->NewStringUTF("UTF-8");
jobject charset = env->CallStaticObjectMethod(charsetClass, forName, utf8);
// find a String constructor that takes a Charset:
// javap -s java.lang.String | egrep -A2 "String\(.*charset"
jclass stringClass = env->FindClass("java/lang/String");
jmethodID ctor = env->GetMethodID(
stringClass, "<init>", "([BLjava/nio/charset/Charset;)V");
jstring jMessage = reinterpret_cast<jstring>(
env->NewObject(stringClass, ctor, bytes, charset));
return jMessage;
}
Run Code Online (Sandbox Code Playgroud)
JNI很尴尬.所以,如果我们可以将原生字符串为"UTF-8"的知识转移到Java端,我们可以这样做:
private static String getJniString2()
{
return new String(getJniStringBytes(), Charset.forName("UTF-8"));
}
private static native byte[] getJniStringBytes();
Run Code Online (Sandbox Code Playgroud)
更简单的实现:
JNIEXPORT jbyteArray JNICALL Java_the_Package_MainActivity_getJniStringBytes(JNIEnv *env, jclass)
{
std::string message = "Would you prefer €20 once "
"or ?10 every day for a year?";
int byteCount = message.length();
jbyte* pNativeMessage = reinterpret_cast<const jbyte*>(message.c_str());
jbyteArray bytes = env->NewByteArray(byteCount);
env->SetByteArrayRegion(bytes, 0, byteCount, pNativeMessage);
return bytes;
}
Run Code Online (Sandbox Code Playgroud)
在您共享的函数中,您正在使用 C++ 代码创建一个对象数组NewObjectArray。然后在 for 循环中,您NewStringUTF使用 创建一个字符串并将其存储在数组中的索引处SetObjectArrayElement。到目前为止,您的对象数组只有 C++ 代码知道,而 Java 代码则不知道。只有当您返回它时,您的 java 应用程序才能访问它。
我可以想到几种将字符串从 C++ 发送到 java 的方法,尽管它可能不完全是您想要的。
将字符串数组传递给您的本机函数。在本机代码中,您可以使用 访问每个元素GetObjectArrayElement并使用 更新它SetObjectArrayElement。这可能毫无意义,因为您最终不得不调用一个我认为您不想要的函数。
GetFieldID如果您已经在 Java 代码中定义了一个字符串作为字段,则可以使用和从本机访问它GetObjectField,并且可以使用 更新它SetObjectField。我不知道你如何向你的java代码发出该字段已更新的信号(如果你需要的话)
编辑
您编写的更新函数旨在从java层调用。线索是函数的名称Java_the_package_MainActivity_getJniString。要从本机上下文调用 java 代码,您将需要对 java.langenv和objjava.lang.String 的引用。看看如何在 Android 上用 C 加载我自己的 Java 类?获取此方法的方法。您可能还需要了解如何在 JNI 中使用全局引用
| 归档时间: |
|
| 查看次数: |
22408 次 |
| 最近记录: |