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

如何在Android的JNI原生代码中获取GPS位置更新?

在JNI中实现Android GPS位置追踪的步骤指引

要在JNI中实现和你给出的Java代码等效的GPS位置追踪,本质是通过JNI调用Android框架的Java API完成流程,以下是具体实现步骤和代码示例:

1. 准备Java层基础代码

首先需要在Java层定义JNI入口方法,以及一个LocationListener实现类用于接收位置回调并传递给JNI处理:

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-gps");
    }

    // 原生方法:启动GPS追踪
    public native void startGpsTracking();

    // 处理位置更新的Java方法
    private void handleLocationUpdate(double latitude, double longitude) {
        Toast.makeText(this, "Latitude: " + latitude + ", Longitude: " + longitude, Toast.LENGTH_SHORT).show();
    }

    // 自定义LocationListener,将位置回调转发给JNI
    private class NativeLocationListener implements LocationListener {
        @Override
        public void onLocationChanged(Location location) {
            nativeHandleLocation(location.getLatitude(), location.getLongitude());
        }

        // 其他接口方法按需实现或留空
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {}
        @Override
        public void onProviderEnabled(String provider) {}
        @Override
        public void onProviderDisabled(String provider) {}
    }

    // JNI处理位置数据的入口方法
    private native void nativeHandleLocation(double latitude, double longitude);
}

2. JNI层核心逻辑实现

在C++代码中完成获取LocationManager、创建Listener实例、调用位置更新接口的流程:

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

#define LOG_TAG "NativeGPS"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

// 全局引用:避免Context和Listener被GC回收
static jobject g_context = nullptr;
static jobject g_location_listener = nullptr;

extern "C" JNIEXPORT void JNICALL
Java_com_example_nativegps_MainActivity_startGpsTracking(JNIEnv *env, jobject thiz) {
    // 保存Context全局引用
    g_context = env->NewGlobalRef(thiz);

    // 1. 获取LocationManager实例
    jclass context_cls = env->FindClass("android/content/Context");
    jfieldID location_service_field = env->GetStaticFieldID(context_cls, "LOCATION_SERVICE", "Ljava/lang/String;");
    jstring location_service_str = (jstring)env->GetStaticObjectField(context_cls, location_service_field);
    
    jmethodID get_system_service_method = env->GetMethodID(context_cls, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
    jobject location_manager_obj = env->CallObjectMethod(g_context, get_system_service_method, location_service_str);
    jclass location_manager_cls = env->FindClass("android/location/LocationManager");

    // 2. 创建NativeLocationListener实例
    jclass listener_cls = env->FindClass("com/example/nativegps/MainActivity$NativeLocationListener");
    // 内部类构造方法需要传入外部类实例作为第一个参数
    jmethodID listener_constructor = env->GetMethodID(listener_cls, "<init>", "(Lcom/example/nativegps/MainActivity;)V");
    g_location_listener = env->NewGlobalRef(env->NewObject(listener_cls, listener_constructor, g_context));

    // 3. 调用requestLocationUpdates
    jfieldID gps_provider_field = env->GetStaticFieldID(location_manager_cls, "GPS_PROVIDER", "Ljava/lang/String;");
    jstring gps_provider_str = (jstring)env->GetStaticObjectField(location_manager_cls, gps_provider_field);
    
    jmethodID request_updates_method = env->GetMethodID(location_manager_cls, "requestLocationUpdates", "(Ljava/lang/String;JFLandroid/location/LocationListener;)V");
    try {
        env->CallVoidMethod(location_manager_obj, request_updates_method, gps_provider_str, 1000L, 1.0f, g_location_listener);
    } catch (...) {
        LOGD("触发SecurityException:请检查位置权限是否授予");
    }

    // 释放局部引用
    env->DeleteLocalRef(context_cls);
    env->DeleteLocalRef(location_service_str);
    env->DeleteLocalRef(location_manager_obj);
    env->DeleteLocalRef(location_manager_cls);
    env->DeleteLocalRef(listener_cls);
    env->DeleteLocalRef(gps_provider_str);
}

extern "C" JNIEXPORT void JNICALL
Java_com_example_nativegps_MainActivity_nativeHandleLocation(JNIEnv *env, jobject thiz, jdouble latitude, jdouble longitude) {
    // 调用Java层方法显示位置信息
    jclass activity_cls = env->FindClass("com/example/nativegps/MainActivity");
    jmethodID handle_update_method = env->GetMethodID(activity_cls, "handleLocationUpdate", "(DD)V");
    env->CallVoidMethod(thiz, handle_update_method, latitude, longitude);
    env->DeleteLocalRef(activity_cls);
}

// 在JNI卸载时释放全局引用
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
    JNIEnv *env;
    if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) {
        return;
    }
    if (g_context != nullptr) {
        env->DeleteGlobalRef(g_context);
        g_context = nullptr;
    }
    if (g_location_listener != nullptr) {
        env->DeleteGlobalRef(g_location_listener);
        g_location_listener = nullptr;
    }
}

关键注意事项

  • 全局引用管理:必须用NewGlobalRef保存Context和Listener对象,避免Java GC回收导致JNI调用崩溃,同时在JNI_OnUnload中释放引用。
  • 方法签名匹配:JNI调用Java方法时,必须严格匹配方法签名(可通过javap -s命令生成),比如内部类构造方法需要传入外部类实例作为第一个参数。
  • 权限要求:实际运行必须申请ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION权限,否则会触发SecurityException。
  • 线程处理:LocationListener的回调在非UI线程执行,若需更新UI,要在Java层切换到主线程处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 10:50:37