加載靜態庫到android,靜態庫的提供方式有2種, css
a. 經過源文件來編譯靜態庫 html
b. 加載已經編譯好的靜態庫 java
首先咱們來看,經過源文件來編譯靜態庫,工程目錄以下 android
第一步:咱們來看咱們的jni目錄,目錄下包含如下4個文件 windows
Android.mk --- 編譯文件 ide
first.c ,first.h --- 外部須要引用的文件 ui
second.c ---- 咱們的jni轉換文件 this
首先咱們簡單的看下源碼spa
#include "first.h" int first(int x, int y) { return x + y; }
first.c裏面簡單的定義了一個加法的方法,而後申明瞭頭文件
second.c : 把first.c的方法轉換爲jni能夠識別的方法。3d
#include "first.h" #include <jni.h> jint Java_com_example_twolibs_TwoLibs_add( JNIEnv* env, jobject this, jint x, jint y ) { return first(x, y); }
第二步是重點,咱們來分析下mk文件,看編譯文件是怎樣生成first.c對於的靜態文件,並在編譯second.c的時候加載靜態文件
1: LOCAL_PATH:= $(call my-dir)
2:
3: # first lib, which will be built statically
4: #
5: include $(CLEAR_VARS)
6:
7: LOCAL_MODULE := libtwolib-first
8: LOCAL_SRC_FILES := first.c
9:
10: include $(BUILD_STATIC_LIBRARY)
11:
12: # second lib, which will depend on and include the first one
13: #
14: include $(CLEAR_VARS)
15:
16: LOCAL_MODULE := libtwolib-second
17: LOCAL_SRC_FILES := second.c
18:
19: LOCAL_STATIC_LIBRARIES := libtwolib-first
20:
21: include $(BUILD_SHARED_LIBRARY)
如上: 1-10 行是生成靜態文件的方法,
14-21 行是編譯動態文件的方法,經過標識符BUILD_SHARED_LIBRARY 以及 BUILD_STATIC_LIBRARY 來區分是編譯成動態文件仍是靜態,19行標識須要連接靜態庫libtwolib-first
第三步:在java中調用
public class TwoLibs extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); int x = 1000; int y = 42; // here, we dynamically load the library at runtime // before calling the native method. // System.loadLibrary("twolib-second"); int z = add(x, y); tv.setText( "The sum of " + x + " and " + y + " is " + z ); setContentView(tv); } public native int add(int x, int y); }
第二種方法: 用第3方提供的靜態庫來編譯,咱們仍是用前面的jni文件
首先第一步咱們經過gcc來生成靜態庫文件
gcc -c first.c 生成.o文件
ar -cr libtwolib-first.a first.o 來生成libtwolib-first.a庫文件
而後經過 查看,方法多了一個」_」,這個坑爹了,還不知道怎麼處理,網上沒找到方法,這種方法只能先放放了。
那既然第一種不行,那是否是能夠直接用原來的.mk文件來生成了,嘗試了下,修改了mk文件,註釋掉生成動態庫的一部分。
LOCAL_PATH:= $(call my-dir) # first lib, which will be built statically # include $(CLEAR_VARS) LOCAL_MODULE := libtwolib-first LOCAL_SRC_FILES := first.c include $(BUILD_STATIC_LIBRARY) # second lib, which will depend on and include the first one # #include $(CLEAR_VARS) #LOCAL_MODULE := libtwolib-second #LOCAL_SRC_FILES := second.c #LOCAL_STATIC_LIBRARIES := libtwolib-first #include $(BUILD_SHARED_LIBRARY)
而後執行 ndk-build 什麼反應都沒有,通過查找一位大拿解決了,須要修改配置文件
NDK r6 默認不支持靜態庫的 install 操做。能夠將 definitions.mk 腳本里的 D:\cygwin\home\Administrator\android-ndk-r8b\build\core\definitions.mk 1669行 module-class-is-installable = $(if $(NDK_MODULE_CLASS.$1.INSTALLABLE),$(true),$(false)) 修改成: module-class-is-installable = $(if $(NDK_MODULE_CLASS.$1.INSTALLABLE),$(true),$(true)) 這樣強制 NDK 對靜態庫進行 install,便可單獨生成靜態庫
修改完之後,執行ndk-build,果真在/libs/armeabi目錄下找到了庫文件libtwolib-first.a
方法也正常。
而後把.a文件拷貝到jni目錄下,修改mk文件,去掉生成靜態庫部分,編譯報錯,找不到方法
通過查找才知道 「編譯器改爲windows版的了,/cygdrive/開頭的cygwin下的路徑再也不支持,使用windows路徑就能夠了」
因此從新修改mk文件爲以下
/usr/lib/gcc/i686-pc-cygwin/4.5.3/cc1.exe: error while loading shared libraries:
cygppl_c-2.dll: cannot open shared object file: No such file or directory
不用着急,這是由於在安裝時,沒有安裝mpfr(版本4)所至,打開cygwin.exe,輸入mpfr,下載libmpfr4至可
將NDK編譯的第三方靜態拷貝到JNI目錄下,在Android.mk中添加以下代碼
以openssl靜態庫(libcrypto-static.a)爲例
第一種連接方法:LOCAL_LDFLAGS := libcrypto-static.a
第二種連接方法:LOCAL_LDLIBS := libcrypto-static.a
第三種連接方法:
include $(CLEAR_VARS)
LOCAL_MODULE := third_static_lib (能夠隨便起一個名字)
LOCAL_SRC_FILES := libcrypto-static.a
include $(PREBUILT_STATIC_LIBRARY)
//在你要編譯的模塊中引用third_static_lib
LOCAL_STATIC_LIBRARIES := third_static_lib
標籤:
項目編譯成動態庫是正常的,將 Android.mk 裏面的
include $(BUILD_SHARED_LIBRARY)
改爲
include $(BUILD_STATIC_LIBRARY)
編譯靜態庫,
運行 ndk-build 卻一點反應都沒有,一閃而過。
解決方案:
在 工程目錄\jni\ 目錄下添加一個 Application.mk 文件,裏面只寫上以下一行代碼:
APP_MODULES := lib庫名
問題解決。
目錄結構示意圖:
工程目錄
|-jni
| |-*.c/*.h <--多個源文件
| |-Android.mk
| |-Application.mk
|
|-Application.mk
1.工程目錄/jni/Android.mk 文件內容:
# 提供當前文件的路徑,必須定義它在你的 Android.mk 文件的開始處
LOCAL_PATH := $(call my-dir)
# CLEAR_VARS 變量是由生成系統已提供的,
# 而且指出一個特殊的 GNU Makefile 文件爲你清除除了 LOCAL_PATH 之外的許多的 LOCAL_* 變量,
# 這是必須的,由於所有的生成控制文件是在一個單獨的 GNU Make 執行環境中被分析的,
# 在那裏全部的變量是全局的。
include $(CLEAR_VARS)
# 該變量是必須定義的,用來標識你的 Android.mk 文件中描述的每一個模塊,
# 模塊名字必須是惟一的,而且不能包含任何的空格。
LOCAL_MODULE:= 模塊名字
# 該變量是必須包含將要生成且彙編成一個模塊所需的 C / C++ 源文件的列表。
# 注意:不列出頭文件和包含文件在這裏,由於生成系統將自動地爲你估算信賴。
LOCAL_SRC_FILES := 多個源代碼文件(*.c)用空格分隔
# 一個可選的路徑列表,作爲 include 搜索路徑之一。
LOCAL_C_INCLUDES := $(LOCAL_PATH)
#include $(BUILD_SHARED_LIBRARY)
include $(BUILD_STATIC_LIBRARY)
2.工程目錄/jni/Application.mk 文件內容:
# 該變量是可選的,指出你的應用程序工程名
APP_MODULES := lib模塊名字
3.工程目錄/Application.mk 文件內容:
# 該文件是可選的,用來描述你的工程的更多細節,如:支持更多 CPU 以及替代編譯器或連接器標誌。
# 指出你的應用程序工程目錄
APP_PROJECT_PATH := $(call my-dir)
# 默認狀況下,NDK 生成系統將尋找一個名爲 Android.mk 文件在 $(APP_PROJECT_PATH)/jni 目錄下
APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/jni/Android.mk
注:工程目錄/jni/Application.mk 文件內容,
在編譯動態庫時,能夠合併到 工程目錄/Application.mk 文件內容 中。