在編寫JNI方法時有兩種方法:一種是标準的通過javah生成頭檔案,然後自己實作對應的cpp檔案,這種辦法也是官方推薦的。還有一種方法是在JNI_OnLoad函數中進行函數映射,将java裡面的方法映射到自己實作的方法。
當Android的DVM(Virtual Machine)執行到C元件裡的System.loadLibrary()函數時,首先會去執行C元件裡的JNI_OnLoad()函數。它的用途有二:
1. 告訴VM此C元件使用那一個JNI版本。
如果你的*.so檔沒有提供JNI_OnLoad()函數,VM會預設該*.so檔是使用最老的JNI 1.1版本。
由于新版的JNI做了許多擴充,如果需要使用JNI的新版功能,
例如JNI 1.4的java.nio.ByteBuffer,就必須藉由JNI_OnLoad()函數來告知VM。
2. 由于VM執行到System.loadLibrary()函數時,就會立即先呼叫JNI_OnLoad(), 是以C元件的開發者可以藉由JNI_OnLoad()來進行C元件内的初期值之設定(Initialization) 。
3. 在so被成功解除安裝時,會回調另一個JNI方法:JNI_UnOnLoad。這兩個方法聲明如下:
其中第一個參數vm表示DVM虛拟機,該vm在應用程序中僅有一個,可以儲存在native的靜态變量中,供其他函數或其他線程使用。其傳回值表示目前需要native library需要的版本。
首先在Java中寫好native方法:
然後編寫對應的native方法
然後在JNI_OnLoad中注冊改函數映射
其中JNINativeMethod的結構如下:
通過以上方法就可以實作方法映射,而不用遵循原有的命名規則。
JNI_OnLoad是加載so時最先調用的方法,而且該方法會把JavaVM* vm指針傳過來,這樣在native就可以儲存該指針,該指針在整個應用程序中僅有一個,可以跨線程使用。我們通過在該方法中注冊函數映射,當然也可以在該方法中做其他操作。比如我們可以在該方法中進行版本校驗,也可以校驗目前調用該so的應用是否合乎要求。