在 Go 中将 C.jstring 转换为本机字符串

2022-09-02 11:03:01

如何在Go中将C.jstring转换为可用的字符串?

我正在使用GoAndroid

在C中,你可以做类似这个堆栈溢出线程的事情

JNIEXPORT void JNICALL Java_ClassName_MethodName(JNIEnv *env, jobject obj, jstring javaString)   
{
   const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);

  // use your string

  (*env)->ReleaseStringUTFChars(env, javaString, nativeString);
}

在Go中,它开始看起来像这样

func Java_ClassName_MethodName(env *C.JNIEnv, clazz C.jclass, jstring javaString) {
    defer func() {
        if err := recover(); err != nil {
           log.Fatalf("panic: init: %v\n", err)
       }
   }()
   // ???
}

答案 1

我知道这个问题已经很老了,但我最近遇到了这个问题,并认为我会为其他任何在这里结束的人详细说明一下:

像 JNI 这样的函数是不能直接从 Go 调用的函数指针。您必须将函数包装在单独的 C 文件中,例如:GetStringUTFChars

jx.c
#include <jni.h>

const char* jx_GetStringUTFChars(JNIEnv *env, jstring str, jboolean *isCopy) {
    return (*env)->GetStringUTFChars(env, str, isCopy);
}

从 C 文件创建库后,Go 文件将如下所示:

package main

/*
#cgo CFLAGS: -I/usr/java/jdkX.X.X_XXX/include/ -I/usr/java/jdkX.X.X_XXX/include/linux/
#cgo LDFLAGS: -L${SRCDIR}/ -ljx

#include "jx.h"
*/
import "C"
import (
    "fmt"
)

//export Java_com_mypackage_MyClass_print
func Java_ClassName_MethodName(env *C.JNIEnv, clazz C.jclass, str C.jstring) {
    s := C.jx_GetStringUTFChars(env, str, (*C.jboolean)(nil))
    fmt.Println(C.GoString(s))
}

func main() {}

之所以有一个单独的 C 文件仅用于包装器函数,是因为文档中的以下子句:

在文件中使用 //export 会对前导码施加限制:由于它被复制到两个不同的 C 输出文件中,因此它不能包含任何定义,只能包含声明。


答案 2

如果我是你,我会寻找Java到C字符串,然后使用标准的C字符串到Go字符串。

我会考虑编写一个C函数,将Java字符串转换为C字符串,并将其返回到Go运行时。

C 到 GoString:

b := C.malloc(50)
defer C.free(unsafe.Pointer(b))
C.callToCFunction(PChar(b), 50)
rs := C.GoString(PChar(b))
return rs, err

Java有自己的内存管理,因此应该有自己的将数据移动到C中的方式。您可以使用Java JNI关键字询问。

您在一个进程中使用 Java 和 Go 运行时。这可能会有一些副作用。


推荐