android下JNI開發--02

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頭文件
    • ⑤ 調用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代碼 聲明本地方法 用關鍵字 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
  • //可選的參數 回調方法要傳的數據
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章