1. 程式人生 > >Android NDK開發之旅(6):JNI函式完全解析與專案實戰

Android NDK開發之旅(6):JNI函式完全解析與專案實戰

對於基本型別而言,JNI與Java之間的對映是一對一的,比如Java中的int型別直接對應於C/C++中的jint;而對引用型別的處理卻是不同的,JNI把Java中的物件當作一個C指標傳遞到本地函式中,這個指標指向JVM中的內部資料結構,而內部資料結構在記憶體中的儲存方式是不可見的,原生代碼必須通過在JNIEnv中選擇適當的JNI函式來操作JVM中的物件,而這裡的物件是指Java物件,陣列、String。

1. JNI函式完全解析

 在 Android NDK開發之旅(3):詳解JNI資料型別與C/C++、Java之間的互調一文中,我們介紹到JNI根據原始檔的不同(.cpp/.c)提供了兩種呼叫介面,它們的函式原型分別被封裝在結構體_JNIEnv和JNINativeInterface_

,且_JNIEnv又是對JNINativeInterface_的進一步封裝。因此,下面我們只需要對其中的一個進行分析即可,這裡選擇解析JNINativeInterface_結構體中的函式原型。_JNIEnv與JNINativeInterface_的關係如下:

// .cpp原始檔,JNIEnv為結構體_JNIEnv
// .c,JNI為結構體JNINativeInterface
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
typedef const struct JNINativeInterface*
JNIEnv; typedef const struct JNIInvokeInterface* JavaVM; #endif //------------------------------------------------------------------ // .c原始檔JNI函式原型 // 呼叫示例:(*env)->FindClass(env,"java/lang/String"); struct JNINativeInterface { jclass (*FindClass)(JNIEnv*, const char*); jclass (*GetObjectClass)(JNIEnv*
, jobject); ... }; // .cpp原始檔JNI函式原型 // 呼叫示例:env->FindClass("java/lang/String"); struct _JNIEnv { const struct JNINativeInterface* functions; #if defined(__cplusplus) jclass FindClass(const char* name) { return functions->FindClass(this, name); } jobject NewObject(jclass clazz, jmethodID methodID, ...) { va_list args; va_start(args, methodID); jobject result = functions->NewObjectV(this, clazz, methodID, args); va_end(args); return result; } ... #endif /*__cplusplus*/ };
1.1 字串處理

 JNI函式表中提供了兩套字串處理函式,分別對應於unicode、utf-8編碼方式,用於實現jstring型別字串與c/c++字串之間的轉換、獲取jstring型別字串長度以及釋放字串所佔資源。

(1) 函式原型

//-----------------------Unicode編碼-------------------------------//
jstring     (*NewString)(JNIEnv*, const jchar*, jsize);
jsize       (*GetStringLength)(JNIEnv*, jstring);
const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*);
void        (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*);
//-----------------------UTF-8編碼-------------------------------//
// 將char *(c/c++型別)轉換為jstring(Java型別)
jstring     (*NewStringUTF)(JNIEnv*, const char*);
// 將jstring轉換為char*
const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);
// 釋放記憶體資源,與GetStringUTFChars配合使用
void (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*);
// 獲取jstring型別字串長度
jsize (*GetStringUTFLength)(JNIEnv*, jstring);

 關於為什麼要對jstring型別與char *字串進行轉換,是因為jstring型別表示Java層,指向的是JVM記憶體的一個Unicodec編碼格式字串,而c層的char *型別字串編碼格式為UTF-8,因此不能簡單的將jstring當作一個c/c++層字串使用,必須使用JNI函式將jstring轉換為char *型別。當然,如果我們需要返回一個將c/c++層的char*型別返回給Java層,也必須將char *轉換為jstring。

(2) 例項演示:中文亂碼處理
 從前面介紹可知,在c/c++層是不能夠直接將jstring當作char *型別字串使用的,需要藉助JNI函式對其進行轉換。但是,在實際開發中,我遇到這麼一個問題,即當Java層傳下來的jstring型別字串包含中文時,在c/c++層處理時中文會亂碼。因為,中文是GB2312編碼,所以接下來,我們將利用第三方庫iconv解決中文亂碼為例,講解JNI字串處理函式的應用。

