⑴ androidStudio如何配置NDK/JNIAndroidStudio怎麼調用so動態鏈接庫
AndroidStudio怎麼調用so動態鏈接庫?在我們日常開發中,經常會用到一些復雜的加密的演算法以保證通信的安全。通常這些演算法會用C或C++實現後打包成.so動態鏈接庫並向java層開發介面方便調用。
以AndroidStudio為例
1 . 首先去下載NDK包,下載路徑如下可根據自己系統定點下載
https://developer.android.google.cn/ndk/downloads/index.html
static{
System.loadLibrary("jnitext");
}
publicnativeStringget_1111CLang_1String();
⑵ Android studio如何通過jni調用openssl生成的.so動態鏈接庫
(1)老版本,方法如下:
task NativeLibs(type: Copy) {
from(new File(project(':MyProject').buildDir, 'native-libs')) { include '**/*.so' }
into new File(buildDir, 'native-libs')
}
tasks.withType(Compile) { compileTask -> compileTask.dependsOn NativeLibs }
clean.dependsOn 'cleanCopyNativeLibs'
tasks.withType(com.android.build.gradle.PackageApplicationTask) { pkgTask ->
pkgTask.jniDir new File(buildDir, 'native-libs')
}
(2)新版本三種方法:
(2.1)打包前先生成.Jar文件後自動解包到apk文件
task nativeLibsToJar(type: Zip, description: 'create a jar archive of the native libs') {
destinationDir file("$buildDir/native-libs")
baseName 'native-libs'
extension 'jar'
from fileTree(dir: 'libs', include: '**/*.so')
into 'lib/'
}
tasks.withType(Compile) {
compileTask -> compileTask.dependsOn(nativeLibsToJar)
}
下面一句話就是打包生成目錄(build\native-libs)中的.jar文件
compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar')
(2.2)手動生成.Jar文件後自動解包到apk文件
這個方式需要自己手動進行.SO文件壓縮,具體步驟為:將所有需要使用的.so文件壓縮為.zip文件(zip中的文件目錄結構為: lib/armeabi/*.so)然後把zip文件後綴改為.Jar然後放到libs生成apk就ok
默認就是自動打包所有.Jar文件:
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
}
(2.3)這也就是現在正在使用的方式(推薦) ,其實無非就是把.SO文件打包到APK的lib文件夾中,假如仔細閱讀了Gradle的使用方法,自然就知道其實Gradle官方在新版已經自動實現了打包.SO文件的.很簡單級就是在配置的android節點下加入下面的內容就ok:
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
其他地方無需修改,整個項目的配置文件如下:
apply plugin: 'android'
android {
compileSdkVersion 19
buildToolsVersion "19.0.0"
defaultConfig {
minSdkVersion 16
targetSdkVersion 19
versionCode 1
versionName "1.0"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
⑶ 如何在Android下使用JNI
1.引言
我們知道,Android系統的底層庫由c/c++編寫,上層Android應用程序通過Java虛擬機調用底層介面,銜接底層c/c++庫與Java應用程序間的介面正是JNI(JavaNative Interface)。本文描述了如何在ubuntu下配置AndroidJNI的開發環境,以及如何編寫一個簡單的c函數庫和JNI介面,並通過編寫Java程序調用這些介面,最終運行在模擬器上的過程。
2.環境配置
2.1.安裝jdk1.6
(1)從jdk官方網站下載jdk-6u29-linux-i586.bin文件。
(2)執行jdk安裝文件
[html] view plainprint?
01.$chmod a+x jdk-6u29-linux-i586.bin
02.$jdk-6u29-linux-i586.bin
$chmod a+x jdk-6u29-linux-i586.bin
$jdk-6u29-linux-i586.bin
(3)配置jdk環境變數
[html] view plainprint?
01.$sudo vim /etc/profile
02.#JAVAEVIRENMENT
03.exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29
04.exportJRE_HOME=$JAVA_HOME/jre
05.exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
06.exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
$sudo vim /etc/profile
#JAVAEVIRENMENT
exportJAVA_HOME=/usr/lib/java/jdk1.6.0_29
exportJRE_HOME=$JAVA_HOME/jre
exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
保存後退出編輯,並重啟系統。
(4)驗證安裝
[html] view plainprint?
01.$java -version
02.javaversion "1.6.0_29"
03.Java(TM)SE Runtime Environment (build 1.6.0_29-b11)
04.JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode)
05.$javah
06.用法:javah[選項]<類>
07.其中[選項]包括:
08.-help輸出此幫助消息並退出
09.-classpath<路徑>用於裝入類的路徑
10.-bootclasspath<路徑>用於裝入引導類的路徑
11.-d<目錄>輸出目錄
12.-o<文件>輸出文件(只能使用-d或-o中的一個)
13.-jni生成JNI樣式的頭文件(默認)
14.-version輸出版本信息
15.-verbose啟用詳細輸出
16.-force始終寫入輸出文件
17.使用全限定名稱指定<類>(例
18.如,java.lang.Object)。
$java -version
javaversion "1.6.0_29"
Java(TM)SE Runtime Environment (build 1.6.0_29-b11)
JavaHotSpot(TM) Server VM (build 20.4-b02, mixed mode)
$javah
用法:javah[選項]<類>
其中[選項]包括:
-help輸出此幫助消息並退出
-classpath<路徑>用於裝入類的路徑
-bootclasspath<路徑>用於裝入引導類的路徑
-d<目錄>輸出目錄
-o<文件>輸出文件(只能使用-d或-o中的一個)
-jni生成JNI樣式的頭文件(默認)
-version輸出版本信息
-verbose啟用詳細輸出
-force始終寫入輸出文件
使用全限定名稱指定<類>(例
如,java.lang.Object)。2.2.安裝android應用程序開發環境
ubuntu下安裝android應用程序開發環境與windows類似,依次安裝好以下軟體即可:
(1)Eclipse
(2)ADT
(3)AndroidSDK
與windows下安裝唯一不同的一點是,下載這些軟體的時候要下載Linux版本的安裝包。
安裝好以上android應用程序的開發環境後,還可以選擇是否需要配置emulator和adb工具的環境變數,以方便在進行JNI開發的時候使用。配置步驟如下:
把emulator所在目錄android-sdk-linux/tools以及adb所在目錄android-sdk-linux/platform-tools添加到環境變數中,android-sdk-linux指androidsdk安裝包android-sdk_rxx-linux的解壓目錄。
[plain] view plainprint?
01.$sudo vim /etc/profile
02.exportPATH=~/software/android/android-sdk-linux/tools:$PATH
03. exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH
$sudo vim /etc/profile
exportPATH=~/software/android/android-sdk-linux/tools:$PATH
exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH
編輯完畢後退出,並重啟生效。
2.3.安裝NDK
NDK是由android提供的編譯android本地代碼的一個工具。
(1)從androidndk官網http://developer.android.com/sdk/ndk/index.html下載ndk,目前最新版本為android-ndk-r6b-linux-x86.tar.bz2.
(2)解壓ndk到工作目錄:
[plain] view plainprint?
01.$tar -xvf android-ndk-r6b-linux-x86.tar.bz2
02.$sudo mv android-ndk-r6b /usr/local/ndk
$tar -xvf android-ndk-r6b-linux-x86.tar.bz2
$sudo mv android-ndk-r6b /usr/local/ndk
(3)設置ndk環境變數
[plain] view plainprint?
01.$sudo vim /etc/profile
02.exportPATH=/usr/local/ndk:$PATH
$sudo vim /etc/profile
exportPATH=/usr/local/ndk:$PATH
編輯完畢後保存退出,並重啟生效
(4)驗證安裝
[plain] view plainprint?
01.$ cd/usr/local/ndk/samples/hello-jni/
02.$ ndk-build
03.Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
04.Gdbsetup : libs/armeabi/gdb.setup
05.Install : libhello-jni.so => libs/armeabi/libhello-jni.so
$ cd/usr/local/ndk/samples/hello-jni/
$ ndk-build
Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
Gdbsetup : libs/armeabi/gdb.setup
Install : libhello-jni.so => libs/armeabi/libhello-jni.so
3.JNI實現
我們需要定義一個符合JNI介面規范的c/c++介面,這個介面不用太復雜,例如輸出一個字元串。接下來,則需要把c/c++介面的代碼文件編譯成共享庫(動態庫).so文件,並放到模擬器的相關目錄下。最後,啟動Java應用程序,就可以看到最終效果了。
3.1.編寫Java應用程序代碼
(1)啟動Eclipse,新建android工程
Project:JNITest
Package:org.tonny.jni
Activity:JNITest
(2)編輯資源文件
編輯res/values/strings.xml文件如下:編輯res/layout/main.xml文件
我們在主界面上添加了一個EditText控制項和一個Button控制項。
(3)編輯JNITest.java文件
static表示在系統第一次載入類的時候,先執行這一段代碼,在這里表示載入動態庫libJNITest.so文件。
再看這一段:
[java] view plainprint?
01.privatenativeString GetReply();
privatenativeString GetReply();
native表示這個方法由本地代碼定義,需要通過jni介面調用本地c/c++代碼。
[java] view plainprint?
01.publicvoidonClick(View arg0) {
02.edtName.setText(reply);
03.}
publicvoidonClick(View arg0) {
edtName.setText(reply);
}
這段代碼表示點擊按鈕後,把native方法的返回的字元串顯示到EditText控制項。
(4)編譯工程,生成.class文件。
3.2.用javah工具生成符合JNI規范的c語言頭文件
在終端中,進入android工程所在的bin目錄
[plain] view plainprint?
01.$cd ~/project/Android/JNITest/bin
$cd ~/project/Android/JNITest/bin
我們用ls命令查看,可以看到bin目錄下有個classes目錄,其目錄結構為classes/org/tonny/jni,即classes的子目錄結構是android工程的包名org.tonny.jni。請注意,下面我們准備執行javah命令的時候,必須進入到org/tonny/jni的上級目錄,即classes目錄,否則javah會提示找不到相關的java類。
下面繼續:
[plain] view plainprint?
01.$cd classes
02.$javah org.tonny.jni.JNITest
03.$ls
04.org org_tonny_jni_JNITest.h
$cd classes
$javah org.tonny.jni.JNITest
$ls
org org_tonny_jni_JNITest.h
執行javahorg.tonny.jni.JNITest命令,在classes目錄下會生成org_tonny_jni_JNITest.h頭文件。如果不進入到classes目錄下的話,也可以這樣:
[plain] view plainprint?
01.$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest
$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest
-classpath 參數表示裝載類的目錄。
3.3.編寫c/c++代碼
生成org_tonny_jni_JNITest.h頭文件後,我們就可以編寫相應的函數代碼了。下面在android工程目錄下新建jni目錄,即~/project/Android/JNITest/jni,把org_tonny_jni_JNITest.h頭文件拷貝到jni目錄下,並在jni目錄下新建org_tonny_jni_JNITest.c文件,編輯代碼如下:
[cpp] view plainprint?
01.#include<jni.h>
02.#include<string.h>
03.#include"org_tonny_jni_JNITest.h"
04.
05.
06.JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply
07.(JNIEnv *env, jobject obj){
08.return(*env)->NewStringUTF(env,(char*)"Hello,JNITest");
09.}
#include<jni.h>
#include<string.h>
#include"org_tonny_jni_JNITest.h"
JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply
(JNIEnv *env, jobject obj){
return(*env)->NewStringUTF(env,(char*)"Hello,JNITest");
}
我們可以看到,該函數的實現相當簡單,返回一個字元串為:"Hello,JNITest"
3.4.編寫Android.mk文件
在~/project/Android/JNITest/jni目錄下新建Android.mk文件,android可以根據這個文件的編譯參數編譯模塊。編輯Android.mk文件如下:
[plain] view plainprint?
01.LOCAL_PATH:= $(call my-dir)
02.include$(CLEAR_VARS)
03.LOCAL_MODULE := libJNITest
04.LOCAL_SRC_FILES:= org_tonny_jni_JNITest.c
05.include$(BUILD_SHARED_LIBRARY)
LOCAL_PATH:= $(call my-dir)
include$(CLEAR_VARS)
LOCAL_MODULE := libJNITest
LOCAL_SRC_FILES:= org_tonny_jni_JNITest.c
include$(BUILD_SHARED_LIBRARY)
LOCAL_MODULE表示編譯的動態庫名稱
LOCAL_SRC_FILES 表示源代碼文件
3.5.用ndk工具編譯並生成.so文件
進入到JNITest的工程目錄,執行ndk-build命令即可生成libJNITest.so文件。
[plain] view plainprint?
01.$cd ~/project/Android/JNITest/
02.$ndk-build
03.Invalidattribute name:
04.package
05.Install : libJNITest.so => libs/armeabi/libJNITest.so
$cd ~/project/Android/JNITest/
$ndk-build
Invalidattribute name:
package
Install : libJNITest.so => libs/armeabi/libJNITest.so
可以看到,在工程目錄的libs/armeabi目錄下生成了libJNITest.so文件。
3.6.在模擬器上運行
(1)首先,我們把android模擬器啟動起來。進入到emulator所在目錄,執行emulator命令:
[plain] view plainprint?
01.$cd ~/software/android/android-sdk-linux/tools
02.$./emulator @AVD-2.3.3-V10 -partition-size 512
$cd ~/software/android/android-sdk-linux/tools
$./emulator @AVD-2.3.3-V10 -partition-size 512
AVD-2.3.3-V10表示你的模擬器名稱,與在Eclipse->AVDManager下的AVDName對應,-partition-size表示模擬器的存儲設備容量。
(2)接下來,我們需要把libJNITest.so文件拷貝到模擬器的/system/lib目錄下,執行以下命令:
[plain] view plainprint?
01.$cd ~/project/Android/JNITest/libs/armeabi/
02.$adb remount
03.$adb push libJNITest.so /system/lib
04.80 KB/s (10084 bytes in 0.121s)
$cd ~/project/Android/JNITest/libs/armeabi/
$adb remount
$adb push libJNITest.so /system/lib
80 KB/s (10084 bytes in 0.121s)
當在終端上看到有80 KB/s (10084 bytes in 0.121s)傳輸速度等信息的時候,說明拷貝成功。
(3)在終端上執行JNITest程序,這個我們可以在Eclipse下,右鍵點擊JNITest工程,RunAs->Android Application,即可在模擬器上啟動程序
⑷ 如何從零開始創建Android NDK應用
本文主內容:
1、 Android NDK 安裝
2、 安裝Cygwin與使用NDK編譯
3、 在Eclipse中集成C/C++開發環境CDT
4、 安裝Sequoyah插件
5、 JNI編譯環境配置
本文建立在已經完成Android開發環境搭建的基礎上。其基礎環境至少需要包含以下內容:
1、 JDK
2、 Eclipse
3、 Android SDK and ADT
可以參考我之前的「Android開發環境搭建」。
一、Android NDK 安裝與配置
下載Android NDK。下載地址:http://developer.android.com/tools/sdk/ndk/index.html
下載後解壓縮到你的工作目錄,例如:D:\Java\android-ndk-r8,結果如下圖:
注意:samples下麵包含幾個實例開發演示項目,第一次接觸NDK開發,建議先從示例開始。
docs內是技術文檔,英語能力強的可以研究研究。
二、安裝Cygwin與使用NDK編譯
由於NDK開發大都涉及到C/C++在GCC環境下編譯、運行,所以在Windows環境下,需要用Cygwin模擬Linux編譯環境。
下載:
Cygwin的下載地址:http://www.cygwin.com/
點擊右上角的「setup.exe」即可下載。
安裝:
第一步:運行setup.exe程序,直接點擊Next進入下一步。
第二步:選擇安裝方式。第一次可以採用Direct Connection在線下載安裝,如有現成的離線包,可以選擇離線安裝(Install from Local Directory)。
第三步:選擇安裝目錄。比如D:\Java\Cygwin,注意此目錄是指Cygwin最終的安裝目錄,不是下載文件螞皮數暫存目錄。
第四步:設置本地包暫存路徑。暫存目錄默認是放到setup.exe的同級目錄下,建議放到指定的文件夾,如D:\Cygwin_install_file。安裝完成後把這個文件夾打包備份,以後再配置時不用重新下載。
第五步:設置網路連接方式。這個目前河蟹沒爬過來,選第一個即可。
第六步:選悶首擇下載站點地址。據說國內163站點的速度不錯,我也是用的這個。
第七步:等待載入安裝項載入,選擇安裝項。點擊Devel-Default,使之變成Devel-Install,展開後可以看到其下的子項被選中了(網上多數教程都說選中某12個包,找起來太坑爹了,直接全下載了吧,全選多了150M左右)。此界面其他設置都不用動。
第八步:等待下載完成。下載完成時間決定於你選擇的安裝包數量及網路連接速度,安裝我安裝的版本,約983M,下載完成後會自動握亂安裝到上文設置的安裝目錄,安裝也要時間的,總時間較長,去吃個飯沒啥問題。
提醒:第四步的備份建議,盡量去做。如果有備份,第二步中選擇離線安裝。
驗證:
運行安裝目錄下的「Cygwin.bat」,第一次運行時,它會自動創建用戶信息,用戶信息存放在「.\Cygwin\home」中。
在運行「Cygwin.bat」打開的命令行窗口輸入:「cygcheck -c cygwin」命令,會列印出當前Cygwin的版本和運行狀態,如果status是ok的話,則cygwin運行正常。
分別輸入:「make –v」和,「gcc –v」命令如果檢測成功,會有make和gcc相關版本信息列印出來。
設置NDK路徑:
在windows的系統環境變數中添加NDK的路徑。使用「/cygdrive/d/Java/android-ndk-r8」這種Linux風格路徑,如果使用Windows下的「D:\Java\android-ndk-r8」,Cygwin在編譯時會發出警告。
運行Cygwin命令行,可以直接使用此環境變數,當然也可以手動的cd到該目錄:
使用NDK編譯程序:
現在我們用安裝好的NDK來編譯一個NDK提供的sample程序hello-jni(我的目錄位於:D:\Java\android-ndk-r8\samples\hello-jni)。
第一步:運行Cygwin,配置環境變數後可輸入「cd $ndk/samples/hello-jni/」,未配置則輸入命令「cd /cygdrive/d/java/android-ndk-r8/samples/hello-jni」,進入到「hello-jni」工程目錄。
第二步:編譯。輸入命令「$ndk/ndk-build」命令即可編譯。ndk-build是調用ndk的編譯程序。
關於下面的錯誤,我沒遇到,但是前人有總結,記錄如下:
錯誤:Android NDK: Host 'awk' tool is outdated。
解決方法:打開目錄「D:\Java\android-ndk-r8\prebuilt\windows\bin\」,刪除awk.exe(為保險起見請先備份)。
第三步:到」…/hello-jni/libs/armeabi「目錄下看有沒有生成的.so文件,如果有,你的ndk就運行正常啦!
導入NDK的hello-jni示例到Eclipse中:
第一步:在Eclipse中新建一個Android工程HelloJni。在Create Android Project時勾選「Create project from existing source」,Location中填「D:\Java\android-ndk-r8\samples\hello-jni」 (注意:在選擇API level時需要選擇1.5或更高的版本)。
第二步:直接以Android Aplication運行。這里要注意,你之前在使用NDK編譯程序時要把這個hello-jni編譯過並產生了.so文件,此處才能運行起來。
三、在Eclipse中集成C/C++開發環境CDT
CDT的安裝可以使我們在一個工程中,同時開發基於C/C++的Native代碼和基於Java語言的殼,之後的配置還可以使得一次編譯兩部分代碼。
下載:
下載地址:http://www.eclipse.org/cdt/downloads.php
說明:
Eclipse C/C++ IDE Indigo SR2:是帶CDT的Eclipse開發環境。
p2 software repository:在線安裝的地址。(似乎被河蟹爬了)
cdt-master-8.0.2.zip:這個是CDT的離線安裝包。(推薦使用這個,保留離線包,復用)
離線安裝:
Eclipse -> Help -> Install New Software,點擊add。Name:隨意,建議使用好記的「CDT_版本」。Location:點擊Archive,定位到下載的「cdt-master-8.0.2.zip」文件。
錯誤:
如果Location的下面出現「Duplicate location」錯誤,請到Window -> preferences -> Install/Update -> Avaliable Software Site中找到該條,remove之。
驗證:
安裝完成後,在Eclispe中新建一個項目,如果出現了C/C++項目,則表明CDT插件安裝成功了。
四、安裝Sequoyah插件
Sequoyah插件用於設置Android工程對Native開發的支持。
官方網址:http://www.eclipse.org/sequoyah/downloads/
在線安裝:
官網提供了用於在線安裝的Update Site地址以及安裝包的下載地址。貌似安裝包才1M多,在線安裝也沒被河蟹爬過,直接在線安裝了。勾選全部列出的可安裝項並完成安裝。
Location:http://download.eclipse.org/sequoyah/updates/2.0/
注意:
在安裝界面不要勾選「Group items by category」復選框,默認是勾選的,出現了列表為空(There are no categorized items)的情況。
配置:
安裝完Sequoyah插件後,為Android配置NDK路徑。
在「window –> preferences ->Android -> 本機開發」中添加NDK的路徑。
驗證:
右鍵之前建立的「HelloJni」項目,在「Android Tools」選項中包含「Add Native Support…」選項即成功。
五、JNI編譯環境配置
仍舊以之前建立的「HelloJni」為例,到目前為止,如果我們修改「/HelloJni/jni/hello-jni.c」文件,動態鏈接庫libhello-jni.so文件卻不會被重新編譯生成。這是因為我們沒有給JNI項目添加它需要的編譯配置和依賴庫。現在我們來配置它。
第一步:轉換工程。點擊「文件 -> 新建 -> 其他」(快捷鍵:Ctrl+N)。選擇「C/C++」下的「Convert to a C/C++ Project(Adds C/C++ Nature)」。進入「下一步」。
第二步:選中你剛才建的「HelloJni」工程,下面左邊選「Makefile project」右邊選「Cygwin GCC」。確定後提示的「透視圖」不清楚是什麼,點擊「是」即可。
第三步:在「HelloJni」工程上右鍵,選擇「屬性」。配置「C/C++ Build」和「C/C++ General -> Paths and Symbols」。
C/C++ Build:點擊「C/C++ Build」,在右邊的「Builder Settings」中去掉默認勾選的「Use default build command」復選框。設置Build command為「bash D:\Java\android-ndk-r8\ndk-build」。
C/C++ General -> Paths and Symbols:在Includes下add新的GNU C依賴路徑。此「HelloJni」工程需要「D:\Java\android-ndk-r8\platforms\android-8\arch-arm\usr\include」即可,以後根據不同項目選擇不同的依賴庫。
驗證:
將「/HelloJni/jni/hello-jni.c」中的字元串「Hello from JNI !」如改為「Hello JNI from Baron!」,運行後在模擬器上輸出的字元串改變即說明配置成功。
⑸ 如何用Android NDK編譯FFmpeg
Android內置的編解碼器實在太少,於是我們需要FFmpeg。Android提供了NDK,為我們使用FFmpeg這種C語言代碼提供了方便。
不過為了用NDK編譯FFmpeg,還真的花費了不少時間,也得到了很多人的幫助,最應該謝謝havlenapetr。我覺得我現在這些方法算是比較簡潔的了--
下面就盡量詳細的說一下我是怎麼在項目中使用FFmpeg的,但是基於我混亂的表達能力,有不明白的就問我。
你得了解JNI和Android NDK的基本用法,若覺得我的文章還不錯,可以看之前寫的JNI簡單入門和Android NDK入門
首先創建一個標準的Android項目vPlayer
android create project -n vPlayer -t 8 -p vPlayer -k me.abitno.vplayer -a PlayerView
然後在vPlayer目錄里
mkdir jni && cd jni
wget http //ffmpeg org/releases/ffmpeg-0.6.tar.bz2
tar xf ffmpeg-0.6.tar.bz2 && mv ffmpeg-0.6 ffmpeg && cd ffmpeg
在ffmpeg下新建一個config.sh,內容如下,注意把PREBUILT和PLATFORM設置正確。另外裡面有些參數你也可以自行調整,我主要是為了配置一個播放器而這樣設置的。
#!/bin/bash
PREBUILT=/home/abitno/Android/android-ndk-r4/build/prebuilt/linux-x86/arm-eabi-4.4.0
PLATFORM=/home/abitno/Android/android-ndk-r4/build/platforms/android-8/arch-arm
./configure --target-os=linux \
--arch=arm \
--enable-version3 \
--enable-gpl \
--enable-nonfree \
--disable-stripping \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffserver \
--disable-ffprobe \
--disable-encoders \
--disable-muxers \
--disable-devices \
--disable-protocols \
--enable-protocol=file \
--enable-avfilter \
--disable-network \
--disable-mpegaudio-hp \
--disable-avdevice \
--enable-cross-compile \
--cc=$PREBUILT/bin/arm-eabi-gcc \
--cross-prefix=$PREBUILT/bin/arm-eabi- \
--nm=$PREBUILT/bin/arm-eabi-nm \
--extra-cflags="-fPIC -DANDROID" \
--disable-asm \
--enable-neon \
--enable-armv5te \
--extra-ldflags="-Wl,-T,$PREBUILT/arm-eabi/lib/ldscripts/armelf.x -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib $PREBUILT/lib/gcc/arm-eabi/4.4.0/crtbegin.o $PREBUILT/lib/gcc/arm-eabi/4.4.0/crtend.o -lc -lm -ldl"
運行config.sh開始configure
chmod +x config.sh
./config.sh
configure完成後,編輯剛剛生成的config.h,找到這句
#define restrict restrict
Android的GCC不支持restrict關鍵字,於是修改成下面這樣
#define restrict
編輯libavutil/libm.h,把其中的static方法都刪除。
分別修改libavcodec、libavfilter、libavformat、libavutil、libpostproc和libswscale下的Makefile,把下面兩句刪除
include $(SUBDIR)../subdir.mak
include $(SUBDIR)../config.mak
在ffmpeg下添加一個文件av.mk,內容如下
# LOCAL_PATH is one of libavutil, libavcodec, libavformat, or libswscale
#include $(LOCAL_PATH)/../config-$(TARGET_ARCH).mak
include $(LOCAL_PATH)/../config.mak
OBJS :=
OBJS-yes :=
MMX-OBJS-yes :=
include $(LOCAL_PATH)/Makefile
# collect objects
OBJS-$(HAVE_MMX) += $(MMX-OBJS-yes)
OBJS += $(OBJS-yes)
FFNAME := lib$(NAME)
FFLIBS := $(foreach,NAME,$(FFLIBS),lib$(NAME))
FFCFLAGS = -DHAVE_AV_CONFIG_H -Wno-sign-compare -Wno-switch -Wno-pointer-sign
FFCFLAGS += -DTARGET_CONFIG=\"config-$(TARGET_ARCH).h\"
ALL_S_FILES := $(wildcard $(LOCAL_PATH)/$(TARGET_ARCH)/*.S)
ALL_S_FILES := $(addprefix $(TARGET_ARCH)/, $(notdir $(ALL_S_FILES)))
ifneq ($(ALL_S_FILES),)
ALL_S_OBJS := $(patsubst %.S,%.o,$(ALL_S_FILES))
C_OBJS := $(filter-out $(ALL_S_OBJS),$(OBJS))
S_OBJS := $(filter $(ALL_S_OBJS),$(OBJS))
else
C_OBJS := $(OBJS)
S_OBJS :=
endif
C_FILES := $(patsubst %.o,%.c,$(C_OBJS))
S_FILES := $(patsubst %.o,%.S,$(S_OBJS))
FFFILES := $(sort $(S_FILES)) $(sort $(C_FILES))
接下來要添加一系列的Android.mk,在jni根目錄下的內容如下
include $(all-subdir-makefiles)
在ffmpeg目錄下,Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_STATIC_LIBRARIES := libavformat libavcodec libavutil libpostproc libswscale
LOCAL_MODULE := ffmpeg
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
libavformat/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES := \
$(LOCAL_PATH) \
$(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_CFLAGS += -include "string.h" -Dipv6mr_interface=ipv6mr_ifindex
LOCAL_LDLIBS := -lz
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)
libavcodec/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES := \
$(LOCAL_PATH) \
$(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_LDLIBS := -lz
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)
libavfilter、libavutil、libpostproc和libswscale下的Android.mk內容如下
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES := \
$(LOCAL_PATH) \
$(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)
最外層的jni/Android.mk和jni/ffmpeg/Android.mk我只是隨便這樣寫的,你應該根據自己的需求改寫。
最後運行ndk-build,經過漫長的等待就編譯完成了。至於具體怎麼應用可能以後會寫,我變得太懶了。。。
轉載,僅供參考,祝你愉快,滿意請採納。
⑹ Android NDK開發簡介 NDK和SDK以及JNI有什麼關系
NDK:Android NDK 是在SDK前面又加上了「原生」二字,即Native Development Kit,因此又被Google稱為「NDK」。
NDK全稱:Native Development Kit。
NDK是一系列工具的集合。
* NDK提供了一系列的工具,幫助開發者快速開發C(或C++)的動態庫,並能自動將so和java應用一起打包成apk。這些工具對開發者的幫助是巨大的。
* NDK集成了交叉編譯器,並提供了相應的mk文件隔離CPU、平台、ABI等差異,開發人員只需要簡單修改mk文件(指出「哪些文件需要編譯」、「編譯特性要求」等),就可以創建出so。
* NDK可以自動地將so和Java應用一起打包,極大地減輕了開發人員的打包工作。
其實:
NDK就是能夠方便快捷開發.so文件的工具。JNI的過程比較復雜,生成.so需要大量操作,而NDK就是簡化了這個過程。
Android SDK:
SDK (software development kit)軟體開發工具包。被軟體開發工程師用於為特定的軟體包、軟體框架、硬體平台、操作系統等建立應用軟體的開發工具的集合。因此!Android SDk 指的既是Android專屬的軟體開發工具包
JNI:
Java Native Interface (JNI)標準是java平台的一部分,它允許Java代碼和其他語言寫的代碼進行交互。JNI 是本地編程介面,它使得在 Java 虛擬機 (VM) 內部運行的 Java 代碼能夠與用其它編程語言(如 C、C++ 和匯編語言)編寫的應用程序和庫進行交互操作
當然一般需要進行如下操作流程:
1) 編寫java程序:這里以HelloWorld為例。為了實現在 java代碼中調用c函數printf。
代碼1:
class HelloWorld {
public native void testHelloWorld();
static {
System.loadLibrary("hello");
}
public static void main(String[] args) {
new HelloWorld().testHelloWorld();
}
}
聲明native方法:如果你想將一個方法做為一個本地方法的話,那麼你就必須聲明改方法為native的,並且不能實現。
Load動態庫:System.loadLibrary("hello");
這里一般是以static塊進行載入的。同時需要注意的是System.loadLibrary()的參數「hello」是動態庫的名字。
2) 編譯
javac HelloWorld.java
3) 生成擴展名為h的頭文件 javah ?
JNIEXPORT void JNICALL Java_HelloWorld_testHelloWorld (JNIEnv *, jobject);
這個h文件相當於我們在java裡面的介面,這里聲明了一個 Java_HelloWorld_testHelloWorld (JNIEnv *, jobject)方法,然後在我們 的本地方法裡面實現這個方法,也就是說我們在編寫C/C++程序的時候所使用的方法名必須和這里的一致)。
4) 編寫本地方法實現和由javah命令生成的頭文件裡面聲明的方法名相同的方法
代碼2:
#include "jni.h"
#include "HelloWorld.h"
#include other headers
JNIEXPORT void JNICALL Java_HelloWorld_testHelloWorld(JNIEnv *env, jobject obj)
{
printf("Hello world!/n");
return;
}
注意代碼2中的第1行,需要將jni.h(該文件可以在%JAVA_HOME%/include文件夾下面找到)文件引入,因為在程序中的JNIEnv、 jobject等類型都是在該頭文件中定義的;另外在第2行需要將HelloWorld.h頭文件引入。然後保存為 HelloWorldImpl.c就ok了。
5) 生成動態庫
這里以在Windows中為例,需要生成dll文件。在保存HelloWorldImpl.c文件夾下面,使用VC的編譯器cl成。 cl -I%java_home%/include -I%java_home%/include/win32 -LD HelloWorldImp.c -Fehello.dll 注意:生成的dll文件名在選項-Fe後面配置,這里是hello,因為在HelloWorld.java文件中我們loadLibary的時候使用的名字是hello。
另外需要將-I%java_home%/include -I%java_home%/include/win32參數加上,因為在第四步裡面編寫本地方法的時候引入了jni.h文件。