android NDK開發入門。

關於 NDK 的使用,首先須要瞭解一個概念: JNI 。什麼是 JNI  java

       2.1 Hello-jniandroid

       這個是 NDK 自帶的例子程序,安裝官方網站的說明,一步步來,應該沒有什麼問題,這裏就不細說了。 express

       2.2 My God I did itapache

       學習的第一步,就是模仿。咱們依照上面 Hello-jni 的例子,在建立本身的 NDK 程序。在此過程當中,對相關的內容和概念進行分析和說明。    app

首先,在工程的 src 夾子下用來放置 Java 文件。咱們打開 Eclipse ,而後新建一個 Android 工程,工程名就叫 MyJNI,工程路徑選擇咱們建立的 NDK 的路徑。這裏須要注意的是,工程名,包名等,須要和上面的 c 文件中的保持一致。less

(Java _com_jpf_myjni _MyJNI _stringFromJNI)ide

       工程創建好後,編輯 src/com/jpf/myjni/MyJNI.java 文件,內容以下:函數

package com.jpf.myjni;學習

 

import android.app.Activity;網站

import android.widget.TextView;

import android.os.Bundle;

 

public class MyJNI extends Activity {

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super .onCreate(savedInstanceState);

        TextView  tv = new TextView( this );

        tv.setText( stringFromJNI() );

        System. out .println( "Here we go ..." );

        setContentView(tv);

        System. out .println( "Done!" );

    }

   

    public native String  stringFromJNI();

    static {

           System.loadLibrary ( "myjni" );

    }

}

       須要說明的幾點:

       public native String  stringFromJNI(); 這句申明,帶有 native 關鍵字,說明該方法是本地方法。

       System.loadLibrary ( "myjni" ); 這句就是用來加載咱們的 c 動態庫的。上面聲明的方法,具體實現,就在咱們加載的庫中。

其次,這裏纔是要學習的內容,建立本身的 NDK 工程。作eclips建立到project的目錄下建立jni文件夾,用於放.c文件。

#include <string.h>

#include <stdio.h>

#include <jni.h>

 

#include <android/log.h>

#define LOG_TAG "MYJNI"

 

#define LOGI(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

 

static char s_string[] = "My god, I did it!";

 

jstring

Java_com_jpf_myjni_MyJNI_stringFromJNI( JNIEnv* env,

                                        jobject thiz )

{

       LOGI("MyJNI is called!");

       return (*env)->NewStringUTF(env, s_string);

}

       這個程序,惟一和 hello-jni 不一樣的就是引用了 <android/log.h> 這個頭文件。在該頭文件中,聲明瞭函數__android_log_print(), 能夠根據不一樣的 log 級別,輸出 log ,方便代碼的調試。在 NDK 中, printf() 無法輸出,因此咱們須要藉助 log 庫來將咱們 c 代碼庫中須要輸出的內容,經過 java 控制檯輸出。調用函數 __android_log_print(), 就能夠在 Eclipse中,查看 LogCat 來查看相關的輸出信息了。

       注意:

       在 c 文件中,函數名這樣定義: Java_com_jpf_myjni_MyJNI_stringFromJNI ,有什麼講究麼?這個是 JNI 的標準,定義須要按照以下格式:

       Java _packagename _classname _methodname ,

       例如: Java _com_jpf_myjni _MyJNI _stringFromJNI

       接着建立文件 jni/Android.mk. 這個文件是咱們本地 c 代碼的 Makefile 。文件內容以下:

LOCAL_PATH := $(call my-dir)

 

include $(CLEAR_VARS)

 

LOCAL_MODULE := myjni

LOCAL_SRC_FILES := myjni.c

 

LOCAL_LDLIBS += -llog

 

include $(BUILD_SHARED_LIBRARY)

       分別對上述 Makefile 的語句進行說明。

       LOCAL_PATH := $(call my-dir) 這句用來指定編譯的路徑。經過調用宏 my-dir ,獲取到當前工做的路徑。

       include $(CLEAR_VARS) CLEAR_VARS 這個變量是編譯系統提供的,用來指明一個 GNU makefile 文件,添加這句,主要的目的是清理全部的 LOCAL_XXX. ,好比 LOCAL_MODULE , LOCAL_LDLIBS 。在每一個新模塊的開始處,須要添加這句。

       LOCAL_MODULE := myjni 這句定義了模塊名稱,未來編譯的庫就以此命名。若果編譯的是動態庫,那麼庫名就是 libmyjni.so.須要注意的是,若是你定義 module 爲 libmyjni ,那麼系統在生成動態庫的時候,就不要再爲你添加 lib 的前綴了,生成德動態庫名字仍是 libmyjni.so.

       LOCAL_LDLIBS += -llog 這句指定了須要另外連接的庫。咱們在代碼中,用到了 log 庫,因此這裏加上這句。

       include $(BUILD_SHARED_LIBRARY) 這句說明未來生產的庫是共享庫,及動態連接庫。若須要生產靜態庫,能夠這樣寫:include $(BUILD_STATIC_LIBRARY) 

  若是沒有創建工程,      

 寫完了 c 文件和 Makefile 文件,是否能夠編譯了呢?咱們試一下。在 cygwin 中,進入工程目錄,運行 ndk-build ,獲得下面的結果:

Administrator@lenovo-0e47e162 /android/android-ndk-r4/samples/myndk

$ ndk-build

Android NDK: Could not find application's manifest from current directory.

Android NDK: Please ensure that you are inside the project's directory !

/android/android-ndk-r4/build/core/build-local.mk:74: *** Android NDK: Aborting

   .  Stop.

       看到這個錯誤的意思是,缺乏 manifest 文件。老版本的 NDk ,工程中有一個 apps ,裏面包含了應用的程序文件和Application.mk 。如今的版本,不須要咱們本身編寫 Application.mk, ,不過仍須要工程相關的配置信息。那麼如何作到呢?須要手工去寫 manifest 文件麼?不須要。咱們只須要在 Eclipse 中,建立工程就能夠了,這些配置文件會自動生成。

       創建好工程,再次編譯,在 cygwin 中運行 ndk-build ,結果 OK 

Administrator@lenovo-0e47e162 /android/android-ndk-r4/samples/myndk

$ ndk-build

Compile thumb  : myjni <= /android/android-ndk-r4/samples/myndk/jni/myjni.c

SharedLibrary  : libmyjni.so

Install        : libmyjni.so => /android/android-ndk-r4/samples/myndk/libs/armea

bi

       咱們看到,須要的共享庫已經生成,而且安裝好了。下面就能夠生成 apk 了。

而後,就能夠運行了,用eclisps模擬器仍是生成APK文件,都是能夠的。


在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.cinclude $(BUILD_SHARED_LIBRARY)
這個Androd.mk文件很短,下面咱們來逐行解釋下:

LOCAL_PATH := $(call my-dir)

一個Android.mk 文件首先必須定義好LOCAL_PATH變量。它用於在開發樹中查找源文件。在這個例子中,宏函數’my-dir’, 由編譯系統提供,用於返回當前路徑(即包含Android.mk file文件的目錄)。

include $( CLEAR_VARS)

CLEAR_VARS由編譯系統提供,指定讓GNU MAKEFILE爲你清除許多LOCAL_XXX變量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...), 
除LOCAL_PATH 。這是必要的,由於全部的編譯控制文件都在同一個GNU MAKE執行環境中,全部的變量都是全局的。

LOCAL_MODULE := hello-jni

編譯的目標對象,LOCAL_MODULE變量必須定義,以標識你在Android.mk文件中描述的每一個模塊。名稱必須是惟一的,並且不包含任何空格。

注意:編譯系統會自動產生合適的前綴和後綴,換句話說,一個被命名爲'hello-jni'的共享庫模塊,將會生成'libhello-jni.so'文件。

重要注意事項:

若是你把庫命名爲‘libhello-jni’,編譯系統將不會添加任何的lib前綴,也會生成 'libhello-jni.so',這是爲了支持來源於Android平臺的源代碼的Android.mk文件,若是你確實須要這麼作的話。

LOCAL_SRC_FILES := hello-jni.c

LOCAL_SRC_FILES變量必須包含將要編譯打包進模塊中的C或C++源代碼文件。注意,你不用在這裏列出頭文件和包含文件,由於編譯系統將會自動爲你找出依賴型的文件;僅僅列出直接傳遞給編譯器的源代碼文件就好。

注意,默認的C++源碼文件的擴展名是’.cpp’. 指定一個不一樣的擴展名也是可能的,只要定義LOCAL_DEFAULT_CPP_EXTENSION變量,不要忘記開始的小圓點(也就是’.cxx’,而不是’cxx’)

include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY表示編譯生成共享庫,是編譯系統提供的變量,指向一個GNU Makefile腳本,負責收集自從上次調用'include $(CLEAR_VARS)'以來,定義在LOCAL_XXX變量中的全部信息,而且決定編譯什麼,如何正確地去作。還有 BUILD_STATIC_LIBRARY變量表示生成靜態庫:lib$(LOCAL_MODULE).a, BUILD_EXECUTABLE 表示生成可執行文件。

相關文章
相關標籤/搜索