#include <iconv.h>
JNIEXPORT void JNICALL Java_com_jiangdg_jnilearning_JNIUitls_getChineseFromC1
        (JNIEnv *env, jobject jobj, jstring j_str){
    // 得到UTF-8格式的位元組陣列資料
    const char* c_str_utf8 = (*env)->GetStringUTFChars(env,j_str,JNI_FALSE);
    // 使用iconv庫將UTF-8轉換為GB2312
	iconv_t cd = iconv_open ("gbk","utf-8");
	if(cd == (iconv_t)-1){
		LOG_E("開啟iconv庫失敗,error = %d",errno);
		return;
	}
	// 轉換漢字編碼格式
	char* c_str_gbk = (char *)malloc(32);
	unsigned int len = 32;
	char *temp = (char *)malloc(32);
	strcpy(temp,c_str_utf8);
	iconv (cd, &temp,&len, &c_str_gbk, &len);
	iconv_close (cd);
	(*env)->ReleaseStringUTFChars(env,j_str,c_str_utf8);
}
1.2 陣列處理

 眾所周知,在Java中陣列是以物件的形式存在的,而在JNI開發中,JNI把Java中的物件當作一個C指標傳遞到本地函式中,這個指標指向JVM中的內部資料結構,而內部資料結構在記憶體中的儲存方式是不可見的。因此,JNI提供了系列函式用於在原生代碼中能夠輕易訪問和操作JVM記憶體中的陣列資料(即java轉c/c++),同時也可以在原生代碼中建立一個數組並對其進行本地賦值(即c/c++轉java),然後返回給Java層。

(1) 函式原型

// 獲取陣列長度
jsize (*GetArrayLength)(JNIEnv*, jarray);
//---------------------------陣列元素為物件------------------------------

jobjectArray (*NewObjectArray)(JNIEnv*, jsize, jclass, jobject);
jobject (*GetObjectArrayElement)(JNIEnv*, jobjectArray, jsize);
void (*SetObjectArrayElement)(JNIEnv*, jobjectArray, jsize, jobject);

//-------------------------陣列元素為基本型別-------------------------
//--------boolean、byte、char、short、int、long、float、double-----------

// 建立指定型別陣列
// 模板:j<型別>Array (*New<型別>Array)(JNIEnv*, jsize);
jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize);
...
jdoubleArray  (*NewDoubleArray)(JNIEnv*, jsize);
// 獲取陣列元素,即將Java層陣列(jbooleanArray)轉換為c/c++層(jboolean*)
// 模板:j<型別>* (*Get<型別>ArrayElements)(JNIEnv*, jbooleanArray, jboolean*)
jboolean* (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*);
...
jdouble* (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*);
// 釋放資源,與Get<型別>ArrayElements成對配合使用
// 模板:void (*Release<型別>ArrayElements)(JNIEnv*,...);
void (*ReleaseBooleanArrayElements)(JNIEnv*, jbooleanArray,jboolean*, jint);
...
void (*ReleaseDoubleArrayElements)(JNIEnv*, jdoubleArray,jdouble*, jint);
// 填充陣列,即將c/c++層陣列(jboolean*)填充到Java層陣列(jbooleanArray)中
// 模板:void (*Get<型別>ArrayRegion(JNIEnv*,...))
void (*GetBooleanArrayRegion)(JNIEnv*, jbooleanArray,jsize, jsize, jboolean*);
...
void (*GetDoubleArrayRegion)(JNIEnv*, jdoubleArray,jsize, jsize, jdouble*);
// 填充陣列,即將const j<型別>*轉換為j<型別>Array中
// 模板:void (*Set<型別>ArrayRegion)(JNIEnv*,...)
void (*SetBooleanArrayRegion)(JNIEnv*, jbooleanArray,jsize, jsize, const jboolean*);
...
void (*SetDoubleArrayRegion)(JNIEnv*, jdoubleArray,jsize, jsize, const jdouble*);

