標準的JNI (Java Native Interface) 加載函數 JNI_OnLoad

1.JNI_OnLoad

在 Android Native 開發中,JNI_OnLoad 是動態注冊本地方法的標準入口點。以下是一個標準實現示例及其說明:


JNI_OnLoad 標準實現

#include <jni.h>
#include <string>// 聲明本地方法對應的 C/C++ 函數
jint native_add(JNIEnv* env, jobject thiz, jint a, jint b) {return a + b;
}// 定義 JNINativeMethod 結構體數組
static JNINativeMethod gMethods[] = {// Java方法名 | 方法簽名 | 本地函數指針{"add", "(II)I", (void*)native_add},
};// 緩存 JavaVM 實例(用于后續獲取 JNIEnv)
JavaVM* gJavaVM = nullptr;JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {JNIEnv* env = nullptr;jint result = -1;// 1. 獲取 JNIEnvif (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) {return JNI_ERR;}// 2. 緩存 JavaVM 實例gJavaVM = vm;// 3. 找到目標 Java 類const char* className = "com/example/MyJniClass";jclass clazz = env->FindClass(className);if (clazz == nullptr) {return JNI_ERR;}// 4. 注冊本地方法if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) < 0) {return JNI_ERR;}// 5. 返回使用的 JNI 版本(必須與獲取 JNIEnv 時指定的版本一致)return JNI_VERSION_1_6;
}

關鍵步驟說明

  1. 獲取 JNIEnv
    通過 JavaVM::GetEnv 獲取 JNIEnv 指針,需指定 JNI 版本(通常為 JNI_VERSION_1_6)。

  2. 緩存 JavaVM
    JavaVM 實例保存到全局變量中,以便在其他線程中通過 AttachCurrentThread 獲取 JNIEnv

  3. 查找 Java 類
    使用 FindClass 找到需要注冊本地方法的 Java 類(需全限定類名,如 com/example/MyJniClass)。

  4. 注冊本地方法
    調用 RegisterNativesJNINativeMethod 數組中的方法動態注冊到目標類。每個 JNINativeMethod 包含:

    • Java 方法名:與 Java 代碼中的 native 方法名一致。
    • 方法簽名:描述方法的參數和返回值類型(可通過 javap -s <ClassName> 生成)。
    • 本地函數指針:C/C++ 實現的函數地址。
  5. 返回 JNI 版本
    需返回與 GetEnv 中指定的版本一致的 JNI 版本號(如 JNI_VERSION_1_6)。


注意事項

  1. 方法簽名
    必須與 Java 方法的參數和返回值類型完全匹配。例如:

    • (II)I 表示接收兩個 int 參數并返回 int
    • (Ljava/lang/String;)V 表示接收一個 String 參數且無返回值。
  2. 避免名稱改編(C++)
    如果使用 C++,需通過 extern "C"#pragma GCC visibility 確保函數名稱不被編譯器改編:

    extern "C" JNIEXPORT jint JNICALL Java_com_example_MyJniClass_add(JNIEnv*, jobject, jint, jint);
    
  3. 錯誤處理
    檢查 FindClassRegisterNatives 的返回值,避免因注冊失敗導致崩潰。

  4. 線程安全
    通過緩存的 JavaVM,可在其他線程中安全獲取 JNIEnv

    JNIEnv* env;
    gJavaVM->AttachCurrentThread(&env, nullptr);
    

優勢(動態注冊 vs 靜態注冊)

  • 更高效:避免運行時通過方法名動態查找本地函數。
  • 更靈活:無需遵循 Java_<Package>_<Class>_<Method> 的命名格式。
  • 可控性:可在 JNI_OnLoad 中集中管理所有注冊邏輯。

通過以上實現,可確保本地方法在 JNI 庫加載時正確注冊,提升代碼可維護性和性能。

2.調用JNI_OnLoad

在 Android 開發中,JNI_OnLoad 不是由開發者直接調用的,而是由 Java 虛擬機(JVM)在加載動態庫(.so 文件)時自動觸發的。以下是它的調用機制和觸發方式:


