準備工作
工具選擇
開發NDK我選擇最新版的Android Studio2.2.2,主要原因是最新版已經很好的支持了c/c++的代碼提示、代碼調試和源代碼跳轉等功能,個人感覺非常好用。
開始實踐
1.首先下載最新版Android studio並且下載ndk開發中需要的工具,如下圖所示:
2.安裝好三個工具後我們就可以進行開發了,首先我們新建一個項目,其中選中“Include C++ Support”,如下圖所示:
3.創建好之後,點擊“run”就可以安裝運行了。
使用c/c++進行開發
創建一個Java類
public class NdkTest {
public static native String callFromNativ(String str);
public static native void callJavaCode(String str);
public static native void getBitmapInfo(Bitmap bitmap);
public static native void callJavaInstaceCode(String str);
}
public class CallFromNative {
public static final String TAG = "CallFromNative";
public static void showLog(String str) {
Log.e(TAG,"callByNative = "+str);
}
public void showInstanceLog(String str) {
Log.e(TAG,"callByNative = "+str);
}
}
生成頭文件
通過命令行生成頭文件,首先進入到java目錄下然後輸入命令
然後你就可以看到生成的頭文件了,打開頭文件如下所示:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class test_com_example_liaojd_myapplication_NdkTest */
#ifndef _Included_test_com_example_liaojd_myapplication_NdkTest
#define _Included_test_com_example_liaojd_myapplication_NdkTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: test_com_example_liaojd_myapplication_NdkTest
* Method: callFromNativ
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callFromNativ
(JNIEnv *, jclass, jstring);
/*
* Class: test_com_example_liaojd_myapplication_NdkTest
* Method: callJavaCode
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callJavaCode
(JNIEnv *, jclass, jstring);
/*
* Class: test_com_example_liaojd_myapplication_NdkTest
* Method: callJavaInstaceCode
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callJavaInstaceCode
(JNIEnv *, jclass, jstring);
/*
* Class: test_com_example_liaojd_myapplication_NdkTest
* Method: getBitmapInfo
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_getBitmapInfo
(JNIEnv *, jclass, jobject);
#ifdef __cplusplus
}
#endif
#endif
實現函數聲明
在cpp文件夾下面創建一個main.c的文件,如下所示:
//
// Created by liaojd on 2017/1/13.
//
#include <android/bitmap.h>
#include "jni.h"
#include "android/log.h"
#include "android/bitmap.h"
#define TAG "NDK_TEST"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
/**
* 實現打印輸出並返回一個字符串
*/
JNIEXPORT jstring JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callFromNativ
(JNIEnv *env, jclass obj, jstring jstr) {
LOGD("test ndk");
return (*env)->NewStringUTF(env,"Test NDK");
}
/**
*回調Java靜態方法
*/
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callJavaCode
(JNIEnv *env, jclass thiz, jstring jstr) {
//得到類的實例對象
jclass clazz = (*env)->FindClass(env,"test/com/example/liaojd/myapplication/CallFromNative");
jmethodID showLog= (*env)->GetStaticMethodID(env, clazz, "showLog","(Ljava/lang/String;)V");
//調用java函數
jstring str =(*env)->NewStringUTF(env, "Hi,I'm From C");
(*env)->CallStaticVoidMethod(env,clazz,showLog,str);
}
/**
* 回調Java實例方法
*/
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_callJavaInstaceCode
(JNIEnv *env, jclass thiz, jstring jstr) {
//得到類的實例對象
jclass clazz = (*env)->FindClass(env,"test/com/example/liaojd/myapplication/CallFromNative");
jmethodID showInstanceLog= (*env)->GetMethodID(env, clazz, "showInstanceLog","(Ljava/lang/String;)V");
//得到一個實例對象
jobject instance = (*env)->AllocObject(env,clazz);
//調用java函數
jstring str =(*env)->NewStringUTF(env, "Hi,I'm From C");
(*env)->CallVoidMethod(env,instance,showInstanceLog,str);
}
/**
* 獲取圖片信息
*/
JNIEXPORT void JNICALL Java_test_com_example_liaojd_myapplication_NdkTest_getBitmapInfo
(JNIEnv *env, jclass obj, jobject jbitmap) {
AndroidBitmapInfo info;
AndroidBitmap_getInfo(env,jbitmap,&info);
LOGD("bitmap width = %d height = %d", info.width, info.height);
}
上面的例子中獲取方法的ID的時候需要傳入方法描述符,在Java中它表示方法的簽名,Java類型簽名映射表如下:
Java類型 | 簽名 |
---|---|
Boolean | Z |
Byte | B |
Char | C |
Short | S |
Int | I |
Long | J |
Float | F |
Double | D |
fully-qualified-class | Lfully-qualified-clas; |
type[] | [type |
method type | (arg-type)ret-type |
用類型簽名映射手工生成的方法描述符是一件非常繁瑣的任務,不一定每次都記住,所以JDK爲我們提供了javap反彙編命令行程序,如下所示:
加載動態庫
static {
System.loadLibrary("native-lib");
}
添加運行的代碼
NdkTest.callFromNativ("callFromNativ");
NdkTest.callJavaCode("callJavaCode");
NdkTest.callJavaInstaceCode("callInstanceCode");
NdkTest.getBitmapInfo(bitmapDrawable.getBitmap());
因爲bitmap.h在libjnigraphics.so中,所以修改CMakeLists.txt文件,如下所示:
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# file are automatically included.
src/main/cpp/main.c)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
find_library( # Sets the name of the path variable.
jnigraphics-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
jnigraphics )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${jnigraphics-lib}
${log-lib} )
涉及到相關的知識點
1.Cmake參考資料
cmake document
2.最新版Android studio關於如何使用c/c++請參考官方文檔
官方使用教程