(2) 例項演示
 在Android直播開發之旅(11):從記憶體分佈的角度再談YUV顏色空間一文中,我們介紹到如果需要使用MediaCodec對攝像頭採集的NV21影象資料進行編碼,就必須將NV21轉換為MediaCodec編碼器所支援的顏色格式,否則,編碼輸出就會出現花屏現象。對於YUV顏色格式轉換,雖說在Java層也能夠輕易實現,但由於MediaCodec每秒至少需要處理20幀影象,為了儘量避免因資料處理帶來的推流延遲,對於影象的處理建議放在Native層,因此本例項演示瞭如何利用JNI函式在Native層實現YUV顏色格式轉換。

實現思路:
(1) 通過JNI的GetByteArrayElements函式獲取儲存在JVM記憶體中的陣列資料,並存儲到本地指向的記憶體。需要注意的是,GetByteArrayElements要與ReleaseByteArrayElements配套使用,用於釋放所佔陣列所佔記憶體資源;
(2) 開闢一段記憶體空間,用於快取處理資料,其中YUV4:2:0取樣格式中Y、U、V分量佔比為1:1/4:1/4,每個畫素佔3/2個位元組;
(3) 通過JNI的SetByteArrayRegion函式將快取的資料temp覆蓋到jarray_,以保證jarray_引用指向的資料為處理後的資料;
(4) 使用free()函式釋放快取記憶體。

// Java層native方法
public static native int nativeNV21ToYUV420sp(byte[] data,int width, int height);

// 本地層函式實現
extern "C"
JNIEXPORT jint JNICALL
Java_com_jiangdg_natives_YuvUtils_nativeNV21ToYUV420sp(JNIEnv *env, jclass type, jbyteArray jarray_, jint width, jint height) {
    // 訪問jbyteArray指標指向的資料,將其儲存為本地型別
    jbyte* c_array = env->GetByteArrayElements(jarray_,JNI_FALSE);
    if(c_array == NULL) {
        return -1;
    }
    // sizeof、strlen
    jsize arrayLen = env->GetArrayLength(jarray_);
    // 開闢一段記憶體空間,用於快取處理過程中的資料
    char* temp = (char *)malloc(arrayLen);
    if(temp == NULL) {
        return -1;
    }
    // 分別拷貝Y、U、V分量
    // YYYYYYYY VUVU -> YYYYYYY UVUV
    int yLen = width*height;
    int uLen = yLen/4;
    int i;
    memcpy(temp,c_array,yLen);
    for(i=0;i<uLen;i++) {
        temp[yLen+2*i] = c_array[yLen+2*i+1];
        temp[yLen+2*i+1] = c_array[yLen+2*i];
    }
    // 將temp資料覆蓋到jarray_指標指向的記憶體
    env->SetByteArrayRegion(jarray_,0,arrayLen,(jbyte*)temp);
    // 釋放記憶體資源
    env->ReleaseByteArrayElements(jarray_,c_array,0);
    free(temp);
    return 0;
}
1.3 訪問Java層屬性、方法

 前面說到,JNI把Java中的物件當作一個C指標傳遞到本地函式中,這個指標指向JVM中的內部資料結構,而內部資料結構在記憶體中的儲存方式是不可見的。因此,JNI提供了大量的函式便於我們訪問Java物件的屬性和方法,也包括靜態屬性和靜態方法,甚至允許我們直接在本地層建立一個物件的例項等。
(1) 函式原型

