ndk編譯的程序如何執行-ag真人国际官网
❶ 如何在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
02.#include
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
#include
#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怎麼使用
android ndk的使用:
一、ndk是一系列工具的集合。
1、 ndk提供了一系列的工具,幫助開發者快速開發c(或c )的動態庫,並能自動將so和java應用一起打包成apk。這些工具對開發者的幫助是巨大的。
2、ndk集成了交叉編譯器,並提供了相應的mk文件隔離平台、cpu、api等差異,開發人員只需要簡單修改mk文件(指出「哪些文件需要編譯」、「編譯特性要求」等),就可以創建出so。
3、ndk可以自動地將so和java應用一起打包,極大地減輕了開發人員的打包工作。
二、ndk提供了一份穩定、功能有限的api頭文件聲明。
google明確聲明該api是穩定的,在後續所有版本中都穩定支持當前發布的api。從該版本的ndk中看出,這些api支持的功能非常有限,包含有:c標准庫(libc)、標准數學庫(libm)、壓縮庫(libz)、log庫(liblog)。
❸ 如何使用自己的makefile編譯android ndk項目
android ndk提供了一套自己的makefile管理方式,要將源碼項目移植到android平台,需要按照android的makefile規則編寫makefile,還要按android的規則部署源碼目錄,對一個有自己的makefile管理方法的大型項目來說,只是做一下makefile遷移工作就是一件很麻煩的事。
其實android ndk上的編譯說到底也就是交叉編譯,只要配置好交叉編譯工具鏈,使用原有的makefile也是可以編譯出在android運行的c、c 程序的。
以android-ndk-r4-crystax的ndk版本為例:
編譯器路徑 android-ndk-r4-crystax/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin
名稱前綴 arm-eabi-
頭文件目錄 android-ndk-r4-crystax/build/platforms/android-3/arch-arm/usr/include
庫文件目錄 android-ndk-r4-crystax/build/platforms/android-3/arch-arm/usr/lib
你可以試一下上面的配置,如果編譯鏈接都沒有問題,可以adb push到android設備上運行看看,什麼結果?
有點崩潰,根本運行不起來,你也許想試試看android自帶的ndk例子,確實是能夠運行的,問題在哪兒呢?
只是正確配置了編譯器、頭文件、庫文件還不夠,還需要配置編譯、鏈接的參數,android例子中編譯鏈接的參數是什麼呢?你也許想深究一下android的makefile,可是不久你會發現那是更崩潰的事情,裡面用了很多的make腳本函數。其實android的makefile是可以把執行的詳細命令輸出來的,只要make的時候加上v=1即可。可以看到確實帶了很多參數
編譯參數:
-fpic
-mthumb-interwork
-ffunction-sections
-funwind-tables
-fstack-protector
-fno-short-enums
-wno-psabi
-march=armv5te
-mtune=xscale
-msoft-float
-mthumb
-fomit-frame-pointer
-fno-strict-aliasing
-finline-limit=64
-wa,--noexecstack
-d__arm_arch_5__
-d__arm_arch_5t__
-d__arm_arch_5e__
-d__arm_arch_5te__
-dandroid
鏈接參數:
-nostdlib
-bdynamic
-wl,-dynamic-linker,/system/bin/linker
-wl,--gc-sections
-wl,-z,noreloc
-wl,--no-undefined
-wl,-z,noexecstack
-l$(platform_library_directorys)
crtbegin_static.o
crtend_android.o
這其中鏈接參數中的-wl,-dynamic-linker,/system/bin/linker、crtbegin_static.o、crtend_android.o是最關鍵的,android使用了自己的進程載入器,並且自定義了c運行時的啟動結束。難怪先前編譯的進程啟動不了。
❹ ndk 編譯 boringssl
然後source 命令執行下這個腳本
其中cmake_toolchain_file完全換成boringssl自帶的android.toolchain.cmake 我還添加了一個cmake_build_type 設置為release
cmake_make_program 可以設置為sdk里自帶的ninja。
執行這個shell腳本,你會在ssl和crypto下得到兩個靜態庫libssl.a和libcrypto.a,頭文件就是boringssl根目錄下的include,導入到你的android工程就不介紹了,文章很多的。