Android ndk開發

前言:我對C/C++是沒有任何基礎的,雖然大學中學了一個學期的C可是都算還給老師了。這篇文章是我作一個NDK項目積累下來的知識,能夠說是一篇小白上手文章,因此高手請自行繞路。java

一、準備android

    作NDK開發是很是要注意開發環境和開發版本的(我的認爲)。我使用的是Eclipse (Luna 4.4.0),NDK版本r10,應該是在<=r6版本的NDK還須要安裝cygwin(這這裏就不討論,網上大把資料),附上NDK的下載連接方便不能×××的朋友,32位 ,64位,網站不能訪問,可是直接用下載連接是能夠下載到的。編程

    安裝好NDK後,就須要在Eclipse上進行配置了。
windows

      一、windows-preferences-android-ndk-ndklocation  選擇ndk的安裝目錄
ide

       二、配置builder環境在須要進行ndk開發的項目上右鍵-properties-builder-new - program 在出現的彈窗中作如下配置
學習

        

wKioL1Uva7bxkgyqAAHHkSQdv6o361.jpg

wKiom1UvamKgeEteAAE299U2L3w010.jpg

wKioL1Uva7eRmrMdAAIIeisqxW0452.jpg

    三、右鍵項目工程Android tools - Add Native Support  
測試

wKioL1UvbF_Cvl6KAAAst-L9hxw144.jpg

出現jni目錄以及Android.mk,xx.cpp就說明添加成功了。就能夠進行NDK開發了。網站


二、Java調用C++中的方法。ui

例如:獲取從C++文件中獲取字符串並打印google

在Activity類A中:

static{
    System.loadLibrary("xx");//xx是Android.mk文件中LOCAL_MODULE 的字段
}
//必須和ndk中的方法名同樣
public native String getString();

//onclick方法
public void click(View v){
    String str = getString();
    System.out.println("調用JNI中的方法:"+str);
}

在ndk.cpp中

#include <jni.h>
#include<string.h>
/**
* extern "C" 是必須加的,經測試不加的話方法調用不成功,也沒找到答案,有知道爲何的請* 告知,方法名稱必須按照JNI的規範來Java_包名_類名_方法名,都必須以'_'隔開。
*/
extern "C" jstring Java_com_test_ndk_A_getString(JNIEnv* env,jobject thiz){
    jstring str ;
    //在C中的是以(*env)->調用的,網上大部分的博客文檔也是這種狀況。
    str = env->newStringUTF("hello world");//不能使用中文,否則會報錯。
    return str;
}

運行工程便可看到效果。

三、C++中調用Java方法

在ClassB中

static{
    System.loadLibrary("ndk");
}
public native void loadJavaMethod();

public void f1(){
    String str ;
    str = "hello world from java";
    System.out.println(str);
}

public String f2(){
    String str ;
    str = "f2: hello world from java";
    System.out.println(str);
    return str;
}

public void f3(String str,int i){
    System.out.println("f3 內容爲:"+str+",數字爲:"+i);
}

在ndk.cpp中

#include <jni.h>
#include<string.h>
extern "C" void Java_com_test_ndk_B_loadJavaMethod(JNIEnv *env,jobject thiz){

    //調用無參無返回值的方法
    jclass cls = env->GetObjectClass(thiz);
    //GetMethodID("jclass對象","方法名","方法參數")
    jmethodID mID = env->GetMethodID(cls,"f1","()V");
    if(mID != NULL){
	 env->CallVoidMethod(thiz,mID);
    }
    //調用有參無返回值得方法
     //參數類型除了基本數據類型外,其餘的都須要按照這樣的格式
     //L包名/類名;  包名用/分割,必須以;結束
     //詳情請參考這篇文章     
     jclass cls = env->GetObjectClass(thiz);
    jmethodID mID = env->GetMethodID(cls,"f3","(Ljava/lang/String;I)V");
    jstring content = env->NewStringUTF("hehe");
    jint i = 10;
    if(mID != NULL){
	 env->CallVoidMethod(thiz,mID,content,i);
    }
    //調用有返回值無參的方法
    jclass cls = env->GetObjectClass(thiz);
    jmethodID mID = env->GetMethodID(cls,"f2","()Ljava/lang/String;");
     if(mID != NULL){
	 env->CallObjectMethod(thiz,mID);
    }
    //調用其餘類中的方法假設有一個Student類,若是要使用Student類中的內部類A,格式爲
    //com/test/ndk/Student$A
    jclass stu = env->FindClass("com/test/ndk/Student");
    //實例化無參構造方法
    jobject stuObj = env->NewObject(stu,env->GetMethodID(stu,"<init>","()V"));
    jmethodID getNameId = env->GetMethodID(stu,"getName","()V");
    if(getNameId !=NULL){
	env->CallVoidMethod(stuObj,getNameId);
    }
}

四、在本身的 so文件中調用第三方的so文件

這種狀況通常是由於第三方的C/C++中的方法不是按照JNI的規範來寫,這時就須要進行從新包裝,並使用,固然前提是有了第三方的說明文檔。

將第三方的so文件配置到預編譯環境

在工程的jni文件下新建prebuilt文件夾(名稱隨意)將第三方的so文件放到裏面例如libthird.so,而後在這個文件夾下新建Androdid.mk文件,文件內容爲

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := libthird
LOCAL_SRC_FILES := libthird.so

include $(PREBUILT_SHARED_LIBRARY)

打開jni下的Android.mk文件,加入如下字段

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := ndk
LOCAL_SRC_FILES := ndk.cpp

#名稱和第三方mk中LOCAL_MODULE定義的名稱同樣
LOCAL_SHARED_LIBRARIES := libthird

include $(BUILD_SHARED_LIBRARY)

#添加路徑
include $(LOCAL_PATH)/prebuilt/Android.mk

 配置完成後,在工程的libs\armeabi目錄下能夠看到第三方的so文件,注意不能直接將第三方的so文件放到這個目錄下。不然在builde的時候會刪除。

假設在第三方的C/C++文件中有這樣一個方法

//extern "C"在第三方的包中的方法也必須添加,測試時,若是不添加方法調用不成功,但這個是不能限//制到第三方的,有待解決
extern "C" int f1(){
	return 101;
}

 在本身的C/C++文件中調用第三方的方法

  

#include <jni.h>
#include <dlfcn.h>
#include <fcntl.h>
void *filehandle = NULL;
jstring (*f1)() =NULL;
extern "C" jint Java_com_test_ndk_classA_f1(JNIEnv * env,jobject thiz){
    jint i ;
    filehandle = dlopen("/data/data/com.fly.ndk2/lib/libndk.so", RTLD_LAZY);
    if(filehandle){
	f1 = (int(*)())dlsym(filehandle,"f1");
    }
    if(f1){
        i = f1();
        dlclose(filehandle);
	filehandle = NULL;
    }
    return i;
}

以上內容除了沒有涉及到真正的C/C++編程外,JNI開發的一些知識點都涉及到了,僅屬入門的一些知識,在徹底不瞭解C/C++編程的狀況下耗費了2天時間才積累了以上知識。若是還須要更深刻的學習就須要學習C/C++的語法知識以及編譯。

以上的代碼以及操做不必定在其餘的環境中有效,謹記。

相關文章
相關標籤/搜索