eclipse中新建jni工程


1.什么是NDK

網上很多不多說,全稱是Android Native Developer Kit,是一個工具合集,我理解可以把c/c++打包成.so文件

這是目錄結構,要用到指令ndk-build

需要配置環境變量

配置成功在cmd中輸入ndk-build會出現如下信息

2.什么JNI

JNI全稱是 Java Native Interface,字面意思是java的本地接口,我們知道java是誇平台的,所以java寫的程序應該是與平台無關的,

所以在java中如果要調用本地庫就需要專門的接口,我可以理解為一套調用機制或者說協議。

進行JNI編程的步驟:  

  1.java 層:用關鍵字native聲明c/c++方法。導入lib庫:

public class Native {
    static{
        System.loadLibrary("HelloJava");
    }
    public static native String getString();
}

注意這里"HelloJava"是你新建的c/c++文件名,不要多余寫東西。現在我們定義了一個類是Native.java,然后我們要把這個類變成頭文件。不過谷歌出的android studio 2.2版本以后可以直接新建一個支撐c/c++工程了。這里不先不提。

首先需要將Native.java編譯生成一個.class文件。這里要用的javac。不過你也可以直接運行一下。eclipse會主動幫你編譯生成.class,打開cmd

生成的Native.class

 

這里注意javac的使用我直接cd到了這個類的目錄。

生成.class文件之后,再用jdk另外一個工具生成.h文件javah

同樣在cmd中:輸入javah -help查看使用幫助

[options]是可選項目,<classes>是必須項目。這個就是我們之前生成的Native.class

現在我們要確定需要加載類的路徑,還有輸出目錄。注意每一段之間的空格,容易出錯

類的后綴不需要寫。執行這個指令完成之后會在當前目錄下生成對應的.h文件

在eclipse右鍵工程名,refresh(f5)以下就會顯示出來

至此我們java層的工作完成,接下來就是在Jni中實現所聲明的方法。

2.Jni層: 

在工程中新建一個jni目錄並且將剛才的.h文件移過來

新建一個HelloJava.c的.c源文件在這里我們來實現java層中聲明的native方法

#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
JNIEXPORT jstring JNICALL Java_com_example_helloc_Native_getString
  (JNIEnv *env, jclass j){
    return (**env).NewStringUTF(env,"hello java!");
}

這個函數名字太復雜太扯淡了。其實jni有一個命名規則,我們現在不關心這個,這個函數名可以直接從之前生成的.h文件復制過來
下面就是.h文件的內容

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_helloc_Native */

#ifndef _Included_com_example_helloc_Native
#define _Included_com_example_helloc_Native
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_helloc_Native
 * Method:    getString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_helloc_Native_getString
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

這里只有函數聲明,復制這個聲明,我們只要在jni實現函數體就可以了。具體的編程方式這里先不提,這里只是返回了一個字符串

ndk中已經集成了部分c庫。完成之后,我們需要將.c變成linux系統能使用的.so庫。這個工作就由ndk來完成,具體如下:

ndk-build指令需要在工程目錄下執行才有效果,但是並沒有規定在什么子目錄下,所有效果都是一樣的。該指令會將.c或者c++文件生成對應的.so文件,而且是兩份,一份在\project path\obj\local\armeabi,這份比較大,包含有調試信息,不會隨着app一起發布。另外一份比較小\ project path \libs\armeabi,這個會隨着apk一起發布。編譯結果

生成了各個平台支持的.so文件完成之后工程目錄的libs還沒有出現.so文件,

需要右鍵工程refresh(F5)一下就會出現,這里系統會自動添加"lib"前綴。但是注意在java層導入庫的時候不要寫"libHelloJava"這個要寫:

static{

    System.loadLibrary("HelloJava");

}

完成之后執行結果。這是android代碼

public class MainActivity extends Activity {
    public Button btnShow;
    public TextView tvShow;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnShow = (Button)findViewById(R.id.btn_show);
        tvShow = (TextView)findViewById(R.id.tv_show);
        btnShow.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                tvShow.setText(Native.getString());
            }
        });
    }
}

結果

 

另外執行ndk-build之前需要先編寫.mk文件。具體如下:

在jni中新建一個android.mk文件,內容如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE    := HelloJava
LOCAL_SRC_FILES := HelloJava.c
#LOCAL_LDLIBS    := -llog -ljnigraphics

include $(BUILD_SHARED_LIBRARY)

具體解釋如下(借用一為大神的):

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    := Native

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

 

LOCAL_SRC_FILES := Native.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 表示生成可執行文件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM