1. 程式人生 > >JNI 如何使用dlopen,dlsym呼叫第三方自定義的 .so庫( JNI->C,C++)

JNI 如何使用dlopen,dlsym呼叫第三方自定義的 .so庫( JNI->C,C++)

和前一篇 JNI->JNI唯一不同的就是 編譯出.so 需要在Linux 上,然而直接用linux gcc 編譯出的.so 是不能被NDK編譯的會出 incompatible target 的錯誤所以需要用到交叉環境 即是 linux下的 ndk編譯環境

我用的是 virtual box 裝的 ubuntu 64虛擬機器

第一步:製作第一個linux下的動態庫來模擬第三方動態庫

首先你的linux環境必須裝有linux版本的NDK,現在我們來從NDK中分離出獨立的工具鏈,這樣我們在製作第三方動態庫的時候就不用寫makefile了。

在linux命令終端解壓壓縮包得android-ndk-xx然後再linux終端進入android-ndk-xx的根目錄,$ build/tools/make-standalone-toolchain.sh --platform=<PLATFORM> --install-dir=<INSTALL_PATH>按上述格式輸入下面的命令

$ build/tools/make-standalone-toolchain.sh --platform=android-14 --install-dir=/home/xx/toolchain/arm-linux-androideabi/

這條命令的意思就是將交叉編譯工具完整複製出來,android-14是你的API ,-dir後面是你要複製安裝到的目錄,執行完後你會發現在/home/xxx/下發現你新建的toolchain目錄,到這裡我們已經從NDK中分離出獨立的工具鏈了。最後為了方便我們需要設定一下環境變數,如果不設定,每次你都要這樣寫/home/xx/toolchain/arm-linux-androideabi/bin/arm-linux-androideabi-gcc -c Add.c 這樣相當麻煩。

在Linux終端輸入 $ sudo -s 獲取超級許可權,再輸$gedit /etc/profile 在彈出的profile檔案裡將以下內容:export PATH=$PATH:/home/laijingquan/toolchain/arm-linux-androideabi/bin 加到檔案的最後一行(這句什麼意思?大神可以略去本人下面的贅述。簡單說就是設定這個環境變數後,你後面執行arm-linux-androideabi-gcc這個命令時就會自動在:/home/laijingquan/toolchain/arm-linux-androideabi/bin這個目錄裡去尋找。)接著再執行 $ source /etc/profile 讓環境變數立即生效。

arm-linux-androideabi-gcc -c xxxx.cpp 生成.o的檔案

arm-linux-androideabi-gcc -shared -fPCI -o libxxxx.so xxxx.o  生成動態連結庫.so檔案

第二部:

         將生成的.so 檔案 拷貝到 工程目錄 jni下,在jni下新建 include資料夾將.h檔案拷貝進去。

在 原始的C 語言.h檔案裡面加上3行程式碼:

第一行加 include<jni.h>  
在所有include 最下邊加上 extern "C" { 
 就是包含你所有的介面名,將介面名最前面加上JNIEXPORT,中間加上 JNICALL ,就變成了這個摸樣就行了:
 JNIEXPORT void JNICALL neuglClearColor(float r, float g, float b, float alpha);
}

還需要在 載入本地JNI庫的地方載入下:

public class NativeInterface {
	
	public native static int init_view();
	public native static int draw_view();
	public native static void neuglClearColor(float r,float g,float b,float alpha);
	static{
		System.out.println("java start load MyTestLib.so....");
		System.loadLibrary("MyTestLib");
		System.out.println(System.mapLibraryName("MyTestLib"));
		System.out.println("java loaded MyTestLib.so");
		
		System.out.println("java start load Jtestc.so....");
		System.loadLibrary("Jtestc");         
		System.out.println("java loaded Jtestc.so");
	}
}


最後貼上 .mk檔案程式碼:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE    := MyTestLib
LOCAL_SRC_FILES := eslib/libMyTestLib.so
LOCAL_C_INCLUDES := eslib/include
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := Jtestc
LOCAL_SRC_FILES := Jtestc.cpp
LOCAL_LDLIBS := -lGLESv2
LOCAL_LDLIBS += -llog -lz -lm
LOCAL_SHARED_LIBRARIES := MyTestLib
include $(BUILD_SHARED_LIBRARY)