// 根據const char*(即"包名/類名")獲取Java類(jclass )
jclass (*FindClass)(JNIEnv*, const char*);
// 獲取jobject相對應的Java類
jclass (*GetObjectClass)(JNIEnv*, jobject);
// 判斷jobject是否為jclass類的物件
jboolean (*IsInstanceOf)(JNIEnv*, jobject, jclass);
// 判斷兩個jobject是否為同一個物件
jboolean (*IsSameObject)(JNIEnv*, jobject, jobject);
//分配新 Java 物件而不呼叫該物件的任何建構函式。返回該物件的引用
//如果該類為一個介面或抽象類,會丟擲InstantiationException異常
jobject (*AllocObject)(JNIEnv*, jclass);
// 本地建立Java物件
// jclass:要建立的物件對應的類,jclass可通過FindClass()函式獲取;
// jmethodID為構造方法ID,必須通過呼叫GetMethodID() 獲得,且呼叫時的方法名必須為 <init>,而返回型別必須為 void (V);
// 其中,...或va_list或jvalue*為傳入構造方法的引數,且...可為空,va_list為陣列,jvalue為共用體型別
jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...);
jobject (*NewObjectV)(JNIEnv*, jclass, jmethodID, va_list);
jobject (*NewObjectA)(JNIEnv*, jclass, jmethodID, jvalue*);
//-----------------------------------------------------------------------
//---------------------------訪問Java層物件屬性----------------------------
// 獲取java類(jclass)的屬性ID
// 其中,第一個const char*表示屬性名,第二個const char*為屬性型別JNI簽名
jfieldID    (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);
// 本地訪問Java物件屬性,根據屬性變數型別選用相應的JNI函式
// 模板:j<type> (*Get<type>Field)(JNIEnv*,...),其中,jobject為要訪問的物件,jfieldID為屬性ID且通過GetFieldID函式獲得
// 型別還包括:byte、char、short、int、long、float
jobject     (*GetObjectField)(JNIEnv*, jobject, jfieldID);
jboolean    (*GetBooleanField)(JNIEnv*, jobject, jfieldID);
... 
jdouble     (*GetDoubleField)(JNIEnv*, jobject, jfieldID);
// 本地訪問Java物件屬性,根據屬性變數型別選用相應的JNI函式
// 模板:void (*Set<type>Field)(JNIEnv*,...,j<type>),其中,jobject為要訪問的物件,jfieldID為屬性ID且通過GetFieldID函式獲得,j<type>為被賦值的值
// 型別還包括:byte、char、short、int、long、float
void  (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);
void  (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean);
...
void  (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble);

//---------------------------訪問Java層類的屬性----------------------------
// 獲取類屬性的ID
jfieldID (*GetStaticFieldID)(JNIEnv*, jclass, const char*,const char*);
// 本地訪問類的屬性,,根據屬性型別的不同選用相應的JNI函式,其他type還包括byte、char、short、int、long、float
// 模板:j<type> (*Get<Statictype>Field)(JNIEnv*,...)
jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);
jboolean (*GetStaticBooleanField)(JNIEnv*, jclass, jfieldID);
...
jdouble (*GetStaticDoubleField)(JNIEnv*, jclass, jfieldID);
// 本地為類的屬性賦值,根據屬性型別的不同選用相應的JNI函式,其他type還包括byte、char、short、int、long、float
// 模板:void  (*SetStatic<type>Field)(JNIEnv*, ..., j<type>);
void  (*SetStaticObjectField)(JNIEnv*, jclass, jfieldID, jobject);
void  (*SetStaticBooleanField)(JNIEnv*, jclass, jfieldID, jboolean);
...
void (*SetStaticDoubleField)(JNIEnv*, jclass, jfieldID, jdouble);

