androidso庫生成
A. 請教關於android linux動態庫.so的載入調用
1、 .so動態庫的生成
可使用gcc或者g++編譯器生成動態庫文件(此處以g++編譯器為例)
g++ -shared -fPIC -c XXX.cpp
g++ -shared -fPIC -o XXX.so XXX.o
2、 .so動態庫的動態調用介面函數說明
動態庫的調用關系可以在需要調用動態庫的程序編譯時,通過g++的-L和-l命令來指定。例如:程序test啟動時需要載入目錄/root/src/lib中的libtest_so1.so動態庫,編譯命令可照如下編寫執行:
g++ -g -o test test.cpp –L/root/src/lib –ltest_so1
(此處,我們重點講解動態庫的動態調用的方法,關於靜態的通過g++編譯命令調用的方式不作詳細講解,具體相關內容可上網查詢)
Linux下,提供專門的一組API用於完成打開動態庫,查找符號,處理出錯,關閉動態庫等功能。
下面對這些介面函數逐一介紹(調用這些介面時,需引用頭文件#include <dlfcn.h>):
1) dlopen
函數原型:void *dlopen(const char *libname,int flag);
功能描述:dlopen必須在dlerror,dlsym和dlclose之前調用,表示要將庫裝載到內存,准備使用。如果要裝載的庫依賴於其它庫,必須首先裝載依賴庫。如果dlopen操作失敗,返回NULL值;如果庫已經被裝載過,則dlopen會返回同樣的句柄。
參數中的libname一般是庫的全路徑,這樣dlopen會直接裝載該文件;如果只是指定了庫名稱,在dlopen會按照下面的機制去搜尋:
a.根據環境變數LD_LIBRARY_PATH查找
b.根據/etc/ld.so.cache查找
c.查找依次在/lib和/usr/lib目錄查找。
flag參數表示處理未定義函數的方式,可以使用RTLD_LAZY或RTLD_NOW。RTLD_LAZY表示暫時不去處理未定義函數,先把庫裝載到內存,等用到沒定義的函數再說;RTLD_NOW表示馬上檢查是否存在未定義的函數,若存在,則dlopen以失敗告終。
2) dlerror
函數原型:char *dlerror(void);
功能描述:dlerror可以獲得最近一次dlopen,dlsym或dlclose操作的錯誤信息,返回NULL表示無錯誤。dlerror在返回錯誤信息的同時,也會清除錯誤信息。
3) dlsym
函數原型:void *dlsym(void *handle,const char *symbol);
功能描述:在dlopen之後,庫被裝載到內存。dlsym可以獲得指定函數(symbol)在內存中的位置(指針)。如果找不到指定函數,則dlsym會返回NULL值。但判斷函數是否存在最好的方法是使用dlerror函數,
4) dlclose
函數原型:int dlclose(void *);
功能描述:將已經裝載的庫句柄減一,如果句柄減至零,則該庫會被卸載。如果存在析構函數,則在dlclose之後,析構函數會被調用。
3、 普通函數的調用
此處以源碼實例說明。各源碼文件關系如下:
test_so1.h和test_so1.cpp生成test_so1.so動態庫。
test_so2.h和test_so2.cpp生成test_so2.so動態庫。
test_dl.cpp生成test_dl可執行程序,test_dl通過dlopen系列等API函數,並使用函數指針以到達動態調用不同so庫中test函數的目的。
B. Android怎麼調用第三方SO動態鏈接庫
對於Android調用第三方SO動態鏈接庫,我們可以從兩個主要的方案來考慮。第一個方案是直接將SO文件放置於libs/armeabi目錄下,然後在代碼中通過System.loadLibrary("xxx")來載入,緊接著定義public native static int xxx_xxx_xxx()方法,這樣就可以直接調用xxx_xxx_xxx()方法了。
第二種方案則更為復雜,它涉及到自己創建SO文件,這個SO文件會調用第三方的SO。為了實現這一點,需要創建一個Java類文件,生成對應的.h文件,編寫C源文件並包含生成的.h文件,實現相應的方法,最後使用Android NDK開發包中的ndk-build腳本生成對應的.so共享庫。
關於網上討論的第二種方案,即自己引用so庫的說法,我們需要考慮幾個因素。首先,這個SO是否符合JNI調用規范,例如是否直接支持特定類型。如果不符合,我們只能選擇第二種方案。如果符合,那麼是否希望這個SO直接暴露給JAVA層也是需要考慮的因素。如果不想,同樣只能選擇第二種方案。
通常情況下,當你只有SO文件,這表明這是一個由他人提供的庫,你可以要求對方提供配套的JAVA調用文件。因此,在實際操作中,我們首先需要檢查SO文件是否符合JNI調用規范,以及根據自身的需求決定是否需要直接暴露給JAVA層。
第二種方案之所以更為靈活,是因為它可以應對各種情況,尤其是當直接調用第三方SO文件存在困難時。而如果SO文件符合JNI規范,且你願意將其直接暴露給JAVA層,那麼直接調用的方法將更為簡便。
在嘗試從JAVA調用時,最簡單的判斷方法是查看SO里的函數名是否遵循Java_XXX_XXX_XXX的格式。如果符合,你可以自己編寫配套的JAVA文件,注意函數名的轉換規則,或者向SO提供方索要。如果不符,則需要採取第二種方案。
總的來說,選擇哪種方案取決於你的具體需求和第三方SO文件的具體情況。在實際應用中,合理選擇方案能夠有效提升開發效率。
C. FFmpeg生成Android so庫
為了生成適用於Android的.so庫,本文詳細記錄了從環境准備到成功編譯的整個過程。以FFmpeg 4.2.2版本和NDK 21.1.6352462為實例,解釋了不同編譯環境下的操作細節,為開發者提供了一套可行的解決方案。以下是編譯過程的概述:
編譯環境:
- FFmpeg版本:4.2.2
- 操作系統:Mac
- NDK版本:21.1.6352462
- 手機型號:QIOO855
手機硬體架構:
- 架構:arm64
- CPU類型:armv8-a
- TOOL_CPU_NAME:aarch64
編譯工具鏈:
- NDK工具鏈目錄:/Users/xxx/Library/Android/sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/darwin-x86_64/bin
- 單獨的交叉編譯環境目錄:/Users/xxx/Library/Android/sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/darwin-x86_64/sysroot
在編譯過程中,使用CLANG代替了GCC,這是因為Google在NDK17版本之後,全面推行使用CLANG。對於Mac操作系統,需確保正確安裝NDK和FFmpeg,通過adb命令查看手機硬體信息以確定架構和CPU類型,以確保編譯出的.so庫與手機兼容。
編譯步驟概覽如下:
- **下載**:從ffmpeg.org和dl.google.com下載FFmpeg和NDK。
- **環境配置**:在Mac上,確保正確設置NDK路徑和輸出文件路徑,以便在指定目錄下生成.so庫。
- **腳本編寫與執行**:使用自定義的shell腳本(如build_android_clang.sh)來執行編譯過程,這一步驟中需要根據個人環境調整NDK和輸出路徑的環境變數。
- **腳本調用**:運行編譯腳本,生成適用於Android的.so庫文件。
在Linux環境下,操作流程與Mac類似,但配置細節有所差異。例如,需要在/etc/profile中設置環境變數,使用不同的編譯腳本來執行編譯任務,並通過./android_build.sh命令啟動編譯過程。Linux環境下的編譯通常速度較快,幾分鍾內即可完成編譯生成.so庫。
總結:通過遵循上述指導,開發者可以成功地在Mac或Linux操作系統中生成適用於Android的.so庫,解決FFmpeg與最新版本NDK不兼容的問題。此過程對於集成FFmpeg庫到Android應用中至關重要,確保了編譯出的庫與目標設備的硬體架構兼容,從而實現高效的音視頻處理能力。
D. Android怎麼調用第三方SO動態鏈接庫
在Android開發中,調用第三方SO動態鏈接庫有多種策略。一種簡便的方式是將SO文件放置於libs/armeabi目錄下,然後在代碼中使用System.loadLibrary("xxx")載入,並通過public native static int xxx_xxx_xxx()聲明方法,從而直接調用。
另一種方案較為復雜,涉及創建自己的SO文件,並在其中調用第三方SO。這種方法需要編寫Java類文件、生成.h文件、編寫C源文件並實現相應方法,最後利用android NDK開發包中的ndk-build腳本生成.so共享庫。盡管此過程較為繁瑣,但靈活性較高,能夠應對各種情況。
首先,需要檢查第三方SO是否遵循JNI調用規范。如果不符合,必須選擇第二種方案。即使符合,還需考慮是否希望將SO庫直接暴露給JAVA層。如果否,同樣應採用第二種方案。通常情況下,如果只有SO文件,意味著它是第三方提供的,可以請求對方提供配套的JAVA調用文件。
判斷SO是否遵循JNI規范的一個簡單方法是檢查其函數名是否為Java_XXX_XXX_XXX格式。如果是,可以自行編寫配套的JAVA文件,注意SO函數名與JAVA函數名之間的轉換規則。如果不是,建議採用第二種方案。
總體而言,選擇調用方式時需綜合考慮實際需求和第三方庫的具體情況,以確保代碼的簡潔性和功能的完整性。