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

JNI调用Android Java方法失败:native代码无法调用MainActivity方法

问题排查与解决方案

核心问题分析

你的Native代码调用Java方法失败(customRequestMethod为NULL),主要由以下几个原因导致:

  • 类对象获取错误:GetObjectClass(app->activity->clazz)可能拿到的是NativeActivity的类,而非你自定义的MainActivity类,自然找不到子类中新增的方法。
  • 调用时机过早:android_main启动时直接调用权限申请,此时MainActivity的初始化可能还未完成,Activity实例未就绪。
  • Manifest配置缺失:未正确将MainActivity配置为启动Activity,导致实际运行的是原生NativeActivity,没有自定义方法的实现。

分步解决方案

1. 修正AndroidManifest配置

确保Manifest中声明MainActivity为启动Activity,并配置Native库依赖:

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name">
    <activity
        android:name=".MainActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <!-- 必须配置,关联Native库 -->
        <meta-data
            android:name="android.app.lib_name"
            android:value="你的Native库名称" />
    </activity>
</application>

2. 修正JNI类查找逻辑

直接通过全类名查找MainActivity的Class(注意将包名中的.替换为/):

// 替换原有的GetObjectClass调用
jclass activityClass = env->FindClass("com/google/sample/simcode/MainActivity");

3. 调整权限申请时机

避免在android_main启动时直接调用,改为在Activity窗口初始化完成后触发(通过NDK的事件回调):

#include <android/native_activity.h>

static void handleAppCmd(struct android_app* app, int32_t cmd) {
    switch (cmd) {
        case APP_CMD_INIT_WINDOW:
            // 窗口初始化完成,此时Activity已就绪
            callJavaRequestPermissions(app);
            break;
        // 其他事件处理
        default:
            break;
    }
}

void android_main(struct android_app* app) {
    // 设置事件回调
    app->onAppCmd = handleAppCmd;

    // 事件循环,保证Native层正常运行
    int events;
    struct android_poll_source* source;
    while (ALooper_pollAll(-1, nullptr, &events, (void**)&source) >= 0) {
        if (source != nullptr) {
            source->process(app, source);
        }
    }
}

4. 添加JNI错误日志排查

加入日志输出,方便定位问题:

#include <android/log.h>
#define LOG_TAG "JNI_PERM"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

// 在类查找失败时输出日志
if (activityClass == nullptr) {
    LOGE("找不到MainActivity类");
    if (env->ExceptionCheck()) {
        env->ExceptionDescribe();
        env->ExceptionClear();
    }
    return;
}

// 在方法查找失败时输出日志
if (customRequestMethod == nullptr) {
    LOGE("找不到customRequestPermissions方法");
    if (env->ExceptionCheck()) {
        env->ExceptionDescribe();
        env->ExceptionClear();
    }
    return;
}

同时在build.gradle中开启日志支持:

android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                arguments "-DANDROID_LOG_ENABLED=ON"
            }
        }
    }
}

修改后的完整JNI代码

#include <android/native_activity.h>
#include <android/log.h>
#include <jni.h>

#define LOG_TAG "JNI_PERM"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

void callJavaRequestPermissions(struct android_app* app) {
    JNIEnv* env = nullptr;
    app->activity->vm->AttachCurrentThread(&env, nullptr);

    jclass activityClass = env->FindClass("com/google/sample/simcode/MainActivity");
    if (activityClass == nullptr) {
        LOGE("找不到MainActivity类");
        if (env->ExceptionCheck()) {
            env->ExceptionDescribe();
            env->ExceptionClear();
        }
        app->activity->vm->DetachCurrentThread();
        return;
    }

    jmethodID customRequestMethod = env->GetMethodID(activityClass, "customRequestPermissions", "([Ljava/lang/String;I)V");
    if (customRequestMethod == nullptr) {
        LOGE("找不到customRequestPermissions方法");
        if (env->ExceptionCheck()) {
            env->ExceptionDescribe();
            env->ExceptionClear();
        }
        env->DeleteLocalRef(activityClass);
        app->activity->vm->DetachCurrentThread();
        return;
    }

    jobjectArray permissions = env->NewObjectArray(1, env->FindClass("java/lang/String"), nullptr);
    jstring permission = env->NewStringUTF("android.permission.WRITE_EXTERNAL_STORAGE");
    env->SetObjectArrayElement(permissions, 0, permission);

    // 调用Java方法,传入Activity实例
    env->CallVoidMethod(app->activity->clazz, customRequestMethod, permissions, 101);

    // 释放局部引用
    env->DeleteLocalRef(permission);
    env->DeleteLocalRef(permissions);
    env->DeleteLocalRef(activityClass);

    app->activity->vm->DetachCurrentThread();
}

static void handleAppCmd(struct android_app* app, int32_t cmd) {
    switch (cmd) {
        case APP_CMD_INIT_WINDOW:
            callJavaRequestPermissions(app);
            break;
        default:
            break;
    }
}

void android_main(struct android_app* app) {
    app->onAppCmd = handleAppCmd;

    int events;
    struct android_poll_source* source;
    while (ALooper_pollAll(-1, nullptr, &events, (void**)&source) >= 0) {
        if (source != nullptr) {
            source->process(app, source);
        }
    }
}

内容的提问来源于stack exchange,提问作者خلیل ترابی

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 06:12:06