1. JNI_OnLoad 的調用機制

當你在 Java 代碼中加載一個 JNI 動態庫(.so 文件)時,系統會自動檢查該庫是否實現了 JNI_OnLoad 函數。如果存在,JVM 會在庫加載后立即調用它。

觸發 JNI_OnLoad 的方式

// Java 代碼(例如 MainActivity.java)
static {System.loadLibrary("myjni"); // 加載 libmyjni.so
}
  • System.loadLibrary("myjni")
    會嘗試加載 libmyjni.so(在 Android 中會自動添加 lib 前綴和 .so 后綴)。
  • JVM 檢查 JNI_OnLoad
    如果 libmyjni.so 實現了 JNI_OnLoad,JVM 會在加載后立即調用它。

2. JNI_OnLoad 的調用流程

  1. Java 代碼調用 System.loadLibrary("myjni")
  2. Android Runtime(ART/Dalvik)加載 libmyjni.so
  3. JVM 檢查是否實現了 JNI_OnLoad
    • 如果存在,調用 JNI_OnLoad(JavaVM* vm, void* reserved)
    • 如果不存在,JNI 會使用默認的靜態注冊方式(基于 JNIEXPORT 函數名匹配)。
  4. JNI_OnLoad 執行動態注冊
    • 注冊 JNINativeMethod 數組中的本地方法。
    • 返回 JNI 版本(如 JNI_VERSION_1_6)。

3. 如何確保 JNI_OnLoad 被正確調用?

(1)確保 .so 文件正確編譯

CMakeLists.txtAndroid.mk 中正確配置:

# CMakeLists.txt
add_library(myjni SHARED native-lib.cpp)

# Android.mk
LOCAL_MODULE := myjni
LOCAL_SRC_FILES := native-lib.cpp

(2)確保 Java 代碼正確加載庫

// 在靜態代碼塊中加載庫(避免重復加載)
static {System.loadLibrary("myjni");
}

(3)檢查 JNI_OnLoad 是否被調用

可以在 JNI_OnLoad 中添加日志:

#include <android/log.h>
#define LOG_TAG "JNI_DEBUG"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {LOGD("JNI_OnLoad called!"); // 檢查是否執行// ... 其他注冊邏輯return JNI_VERSION_1_6;
}

然后在 logcat 中查看日志:

adb logcat | grep "JNI_DEBUG"

4. 常見問題

(1)JNI_OnLoad 沒有被調用?

  • 庫未正確加載:檢查 System.loadLibrary 是否成功執行(無 UnsatisfiedLinkError)。
  • .so 文件未正確編譯:確保 JNI_OnLoad 被包含在最終 .so 中(可通過 nm -D libmyjni.so | grep JNI_OnLoad 檢查)。
  • JNI 版本不匹配:確保 JNI_OnLoad 返回正確的版本(如 JNI_VERSION_1_6)。

(2)JNI_OnLoad 和靜態注冊的區別?

