JNI,NDK

jni的調用過程
1)安裝和下載Cygwin,下載Android NDK
2)在ndk項目中JNI接口的設計
3)使用C/C++實現本地方法
4)JNI生成動態連接庫.so文件
5)將動態連接庫複製到java工程,在java工程中調用,運行java工程便可java

NDKlinux

1.NDK是一系列工具的集合,幫助開發者迅速的開發C/C++的動態庫,並能自動將so和java應用打成apk包android

2.NDK集成了交叉編譯器,並提供了相應的mk文件和隔離cpu、平臺等的差別,開發人員只需簡單的修改mk文件就能夠建立出sowindows

交叉編譯
  在一個平臺下,編譯出另外一個平臺可以執行的二進制的代碼
  平臺:windows,mac os,linux
  處理器:x86,arm,mips
交叉編譯的原理
  源代碼->編譯->連接->可執行程序
  模擬其餘平臺的特性
交叉編譯的工具鏈
  多個工具的集合,一個工具使用完後接着調用下一個工具數組

常見工具
  NDK:native developement kit:開發jni必備,就是模擬其餘平臺特性來編譯代碼的工具
  CDT:C/C++ developement tools:高亮顯示c語言關鍵字
  cygwin:一個模擬器,能夠再windows下運行linux指令架構

NDK目錄結構
  docs:幫助文檔
  build/tools:linux的批處理文件
  platforms:編譯c代碼須要使用的頭文件和類庫
  prebuilt:預編譯使用的二進制可執行文件
  sample:jni的使用例子
  source:ndk的源碼
  toolchains:工具鏈
  ndk-build.cmd:編譯打包c代碼的一個指令ide

* 使用C語言實現本地方法函數

1. 在項目根目錄下建立jni文件夾
2. 在jni文件中建立一個c文件
3. 在java代碼中,建立一個本地方法helloFromC工具

//native關鍵字
public native String helloFromC();

4. 在jni中定義函數實現這個方法,函數名必須爲ui

//返回值 報名_類名_方法名(參數參照例子)
jstring Java_com_itheima_helloworld1_MainActivity_helloFromC(JNIEnv* env, jobject obj)

5. 返回一個字符串,用c定義一個字符串

char* cstr = "hello from c";

6. 把c的字符串轉換成java的字符串

jstring jstr = (*env)->NewStringUTF(env, cstr); return jstr;

7. 在jni中建立Android.mk文件
8. 在c文件中添加<jni.h>頭文件
9. 在jni文件夾下執行ndk-build.cmd指令
10. java代碼中加載so類庫,調用本地方法(so是C語言的類庫)

static{ //加載打包完畢的so類庫
    System.loadLibrary("hello"); }

代碼

MainActivity

public class MainActivity extends Activity { static{ //加載打包完畢的so類庫
        System.loadLibrary("hello"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View v){ Toast.makeText(this, helloFromC(), 0).show(); } //定義一個本地方法,方法體由c語言實現
    public native String helloFromC(); }

Hello.c

#include <stdio.h> #include <stdlib.h> #include <jni.h> jstring Java_com_itheima_helloworld1_MainActivity_helloFromC(JNIEnv* env, jobject obj){ //c語言的字符串
    char* cstr = "hello from c"; //把C語言的字符串轉換成java的字符串 // jstring (*NewStringUTF)(JNIEnv*, const char*); // jstring jstr = (*(*env)).NewStringUTF(env, cstr);
    jstring jstr = (*env)->NewStringUTF(env, cstr); return jstr; }

Android.mk

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) #編譯生成的文件的類庫叫什麼名字 LOCAL_MODULE := hello #要編譯的c文件 LOCAL_SRC_FILES := Hello.c include $(BUILD_SHARED_LIBRARY)

* 實現兩個數相加

