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

Android 11迁移:JNI调用Java静态方法打开URL崩溃求助

解决Android 11下JNI调用Java静态方法崩溃的问题

核心问题分析

你的JNI代码存在两个致命问题,直接导致崩溃和方法访问错误:

  1. C字符串直接强转jstring:直接把C字符串"https://stackoverflow.com/"强转为jstring类型是错误的。jstring是JVM内部的对象引用,必须通过JNI函数NewStringUTF创建,强转会触发内存访问错误。
  2. 缺少JNI调用的错误检查:FindClass和GetStaticMethodID可能因类找不到、方法签名不匹配等返回NULL,未做检查的后续调用会直接崩溃。

另外,Utils.open_url方法仅打印URL,未实现实际打开浏览器的逻辑,这部分也需要补充完善。

修复后的代码示例

1. 修正JNI层代码(main.c)

#include <jni.h>

// 假设g_env是已初始化完成的JNIEnv指针
JNIEnv* g_env;

void test( void ) {
    // 1. 查找Utils类
    jclass cls = (*g_env)->FindClass(g_env, "com/android/MyApp/Utils");
    if (cls == NULL) {
        // 类查找失败,可添加日志或错误处理逻辑
        return;
    }

    // 2. 获取静态方法ID,确保方法签名完全匹配
    jmethodID open_url_method = (*g_env)->GetStaticMethodID(g_env, cls, "open_url", "(Landroid/content/Context;Ljava/lang/String;)V");
    if (open_url_method == NULL) {
        (*g_env)->DeleteLocalRef(g_env, cls);
        return;
    }

    // 3. 将C字符串转换为jstring对象
    jstring url_jstr = (*g_env)->NewStringUTF(g_env, "https://stackoverflow.com/");
    if (url_jstr == NULL) {
        (*g_env)->DeleteLocalRef(g_env, cls);
        return;
    }

    // 注意:需要传入有效的Context对象,这里假设你已通过JNI获取到全局引用的Context
    jobject global_context = NULL; // 替换为你的全局Context引用
    if (global_context == NULL) {
        (*g_env)->DeleteLocalRef(g_env, cls);
        (*g_env)->DeleteLocalRef(g_env, url_jstr);
        return;
    }

    // 4. 调用静态方法
    (*g_env)->CallStaticVoidMethod(g_env, cls, open_url_method, global_context, url_jstr);

    // 5. 释放局部引用,避免内存泄漏
    (*g_env)->DeleteLocalRef(g_env, cls);
    (*g_env)->DeleteLocalRef(g_env, url_jstr);
}

2. 完善Utils类的打开URL逻辑(Utils.java)

补充启动浏览器的Intent逻辑,同时适配Android 11的包可见性规则:

package com.android.MyApp;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;

public class Utils {
    public static void open_url(Context context, String url) {
        Log.d("Utils", "待打开URL:" + url);
        try {
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            // 检查是否有可处理该Intent的应用
            if (intent.resolveActivity(context.getPackageManager()) != null) {
                context.startActivity(intent);
            } else {
                Log.e("Utils", "未找到可打开URL的应用");
            }
        } catch (Exception e) {
            Log.e("Utils", "打开URL失败:" + e.getMessage());
        }
    }
}

3. 适配Android 11包可见性(AndroidManifest.xml)

在<manifest>标签内添加声明,确保应用能找到浏览器:

<queries>
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="https" />
    </intent>
</queries>

额外注意事项

  • JNIEnv线程安全性:JNIEnv指针与线程绑定,若test函数在非Java线程调用,需先通过AttachCurrentThread获取当前线程的JNIEnv。
  • Context引用管理:若使用全局Context引用,需确保其生命周期与应用一致,避免内存泄漏。
  • 局部引用释放:JNI中的局部引用(如jclass、jstring)会占用JVM内存,使用后必须调用DeleteLocalRef释放。

内容的提问来源于stack exchange,提问作者McBob

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 10:01:17