Android 11迁移:JNI调用Java静态方法打开URL崩溃求助
解决Android 11下JNI调用Java静态方法崩溃的问题
核心问题分析
你的JNI代码存在两个致命问题,直接导致崩溃和方法访问错误:
- C字符串直接强转jstring:直接把C字符串
"https://stackoverflow.com/"强转为jstring类型是错误的。jstring是JVM内部的对象引用,必须通过JNI函数NewStringUTF创建,强转会触发内存访问错误。 - 缺少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
相关产品推荐
相关产品推荐