public class MainActivity extends Activity { static{ System.loadLibrary("hello"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View v){ Toast.makeText(this, "3+5的和爲" + add(3, 5), 0).show(); } public native int add(int i, int j); }

Android.mk

 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello LOCAL_SRC_FILES := Hello.c include $(BUILD_SHARED_LIBRARY)

Hello.c

#include <jni.h> jint Java_com_itheima_helloworld2_MainActivity_add(JNIEnv* env, jobject obj, jint i, jint j){ return i + j; }

Application.mk

APP_ABI := all //支持arm、mips、x86等全部架構

* javah
  1.7:在src目錄下執行javah 包名.類名
  1.6:在bin/classes目錄下執行

而後工程刷新,複製裏面已經自動生成的方法名,就能夠粘貼到c文件中使用

* 配置NDK路徑

perference->android->ndk

右鍵->android tools->add native support能夠自動生成jni和mk文件

關聯源碼:properties->C/C++ general->paths and symbols(源碼路徑:ndk\platforms\android-18\arch-arm\usr\include)

* 傳遞整形數組

public class MainActivity extends Activity { static{ System.loadLibrary("hello"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } int[] arr = {1,2,3,4,5}; public void click(View v){ arrayEncode(arr); for (int i : arr) { System.out.println(i); } } public native void arrayEncode(int[] arr); }

Android.mk

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello LOCAL_SRC_FILES := hello.c include $(BUILD_SHARED_LIBRARY)

hello.c

#include <jni.h> JNIEXPORT void JNICALL Java_com_itheima_array_MainActivity_arrayEncode (JNIEnv * env, jobject obj, jintArray jintarr){ //拿到整型數組的長度以及第0個元素的地址 //jsize (*GetArrayLength)(JNIEnv*, jarray);
    int length = (*env)->GetArrayLength(env, jintarr); //jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
    int* arrp = (*env)->GetIntArrayElements(env, jintarr, 0); int i; for(i = 0;i < length; i++){ *(arrp + i) += 10; } }

* 調用美圖秀秀的本地方法(只需複製粘貼美圖秀秀的so文件,並不須要建立jni文件)

public class MainActivity extends Activity { private Bitmap bm; private ImageView iv; static{ System.loadLibrary("mtimage-jni"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bm = BitmapFactory.decodeFile("sdcard/aneiyi.jpg"); iv = (ImageView) findViewById(R.id.iv); iv.setImageBitmap(bm); } public void click(View v){ int width = bm.getWidth(); int height = bm.getHeight(); //用於保存全部像素信息
        int[] pixels = new int[width * height]; //獲取圖片的像素顏色信息,保存至pixels
        bm.getPixels(pixels, 0, width, 0, 0, width, height); JNI jni = new JNI(); //arg0:保存了全部像素顏色信息的數組 //arg1:圖片的寬 //arg2:圖片的高 //此方法是經過改變pixels的像素顏色值來實現美化效果
 jni.StyleLomoC(pixels, width, height); Bitmap bmNew = Bitmap.createBitmap(pixels, width, height, bm.getConfig()); iv.setImageBitmap(bmNew); } }

* 在C代碼中打印log日誌

第一步:Android.mk文件增長LOCAL_LDLIBS += -llog

第二步:C代碼中增長

#include <android/log.h>
#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, __VA_ARGS__)

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__) LOGI("info\n"); LOGD("debug\n");

 * 在C中用反射調用JAVA中方法

public class MainActivity extends Activity { static{ System.loadLibrary("hello"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View v){ helloC(); } public native void helloC(); public void show(String message){ Builder builder = new Builder(this); builder.setTitle("БъЬт"); builder.setMessage(message); builder.show(); } }

Android.mk

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_LDLIBS += -llog LOCAL_MODULE := hello LOCAL_SRC_FILES := hello.c include $(BUILD_SHARED_LIBRARY)

hello.c

#include <jni.h> #include <android/log.h>
#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) JNIEXPORT void JNICALL Java_com_itheima_ccalljava_MainActivity_helloC (JNIEnv * env, jobject obj){ LOGD("hello!"); LOGI("hello!"); //jclass (*FindClass)(JNIEnv*, const char*);
    jclass clazz = (*env)->FindClass(env, "com/itheima/ccalljava/MainActivity"); //jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
    jmethodID methodID = (*env)->GetMethodID(env, clazz, "show", "(Ljava/lang/String;)V"); //void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
    (*env)->CallVoidMethod(env, obj, methodID, (*env)->NewStringUTF(env, "是時候再黑一波小志了")); }
相關文章
相關標籤/搜索