//-----------------------------------------------------------------------
//-------------------------訪問Java層物件的方法--------------------------
// 獲取Java類的方法ID
// 其中,第一個const char*表示方法名,第二個const char*表示方法JNI簽名
jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 本地訪問Java物件的方法,且方法的返回值為物件
// 其中,...或va_list或jvalue*為傳入方法的引數,且...可為空,va_list為陣列,jvalue為共用體型別,這對應著不同的函式
jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
// 本地訪問Java物件的方法,且方法的返回值為jboolean、jbyte、jchar、jshort、jint、jlong、jfloat、jdouble
// 其中,jobject為Java物件,jmethodID為方法的ID,其他為傳入方法引數
// 模板:j<型別> (*Call<型別>Method)(JNIEnv*, ...)
jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
...
// 本地訪問Java物件方法,且方法無返回值或返回void
void  (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
void  (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
void  (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);

//-------------------------訪問Java層物件父類的方法-----------------------
// // 本地訪問物件父類的方法,返回值為一個物件jobject
jobject (*CallNonvirtualObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
jobject (*CallNonvirtualObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jobject (*CallNonvirtualObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
// 本地訪問物件父類的方法,返回值為jboolean、jbyte、jchar、jshort、jint、jlong、jfloat、jdouble
jboolean (*CallNonvirtualBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
jboolean (*CallNonvirtualBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jboolean (*CallNonvirtualBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
...
// 本地訪問物件父類的方法,返回值為void
void  (*CallNonvirtualVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
void  (*CallNonvirtualVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
void  (*CallNonvirtualVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);

//-------------------------訪問Java層類的靜態方法-----------------------
// 獲取靜態方法ID
jmethodID  (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
// 訪問靜態方法,根據不同的返回值和傳入引數的方式選擇對應JNI函式
// 返回值為物件
jobject (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...);
jobject (*CallStaticObjectMethodV)(JNIEnv*, jclass, jmethodID, va_list);
jobject (*CallStaticObjectMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);
// 返回值為基本型別,還包括byte/char/short/int/long/float/double
// 模板:j<type>  (*CallStatic<type>Method)(JNIEnv*,...);
jboolean  (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...);
jboolean  (*CallStaticBooleanMethodV
            
           

相關推薦

Android NDK開發(6)JNI函式完全解析專案實戰

對於基本型別而言,JNI與Java之間的對映是一對一的,比如Java中的int型別直接對應於C/C++中的jint;而對引用型別的處理卻是不同的,JNI把Java中的物件當作一個C指標傳遞到本地函式中,這個指標指向JVM中的內部資料結構,而內部資料結構在記憶體

Android直播開發(4)MP3編碼格式分析lame庫編譯封裝

轉載請宣告出處:http://blog.csdn.net/andrexpert/article/77683776 一、Mp3編碼格式分析       MP3,全稱MPEG Audio Layer3,是一種高效的計算機音訊編碼方案,它以較大的壓縮比(1:10至1:12)將音

Android直播開發(12)初探FFmpeg開源框架

1. FFmpeg介紹與裁剪 1.1 FFmpeg簡介  FFmpeg(Fast forword mpeg,音視訊轉換器)是一個開源免費跨平臺的視訊和音訊流方案,它提供了錄製/音視訊編解碼、轉換以及流化音視訊的完整解決方案。ffmpeg4.0.2原始碼目錄結構如下: 目錄說明:

Android直播開發(13)使用FFmpeg+OpenSL ES播放PCM音訊

在Android直播開發之旅(12):初探FFmpeg開源框架一文中,我們詳細介紹了FFmpeg框架的架構、音視訊相關術語以及重要的結構體。為了能夠對這些重要的結構體有個深入的理解,本文將在此基礎上,利用FFmpeg解析rtsp資料流以獲取AAC音訊資料,再對AAC進行解碼為PC

Android直播開發(7)Android視訊直播核心技術(架構)詳解

(轉載請宣告出處:http://blog.csdn.net/andrexpert/article/details/76919535) 一、直播架構解析      目前主流的直播架構中主要有兩種方案,即流媒體轉發、P2P。流媒體轉發,是一種在視訊直播中以流的方式將連續的音、

Android直播開發(10)AndroidUSBCamera,UVCCamera開發通用庫

    AndroidUSBCamera基於[saki4510t/UVCCamera](https://github.com/saki4510t/UVCCamera)開發,該專案對USB Camera(UVC裝置)的使用和視訊資料採集進行了高度封裝,能夠幫助開發者通過幾個簡單

Android直播開發(9)OkCamera,Android 相機應用開發通用庫

OkCamera,Android 相機應用開發通用庫 轉載請宣告出處:http://blog.csdn.net/andrexpert/article/details/79302576     明天就可以回家過年了,有點小激動,於是乎趕緊寫篇文章壓壓驚!本文主要介紹最近

Android直播開發(2)深度解析H.264編碼原理

 (碼字不易,轉載請申明出處:http://blog.csdn.net/andrexpert/article/details/71774230 ) 前 言     在學習H.264編碼之前,我們先了解一下在視訊直播的過程中,如果Camera採集的YUV影象不做任何處理

Android開發3android架構

通過 圖集 例如 sqlit 組件 mil 大小 簡化 .html 引言 通過前面兩篇: Android 開發之旅:環境搭建及HelloWorld Android 開發之旅:HelloWorld項目的目錄結構 我們對android有了個大

Android開發1環境搭建及HelloWorld

lan 及其 其它 ply 新項目 bsp 驗證 for 對話框 ——工欲善其事必先利其器 引言 本系列適合0基礎的人員,因為我就是從0開始的,此系列記錄我步入Android開發的一些經驗分享,望與君共勉!作為Android隊伍中的一個新人的

Android-NDK開發基礎--Android JNI有關Java類命名方式

 (Ljava/lang/String;I)V   其中本句  I = IntegerB = ByteS = ShortC = CharLXXX; = L加上類名   3. 在JNI下面,我們常用的命名方式:     static JavaVM *g_VM;   //全

Android NDK開發Hello-JNI!

Android NDK 是指Android Native Development Kit,也被Google稱為“NDK”。Android程式執行在Dalvik虛擬機器中, NDK允許使用者使用類似C / C++之類的原生程式碼語言執行部分程式。包括了: 從C / C++生

Android-NDK開發基礎--Android JNI開發高階篇(JNI中的常用方法)

有關Android JNI開發中比較強大和有用的功能就是從JNI層建立、構造Java的類或執行Java層的方法獲取屬性等操作。    一、類的相關操作    1. jclass FindClass(JNIEnv *env, const char *name);  查詢類   

Android NDK開發引入第三方庫

在Android開發中我們經常要把一些比較看重安全或者計算效率的東西通過JNI呼叫C/C++程式碼來實現,如果需要實現的功能簡單或者你的C/C++程式碼能力比較強,但是目前還是有很多功能強大的第三方庫的,比如openssl、FFmpeg等,呼叫這些第三方實現顯然比重複造輪子實際的多。 本教程適合將原始的動態

AndroidStudio2.2 Preview3中NDK開發CMake和傳統 JNI在目錄結構和配置檔案上的區別

 自從AndroidStudio更新到2.2,就有了CMake和傳統JNI兩種開發NDK的方法,主要就是在目錄結構和build.gradle上的區別,下面我們將分別介紹目錄區別和build.gradle種配置的區別(提示:在第一次用CMake時,最好在新建專案時勾選Include C++

Android NDK開發CMake

知之為知之,不知為不知 哇!(先來個王者之哇助助興),最近的專案一直用到Android NDK,簡直頭皮發麻,每次底層出現問題,都要找同事幫忙,甚是尷尬,於是看一些帖子,稍微整理了一下,做個小筆記,同時也分享一下前人之經驗.不說了,開始進入正題. Android開發環境 工具:And

Android NDK開發C語言基礎及指標①

我們知道 , Android系統是基於linux開發 , 採用的是linux核心 , Android APP開發大部分也要和系統打交道 , 只是Android FrameWork 幫我們遮蔽了系統操作 , 我們從Android 系統的分成結構可以看出 , Android FrameWork是通過JNI與底層的

Android Studio——Android Bitmap開發--基本操作

原文連結:http://blog.csdn.net/weihan1314/article/details/8012283 1 Bitmap載入方式 在介紹Bitmap--OOM 異常時,首先介紹一下Bitmap有哪幾種載入方式。通常Bitmap的載入方式有Reso

定製Android系統開發八——實現從JNI到Java的回撥

前面已經實現了APP->xxxManager->xxxManagerService->jni的函式呼叫,這篇博文就來實現jni->xxxManagerService的回撥。 使用環境 我先說一下我的應用環境吧。我在有一個對裝置節點

Android NDK開發從環境搭建到Demo級十步流

寫在正文之前: 幾個月沒有更新部落格,感覺有點生疏了,所以說不能斷,一斷人就懶。 其實這幾個月也並不是什麼事也沒有做,俺可是時刻想著今年的任務呢,10本書,30篇博文…,這幾個月間斷性的也是在學習中,學H5,學設計模式,以及NDK JNI開發等等。 學習J