You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义Gluon Attach插件中Java Runnable的JNI传递调用异常

自定义Gluon Attach插件中Runnable对象跨JNI层传递调用问题

背景

开发自定义Gluon Attach插件时,尝试将Java Runnable对象作为native方法showSaveAlert3的参数从Java层传递到JNI层,Native侧调用该Runnable时持续报错:

JNI DETECTED ERROR IN APPLICATION: JNI ERROR (app bug):  
jobject is an invalid JNI transition frame reference: 0x8000000000000008  

代码概览

Java类1(AndroidAlertDialogService)

package com.gluonhq.attachextended.alertdialog.impl;

import com.gluonhq.attachextended.alertdialog.AlertDialogService;

public class AndroidAlertDialogService implements AlertDialogService {

    static {
        System.loadLibrary("alertdialog");
    }

    @Override
    public void showSaveAlert(String title, String content, Runnable r) {
        showSaveAlert3(title, content, r);
    }

    private native static void showSaveAlert3(String title, String content, Runnable r);
}

JNI代码(alertdialog.c)

#include "util.h"

static jclass jAlertDialogServiceClass;
static jobject jDalvikAlertDialogService;

static jmethodID jAlertDialogServiceShowSaveAlert3Method;

static void initializeAlertDialogDalvikHandles() {
    jAlertDialogServiceClass = GET_REGISTER_DALVIK_CLASS(jAlertDialogServiceClass, "com/gluonhq/helloandroid/DalvikAlertDialogService");
    
    ATTACH_DALVIK();
    jmethodID jAlertDialogServiceInitMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jAlertDialogServiceClass, "<init>", "(Landroid/app/Activity;)V");

    jAlertDialogServiceShowSaveAlert3Method = (*dalvikEnv)->GetMethodID(dalvikEnv, jAlertDialogServiceClass, "showSaveAlert3", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Runnable;)V");
    
    jobject jActivity = substrateGetActivity();
    jobject jObj = (*dalvikEnv)->NewObject(dalvikEnv, jAlertDialogServiceClass, jAlertDialogServiceInitMethod, jActivity);
    jDalvikAlertDialogService = (*dalvikEnv)->NewGlobalRef(dalvikEnv, jObj);
    DETACH_DALVIK();
}

//////////////////////////
// From Graal to native //
//////////////////////////

JNIEXPORT jint JNICALL
JNI_OnLoad_alertdialog(JavaVM *vm, void *reserved)
{
    JNIEnv* graalEnv;
    ATTACH_LOG_INFO("JNI_OnLoad_alertdialog called");
#ifdef JNI_VERSION_1_8
    if ((*vm)->GetEnv(vm, (void **)&graalEnv, JNI_VERSION_1_8) != JNI_OK) {
        ATTACH_LOG_WARNING("Error initializing native AlertDialog from OnLoad");
        return JNI_FALSE;
    }
    ATTACH_LOG_FINE("[AlertDialog Service] Initializing native AlertDialog from OnLoad");
    initializeAlertDialogDalvikHandles();
    return JNI_VERSION_1_8;
#else
    #error Error: Java 8+ SDK is required to compile Attach
#endif
}

// from Java to Android

JNIEXPORT void JNICALL Java_com_gluonhq_attachextended_alertdialog_impl_AndroidAlertDialogService_showSaveAlert3  
(JNIEnv *env, jclass jClass, jstring jtitle, jstring jcontent, jobject jr) {  
    const char *titleChars = (*env)->GetStringUTFChars(env, jtitle, NULL);  
    const char *contentChars = (*env)->GetStringUTFChars(env, jcontent, NULL);  

    ATTACH_DALVIK();  
    jstring jTitleString = (*dalvikEnv)->NewStringUTF(dalvikEnv, titleChars);  
    jstring jContentString = (*dalvikEnv)->NewStringUTF(dalvikEnv, contentChars);  

    jobject globalRunnable = (*dalvikEnv)->NewGlobalRef(dalvikEnv, jr);  
    jclass rClass = (*dalvikEnv)->GetObjectClass(dalvikEnv, globalRunnable);  

    jmethodID midMyCustomMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, rClass, "run", "()V");  
    (*dalvikEnv)->CallVoidMethod(dalvikEnv, jDalvikAlertDialogService, jAlertDialogServiceShowSaveAlert3Method, jTitleString, jContentString, midMyCustomMethod);  

    DETACH_DALVIK();  
    (*env)->ReleaseStringUTFChars(env, jtitle, titleChars);  
    (*env)->ReleaseStringUTFChars(env, jcontent, contentChars);  
}

Java类2(DalvikAlertDialogService)

package com.gluonhq.helloandroid;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.app.Activity;

public class DalvikAlertDialogService {

    private final Activity activity;

    public DalvikAlertDialogService(Activity activity) {
        this.activity = activity;
    }

    public void showSaveAlert3(String title, String content, Runnable r) {
        activity.runOnUiThread(() -> {
            if (!activity.isFinishing()) {
                AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
                dialog.setCancelable(false);
                dialog.setTitle(title);
                dialog.setMessage(content);
                dialog.setPositiveButton("Ok", (DialogInterface dialog1, int id) -> {
                    dialog1.dismiss();
                    r.run();
                });

                AlertDialog alert = dialog.create();
                alert.show();
            }
        });
    }
}

已尝试方案

  • 使用NewGlobalRef创建Runnable对象的持久引用后再调用其run方法。
  • 检查Dalvik环境(dalvikEnv)的有效性。
  • 查阅Gluon Attach现有插件(如DisplayService、StorageService)源码,但这些示例主要关注字符串、基本类型或数组的传递,未涉及Runnable这类复杂Java对象。

问题说明

尽管做了上述尝试,仍无法调用Runnable的run()方法,jobject引用在JNI环境中似乎失效,导致上述错误。

疑问

  • 在此场景下,将Java Runnable对象传递到JNI并调用其run()方法的正确方式是什么?
  • 处理Gluon Attach中的Runnable对象是否有遗漏的特定步骤?
  • 该问题是否与Dalvik环境中引用管理(NewGlobalRef、Detach等)不当有关?

内容的提问来源于stack exchange,提问作者CTO - Abid Maqbool

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 15:24:50