c基本語法
- #include import stdlib.h stdio.h
- system
- C基本數據類型 C沒有byte boolean 0非0表示false true
- char c1字節 long 4字節
- signed unsigned 修飾整形變量 有符號無符號
- sizeof 取出類型所佔字節數
- C 輸出函數 printf (“輸出的內容+佔位符”,變量)
- 佔位符跟變量類型匹配
- C的字符串 字符數組 {手動加上結束符 ‘\0’} char cstr[] = “abcd”;
- char* cstr = “abcd”; “%s”
- 輸入函數 scanf(“佔位符”,內存地址); &取地址符
- 內存地址 計算機中一般用16進制數來表示內存地址
- 指針 int* p; int 變量來保存一個地址(32位系統)
- int i; int* p = &i; p &p *p
- 野指針 指針類型要匹配 int* 指向int變量地址
- 值傳遞 引用傳遞
- 指針和數組之間的關係
- 多級指針
- 棧內存 堆內存
- 靜態內存分配 malloc free realloc
- 結構體 struct Student
- 結構體長度 大於等於所有變量長度的和 是最大的那個變量的長度的整數倍
- 函數指針 返回值類型(*指針名字)(參數)
- 結構體的指針 (*stup).age stup->age;
- 聯合體 枚舉
- typedef
交叉編譯
- 在一個平臺下編譯出另一個平臺下可以運行的本地代碼
- cpu平臺 x86 arm mips
- 操作系統平臺 windows linux mac os unix
原理 在一個平臺下模擬另一個平臺的特點去編譯本地代碼
NDK native develop kit SDK
- NDK 目錄結構
- docs 幫助文檔
- platforms 根據不同的android版本號分文件夾
- include 頭文件
- lib 谷歌提供的做jni開發可以用到的庫
- samples 谷歌提供的樣例工程 供參考
- sourcese jni相關源代碼
- build->tools .sh文件 linux平臺下的批處理文件 交叉編譯時會自動調用
- ndk-build.cmd
- CDT 高亮C的關鍵字 代碼提示
JNIHElloWORLD
- jni開發流程
java native interface
- ①寫java代碼 聲明本地方法 用關鍵字 native 本地方法不用實現 具體的實現在C代碼中
- ② 創建jni目錄 在項目的根目錄下創建
③ 創建Android.mk linux下的makefile文件
向編譯系統描述一下 我要編譯的代碼在哪兒 生成一個叫什麼名字的文件
* LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello #System.loadlibrary("hello") LOCAL_SRC_FILES := hello.c #.c源文件的名字 include $(BUILD_SHARED_LIBRARY)
- ④ 創建C源碼 本地函數名的命名規則 本地函數命名規則 Java_包名類名本地方法名
- //JNIEnv* env env 是JNIEnv 的一級指針 env就是結構體 JNINativeInterface的二級指針
//(**env).函數指針 (*env)->函數指針
//JNIEnv 是結構體 JNINativeInterface的一級指針
//結構體 JNINativeInterface定義了大量的函數指針 - //jobject thiz 那個類調用的本地函數 這個thiz 就是這個類的對象 在這個例子中 thiz 指的就是Mainactivity的對象
- 必須導入 jni.h頭文件
- //JNIEnv* env env 是JNIEnv 的一級指針 env就是結構體 JNINativeInterface的二級指針
- ⑤ 調用ndk-build編譯源代碼 到項目根目錄下運行ndk-build
- ⑥ java代碼中 調用System.loadlibrary(“”)
- jni開發常見錯誤
- 本地方法沒有找到 java.lang.UnsatisfiedLinkError: Native method not found:
- 本地方法名寫錯
- 避免寫錯 javah生成頭文件
- jdk1.7以上 到項目/src目錄下去運行 生成的頭文件就在src目錄下
- jdk1.6 到項目/bin/classes 目錄下運行javah 生成的頭文件在 /bin/classes去找
- javah +聲明本地方法的類的全類名
- 忘記加載動態鏈接庫 沒有調用
- System.loadLibrary(“hello”);
- 本地方法名寫錯
- 找動態鏈接庫返回空 java.lang.UnsatisfiedLinkError: ….. findLibrary returned null
- System.loadLibrary(“hello”); 動態鏈接庫的名字寫錯
- 沒有編譯出對應平臺的.so文件 需要手動創建 Application.mk 指定
- APP_ABI := armeabi x86
- APP_PLATFORM := android-14
- 本地方法沒有找到 java.lang.UnsatisfiedLinkError: Native method not found:
簡便開發流程
- ①寫java代碼 聲明本地方法 用關鍵字 native 本地方法不用實現 具體的實現在C代碼中
- ② 添加本地支持 右鍵單擊項目->android tools->add native surrport 添動態鏈接庫的名字
- 如果發現finish不能點擊 需要配置NDK目錄(每一個工作空間只需要配置一次NDK目錄)
- window->preferences->android->ndk 指定一下ndk解壓的目錄
- ③ jni目錄創建好之後 會有.cpp的源文件 Android.mk如果需要些.c文件 修改擴展名,修改Android.mk, Application.mk 需要手動創建 如果是x86的模擬器 需要創建Application.mk
- ④ javah生成頭文件
- ⑤ 解決CDT插件報錯的問題 右鍵單擊項目->properties->c/c++ general->paths and symbols->includes選項卡->add…->File system->找到ndk解壓目錄 ->platforms文件夾 找到項目支持的最小版本文件夾下的include目錄 指定進來
- ⑥ 編寫C代碼 運行之前不要忘記 java中System.loadLibrary(“hello”);
C代碼中打log
Android.mk文件增加以下內容
LOCAL_LDLIBS += -llog
# 加載android提供的.so庫 如果加載liblog.so
#LDLIBS load librarys的意思 -l就是加載的意思
C代碼中增加以下內容
#include <android/log.h>
#define 是C的宏定義 可以給 字符串 和函數起別名
#define LOG_TAG "System.out"
//給__android_log_print函數起別名 第一參數 有限及 第二個參數打log的TAG
//LOGD 就是打印優先級是DEBUG的LOG 用法跟printf一樣
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
C回調java
- ①拿到字節碼對象
- // jclass (FindClass)(JNIEnv, const char*);
- //第二個參數 要回調的java類的路徑com/itheima/Ccallback/JNI
- ②拿到方法
- //第二個參數 剛創建的字節碼對象
- //第三個參數 要回調的java方法名 第四個參數 方法簽名
- //如何獲取方法簽名 javap命令 項目/bin/classes目錄下運行javap -s 要獲取方法簽名的類的全類名
- //jmethodID (GetMethodID)(JNIEnv, jclass, const char*, const char*);
- ③通過字節碼對象獲取到java對象(可選)
- //當回調方法跟本地方法沒有聲明到一個類中就要創建java對象
- //jobject (AllocObject)(JNIEnv, jclass); jclass 剛創建的字節碼對象
- //需要注意的是 如果回調的方法在Activity中 不能自己new activity
- ④調用方法
- //void (Call***Method)(JNIEnv, jobject, jmethodID, …);
- //根據返回值的類型選擇不同的函數
- //第二個參數 回調的方法所在的java對象 第三個參數剛創建的java方法對應的jmethodID
- //可選的參數 回調方法要傳的數據