NDK,动态链接库,JNI
??? jni是java調用本地方法(c、c++寫的),android 下用JNI需要.so文件,NDK就是能夠方便快捷開發(fā).so文件的工具。使用NDK的基本思路就是將本地代碼(native code)編譯成函數庫,然后就可以在Java代碼中使用它。(當java程序在虛擬機中執(zhí)行時,當執(zhí)行native的函數時,虛擬機的“native引擎”會根據包名、函數名和參數來決定調用哪個本地函數(c中函數),所以在調用本地函數之前,必須把C所生成的動態(tài)庫裝載到虛擬機,否則java中的native函數就會因找不到本地實現而報錯。Native引擎中AndroidRuntime類提供了一個registerNativeMethods()函數,它實現了java native函數和c中本地函數的映射關系。)
JNI的編寫步驟
1)編寫帶有native 聲明的java類.
2)編譯java文件成class類(eclipse可自動生成)
3)編譯成.h文件
4)使用C/C++編寫代碼
5)編寫makefile文件,將.h和.c(.cpp)文件編譯成.dll(.so)文件
6)將.dll(.so)文件提供給項目,用system.loadLibrary方法調用.
?一、 開發(fā)環(huán)境的搭建
?Step1安裝Cygwin
????? Android是基于Linux的,因此如果你要為它編寫native代碼,你就需要一些Unix工具。在Windows上,NDK支持Cygwin1.7.x或者更高的版本。Cygwin不過是在Windows上模擬提供Unix環(huán)境的一系列的工具。安裝路徑中不能包含空格字符。(可以直接使用離線安裝方式(需要資源的可留下郵箱))?Step2安裝Android NDK?
????? 從Android官方網站獲得下載Android NDK。下載Windows平臺上的NDK zip包,并將其解壓到某個目錄,再次注意,目錄中不能有空格字符。我將它解壓到D:\,所以目錄路徑就是D:\ android-ndk。?在cygwin環(huán)境下使用ndk的編譯器對c/C++進行編譯。因此,只需在cygwin下配置Android NDK即可。? 配置NDK的路徑: a) 在cygwin安裝目錄中修改 home\<你的用戶名>\.bash_profile 文件(如:C:\cygwin\home\Administrator)中最后添加環(huán)境變量 NDK=/cygdrive/g/qjc/soft/android-ndk-r8b-windows/android-ndk-r8b export NDK 其中:NDK=/cygdrive/<你的android NDK存放的盤的盤符>/<android ndk 目錄> ,"NDK"這個名字隨便起,以后經常用不要太長 b) 重啟cygwin,輸入cd $NDK,可以進行NDK相應的目錄說明配置正確二、代碼的編寫(參考android-ndk-r8d\samples\hello-jni)
Step1?建立項目編寫java代碼
HelloJni.java :
/** Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.hellojni;
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
public class HelloJni extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
/* Create a TextView and set its content.
* the text is retrieved by calling a native
* function.
*/
TextView tv = new TextView(this);
tv.setText( stringFromJNI() );
setContentView(tv);
}
/* A native method that is implemented by the
* 'hello-jni' native library, which is packaged
* with this application.
*/
public native String stringFromJNI();
/* This is another native method declaration that is *not*
* implemented by 'hello-jni'. This is simply to show that
* you can declare as many native methods in your Java code
* as you want, their implementation is searched in the
* currently loaded native libraries only the first time
* you call them.
*
* Trying to call this function will result in a
* java.lang.UnsatisfiedLinkError exception !
*/
public native String unimplementedStringFromJNI();
/* this is used to load the 'hello-jni' library on application
* startup. The library has already been unpacked into
* /data/data/com.example.HelloJni/lib/libhello-jni.so at
* installation time by the package manager.
*/
static {
System.loadLibrary("hello-jni");
}
}
????? 程序開始運行的時候會加載hello-jni, static區(qū)聲明的代碼會先于onCreate方法執(zhí)行。如果你的程序中有多個類,而且HelloJni這個類不是你應用程序的入口,那么 hello-jni(完整的名字是libhello-jni.so)這個庫會在第一次使用HelloJni這個類的時候加載。
public native String stringFromJNI();?
public native String unimplementedStringFromJNI();
可以看到這兩個方法的聲明中有 native 關鍵字, 這個關鍵字表示這兩個方法是本地方法,也就是說這兩個方法是通過本地代碼(C/C++)實現的,在java代碼中僅僅是聲明。
eclipse自動編譯該工程,生成相應的.class文件,這步必須在下一步之前完成,因為生成.h文件需要用到相應的.class文件。
Step2編寫相應的C/C++代碼
利用javah這個工具生成相應的.h文件,然后根據這個.h文件編寫相應的C/C++代碼。
2.1 生成相應.h文件:
?? ? 2.1.1首先我們在工程目錄下建立一個jni文件夾:?
? ?? 2.2.2以生成相應的.h文件:
項目路徑$ javah -classpath bin/classes -d jni com.example.hellojni.HelloJni?
? ? ? -classpath bin/classes:表示類的路徑
? ??? -d jni: 表示生成的頭文件存放的目錄
? ? ? com.example.hellojni.HelloJni 則是完整類名
? ??? 這一步的成功要建立在已經在 bin/com/example/hellojni/? 目錄下生成了 HelloJni.class的基礎之上。
? ??? 現在可以看到jni目錄下多了個.h文件
?
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_test_MainActivity */#ifndef _Included_com_example_test_MainActivity #define _Included_com_example_test_MainActivity #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif #endif?
?2.2 編寫相應的.c文件
???? hello-jni.c :
?
/** Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <string.h>
#include <jni.h>
/* This is a trivial JNI example where we use a native method
* to return a new VM String. See the corresponding Java source
* file located at:
*
* apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java
*/
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
?
2.3. 編譯c文件生成相應的庫
? ?? 2.3.1 編寫Android.mk文件
??????????? 在jni目錄下(即hello-jni.c 同級目錄下)新建一個Android.mk文件,Android.mk 文件是Android 的 makefile文件,內容如下:? ?
# Copyright (C) 2009 The Android Open Source Project#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY) 除去模塊名(hello-jni)外,文件中其它東西都不用關心?對NDK的build過程來說,Android.mk至關重要,它用來區(qū)分NDK模塊。在我們這個例子中,模塊的名字是hello-jni,它告訴build工具它包含了一個源文件hello-jni.c我們到jni文件夾里創(chuàng)建hello-jni 2.3.2 生成.so共享庫文件 運行:$NDK/ndk-build。
???????? 注意:該命令$NDK和/ndk-build是連接到一起的,中間沒有空格,實際使用時輸入完整命令$NDK/ndk-build,不能只輸入ndk-build。$NDK/ndk-build成功運行后,將會在項目libs/armeabi/ 目錄下創(chuàng)建一個.so文件。這個.so文件就是二進制庫,它將被包含到應用的.apk包中,并可以被Java代碼鏈接。在Eclipse中,你只需要在選中項目根節(jié)點后,按F5鍵,就可以將在Cygwin控制臺中所做的更改,更新到Eclipse項目中。?
如果修改了NDK代碼中的C/C++源文件,那么就必須重新運行ndk-build命令。由于Eclipse ADT不支持NDK,所以你需要在Cygwin控制臺中去做這件事情。每次都不能忘記更新Eclipse項目!Step3優(yōu)化
??? 每次修改了之后都要手動進行編譯,這樣比較麻煩,下面介紹一種簡單的方法(增加一個C-Builer):
??????????i.?右擊項目選擇properties,出現下面
? ? ? ? ? ? ? ? ? ? ? ??
??????????ii.在左邊選擇Builders,在右邊點擊New這個按鈕,出現
? ? ? ? ? ? ? ? ? ? ? ?
?????????iii.選擇Program,點擊OK,出現配置編譯器對話框:
? ? ? ? ? ? ? ? ? ? ? ?
?????????iv.?name改為C_Builder
???????? v.?設置Location:<你cygwin安裝路徑>\bin\bash.exe,如:C:\cygwin\bin\bash.exe
??????? ?vi.?設置Arguments:
??????????? --login@-c@"cd@/cygdrive/g/qjc/soft/android-ndk-r8b-windows/android-ndk-r8b/samples/hello-jni@&&@$NDK/ndk-build
???????????? (這是我的目錄,自己的需要適當修改,不能改動的,--login?–c?是神馬意思我也不懂,為了方便表示,上面字符串中的4個@其實是空格,輸入的時候請換為空格)
????????????Arguments這串參數實際是??給bash.exe命令行程序傳參數,進入要編譯的程序目錄,然后運行ndk-build編譯程序
? ? ? ? ? ? ? ? ? ? ? ?
?????????vii.接著切換到Refresh選項卡,給Refresh resources upon completion打上鉤
? ? ? ? ? ? ? ? ? ? ? ?
??????? ?viii.然后切換到Build Options選項卡,勾選上最后三項
? ? ? ? ? ? ? ? ? ? ? ?
?????????ix.之后點擊Specify Resources按鈕,選擇資源目錄,勾選你的項目目錄即可
? ? ? ? ? ? ? ? ? ? ? ??
?????????x.最后點擊Finish,注:如果你配置的編譯器在其它編譯器下邊,記得一定要點Up按鈕,把它排到第一位,否則C代碼的編譯晚于Java代碼的編譯,會造成你的C代碼要編譯兩次才能看到最新的修改
???????????????????? ? ??
轉載于:https://www.cnblogs.com/andies/archive/2013/02/21/2921013.html
總結
以上是生活随笔為你收集整理的NDK,动态链接库,JNI的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SqlCommand类,在与数据库交互式
- 下一篇: 炎性。增生性。结肠息肉会癌变吗