特性JNI_OnLoad(動態注冊)靜態注冊(默認方式)
注冊方式主動調用 RegisterNatives基于函數名匹配(如 Java_com_example_MyClass_method
性能更快(避免運行時查找)較慢(首次調用需解析)
靈活性可自定義注冊邏輯必須遵循固定命名規則
適用場景推薦用于復雜項目簡單 JNI 調用

5. 總結

  • JNI_OnLoad 由 JVM 自動調用,開發者只需實現它并在其中注冊本地方法。
  • 觸發方式:在 Java 中調用 System.loadLibrary("mylib")
  • 核心作用:動態注冊 JNI 方法,提升性能并增強靈活性。
  • 調試技巧:通過 __android_log_print 打印日志,確保 JNI_OnLoad 被正確執行。

如果你的 JNI_OnLoad 沒有被調用,請檢查庫加載流程和編譯配置!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/77512.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/77512.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/77512.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

算法導論思考題

2-1 在歸并排序中對小數組采用插入排序 c. 假定修改后的算法的最壞情況運行時間為 Θ \Theta Θ(nknlg(n/k))&#xff0c;要使修改后的算法與標準的歸并排序具有相同的運行時間&#xff0c;作為n的一個函數&#xff0c;借助 Θ \Theta Θ記號&#xff0c;k的最大值是什么&#…

JavaScript 性能優化

JavaScript 性能優化是提高 Web 應用性能的關鍵步驟,特別是在處理大量數據、復雜計算或頻繁的 DOM 操作時。以下是一些常見的 JavaScript 性能優化技巧和策略: 文章目錄 @[TOC]一、代碼層面優化1. **減少全局變量**2. **避免使用 `with` 語句**3. **使用局部變量**4. **減少 …

NLP高頻面試題(四十七)——探討Transformer中的注意力機制:MHA、MQA與GQA

MHA、MQA和GQA基本概念與區別 1. 多頭注意力(MHA) 多頭注意力(Multi-Head Attention,MHA)通過多個獨立的注意力頭同時處理信息,每個頭有各自的鍵(Key)、查詢(Query)和值(Value)。這種機制允許模型并行關注不同的子空間上下文信息,捕捉復雜的交互關系。然而,MHA…

51單片機的原理圖和PCB繪制

51單片機最小系統原理圖 加了兩個led燈和按鍵檢測電路。 PCB中原件擺放位置 成品 資源鏈接&#xff1a;https://download.csdn.net/download/qq_61556106/90656365

使用注解方式整合ssm時,啟動tomcat掃描不到resource下面的xxxmapper.xml

解決org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.xxx.mapper.方法 在Spring與Mybatis整合時&#xff0c;可能會遇到這樣的報錯 原因&#xff1a; 其原因為mapper路徑的映射錯誤&#xff0c;表示在嘗試執行某個 Mapper 接口的方法時…

提示詞設計:動態提示詞 標準提示詞

提示詞設計:動態提示詞 標準提示詞 研究背景:隨著人工智能與司法結合的推進以及裁判文書公開數量增多,司法摘要任務愈發重要。傳統司法摘要方法生成質量有待提升,大語言模型雖有優勢,但處理裁判文書時存在摘要結構信息缺失、與原文不一致等問題。研究方法 DPCM方法:分為大…

Jenkins 多分支管道

如果您正在尋找一個基于拉取請求或分支的自動化 Jenkins 持續集成和交付 (CI/CD) 流水線&#xff0c;本指南將幫助您全面了解如何使用 Jenkins 多分支流水線實現它。 Jenkins 的多分支流水線是設計 CI/CD 工作流的最佳方式之一&#xff0c;因為它完全基于 git&#xff08;源代…

跨境電商管理轉型:日事清通過目標管理、流程自動化助力智優美科技項目管理升級與目標落地復盤

1.客戶背景介紹 深圳市智優美科技有限公司是一家專業從事外貿B2C的電子商務公司&#xff0c;公司總部位于深圳市寶安區&#xff0c;旗下擁有三家子公司。目前銷售的品類有&#xff1a;家居用品、電子產品、電子配件產品等&#xff0c;在深圳外貿電商行業銷售額穩居行業前10名。…

基于Docker+k8s集群的web應用部署與監控

項目架構圖 server ip master 192.168.140.130 node1 192.168.140.131 node2 192.168.140.132 ansible 192.168.140.166 jumpserver 192.168.100.133 firewall 192.168.1.86 nfs 192.168.140.157 harbor 192.168.140.159 Promethethus 192.168.140.130 Jen…

量子計算與經典計算融合:開啟計算新時代

一、引言 隨著科技的飛速發展&#xff0c;計算技術正迎來一場前所未有的變革。量子計算作為前沿技術&#xff0c;以其強大的并行計算能力和對復雜問題的高效處理能力&#xff0c;吸引了全球科技界的關注。然而&#xff0c;量子計算并非要完全取代經典計算&#xff0c;而是與經典…

【HarmonyOS 5】makeObserved接口詳解

【HarmonyOS 5】makeObserved接口詳解 一、makeObserved接口是什么&#xff1f; makeObserved 接口&#xff08;API version 12 起可用&#xff09;用于將非觀察數據轉為可觀察數據&#xff0c;適用于三方包類、Sendable 裝飾的類、JSON.parse 返回的對象、collections.Array…

豆瓣圖書數據采集與可視化分析(二)- 豆瓣圖書數據清洗與處理

文章目錄 前言一、查看數據基本信息二、拆分pub列三、日期列處理四、價格列處理五、出版社列處理六、評價人數列處理七、缺失值處理八、重復數據處理九、異常值處理十、完整代碼十一、清洗與處理后的數據集展示 前言 豆瓣作為國內知名的文化社區&#xff0c;擁有龐大且豐富的圖…

Wasm -WebAssembly簡介

WebAssembly 是什么&#xff1f; WebAssembly/wasm WebAssembly 或者 wasm 是一個可移植、體積小、加載快并且兼容 Web 的全新格式 WebAssembly&#xff08;簡稱 Wasm&#xff09;是一種二進制指令格式&#xff0c;設計用于在現代 Web 瀏覽器中高效運行程序。它可以被認為是一…

驅動開發硬核特訓 · Day 15:電源管理核心知識與實戰解析

在嵌入式系統中&#xff0c;電源管理&#xff08;Power Management&#xff09;并不是“可選項”&#xff0c;而是實際部署中影響系統穩定性、功耗、安全性的重要一環。今天我們將以 Linux 電源管理框架 為基礎&#xff0c;從理論結構、內核架構&#xff0c;再到典型驅動實戰&a…

【SpringBoot】99、SpringBoot中整合RabbitMQ實現重試功能

最近在做一個項目,需要使用 MQ 實現重試功能,在這里給各位分享一下。 1、整合 RabbitMQ <!-- rabbitmq消息隊列 --> <dependency><groupId>org.springframework.boot</groupId><

AI 中的 CoT 是什么?一文詳解思維鏈

文章目錄 CoT 的組成CoT 的作用CoT 的推理結構變體CoT 的特點CoT 的適用場景總結 在人工智能領域&#xff0c;尤其是自然語言處理和機器學習中&#xff0c;有一種名為思維鏈&#xff08;Chain of Thought&#xff0c;CoT&#xff09;的技術&#xff0c;它正逐漸改變著我們對 AI…

Vue3集成Element Plus完整指南:從安裝到主題定制上

一、Element Plus簡介 Element Plus是一套基于Vue 3.0的桌面端組件庫&#xff0c;由餓了么前端團隊開源維護。它提供了豐富的UI組件&#xff0c;能夠幫助開發者快速構建企業級中后臺產品。 1. 安裝與卸載 bash 復制 下載 # 安裝最新版本 npm install element-plus -S# 卸…

Java29:Spring MVC

一&#xff1a;Springmvc簡介 1.簡介&#xff1a; Spring Web MVC 是基于Servlet API構建的原始Web框架&#xff0c;從一開始就包含在Spring Framework中。正式名稱“Spring Web MVC” 來自其源模塊名稱&#xff08;spring-webmvc&#xff09;但它通常被稱為“Spring Mvc” …

VLC搭建本機的rtsp直播推流和拉流

媒體---流---捕獲設備&#xff0c;選擇攝像頭&#xff0c;點擊串流 x下一步 選擇rtsp&#xff0c;點擊添加 看到了端口&#xff0c;并設置路徑&#xff1a; 選擇Video -H 264 mp3(TS) 點擊下一個&#xff0c; 點擊流&#xff0c;就開始推流了 拉流&#xff0c;觀看端&#x…

云點數據讀寫

一、常見點云數據格式 LAS/LAZ格式 LAS是點云數據的行業標準格式 LAZ是LAS的壓縮版本 支持地理參考信息、顏色、強度等屬性 PCD格式(Point Cloud Data) PCL(Point Cloud Library)開發的格式 支持ASCII和二進制存儲 包含頭部信息和數據部分 PLY格式(Polygon File Format…