1:配置NDK環境變量,將ndk根目錄配置到path當中。java
2:新建Android工程,在local.properties中配置ndk路徑,好比:android
ndk.dir=H\:\\opt\\android-sdk-windows19-24\\ndk-bundle
在gradle.properties文件中加上:windows
android.useDeprecatedNdk=true(爲了適配低版本的ndk,不加編譯可能會不過),Android Studio3.0以後改爲
android.useDeprecatedNdk=true
3:新建Jni類,並寫好本地方法,好比:app
package com.zhy.youku; /** * 生成頭文件以前要運行 set classpath=E:\Android\Studio_App\Jni_Demo\app\src\main\java * Created by kzp on 2017/3/7. */ public class Jni { public native int add(int x, int y); }
4:在cmd中,到工程的java目錄(src\main\java)執行 javah com.zhy.youku.Jni,則會生成一個頭文件,如:ide
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_zhy_youku_Jni */ #ifndef _Included_com_zhy_youku_Jni #define _Included_com_zhy_youku_Jni #ifdef __cplusplus extern "C" { #endif /* * Class: com_zhy_youku_Jni * Method: add * Signature: (II)I */ JNIEXPORT jint JNICALL Java_com_zhy_youku_Jni_add (JNIEnv *, jobject, jint, jint); #ifdef __cplusplus } #endif #endif
新建一個文件夾,取名jni,並將編譯好的頭文件剪切進去。(生成頭文件的另外一個方法:make後在build\intermediates\classes\debug目錄下執行javah -classpath . -jni 包名.類名)便可生成。gradle
5:在jni文件夾中,新建一個C的資源文件,文件名字任意取,並include頭文件, 完成C方法,如圖:ui
#include "com_zhy_youku_Jni.h" JNIEXPORT jint JNICALL Java_com_zhy_youku_Jni_add (JNIEnv *env, jobject obj, jint jint1, jint jint2){ return jint1 + jint2; }
6:在項目的build.gradle文件中添加ndk配置:this
apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.zhy.youku" minSdkVersion 15 targetSdkVersion 25 versionCode 1 versionName "1.0" ndk{ moduleName "jni_test" //動態庫的名稱 abiFilters "armeabi-v7a", "x86", "armeabi" //支持的CPU版本 ldLibs "log" //增長打印信息 } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:25.2.0' }
7:最後new Jni(),就能夠調用C方法:(不要忘了在調用以前要動態加載本地庫,庫名要和build.gradle中配置的名字相同);spa
static { System.loadLibrary("jni_test"); }
調用:debug
Log.e("m_tag", "result=" + new Jni().add(1,1));
正確打印結果:03-07 14:35:50.186 18069-18069/com.zhy.youku E/m_tag: result=2。
二:上面講的是java調用C的過程,下面將的是C經過java的反射機制調用java類當中的方法的過程,生成頭文件的方法和上面是同樣的,不一樣的是C方法中實現步驟的不一樣。
1:Jni文件夾爲:
package zhy.ccalljava; import android.util.Log; /** * Created by kzp on 2017/3/1. */ public class Jni { static { System.loadLibrary("ccalljava"); } /** * 當執行這個代碼的時候,讓C代碼調用 add(int x, int y) */ public native void callbackAdd(); /** * 當執行這個代碼的時候,讓C代碼調用 helloFromJava() */ public native void callbackHelloFromJava(); /** * 當執行這個代碼的時候,讓C代碼調用 printString() */ public native void callbackPrintString(); /** * 當執行這個代碼的時候,讓C代碼調用靜態方法 sayHello(String s)() */ public native void callbackSayHello(); public int add(int x, int y) { Log.e("m_tag", "add() x=" + x + " y=" + y); return x + y; } public void helloFromJava() { Log.e("m_tag", "helloFromJava()"); } public void printString(String s) { Log.e("m_tag","C中輸入的:" + s); } public static void sayHello(String s){ Log.e("m_tag", "我是java代碼中的JNI." + "java中的sayHello(String s)靜態方法,我被C調用了:"+ s); } }
2:C的實現步驟爲:
// // Created by kzp on 2017/3/1. // //獲取java方法簽名:在build->intermediates->classes->debug 目錄下 javah -s 報名.類名 #include "zhy_ccalljava_Jni.h" #include <stdlib.h> #include <stdio.h> #include <android/log.h> #define LOG_TAG "m_tag" //增長打印 app.gradld中也要配置 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) /** * add(int x, int y) */ JNIEXPORT void JNICALL Java_zhy_ccalljava_Jni_callbackAdd(JNIEnv *env, jobject obj){ //獲得字節碼 jclass jclazz = (*env)->FindClass(env, "zhy/ccalljava/Jni"); //獲得方法 (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); //參數:env, 類, 方法名, 方法簽名 jmethodID methodId = (*env)->GetMethodID(env, jclazz, "add", "(II)I"); //實例化該類 jobject jobject1 = (*env)->AllocObject(env, jclazz); //調用方法 (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...); jint value = (*env)->CallIntMethod(env, jobject1, methodId, 1, 1); //成功調用 LOGE("value=%d\n", value); } /** * helloFromJava() */ JNIEXPORT void JNICALL Java_zhy_ccalljava_Jni_callbackHelloFromJava (JNIEnv *env, jobject obj){ jclass jclazz = (*env)->FindClass(env, "zhy/ccalljava/Jni"); jmethodID methodId = (*env)->GetMethodID(env, jclazz, "helloFromJava", "()V"); jobject jobject1 = (*env)->AllocObject(env, jclazz); (*env)->CallVoidMethod(env, jobject1, methodId); } /** * 讓C代碼調用printString(String s) */ JNIEXPORT void JNICALL Java_zhy_ccalljava_Jni_callbackPrintString (JNIEnv *env, jobject obj){ jclass jclazz = (*env)->FindClass(env, "zhy/ccalljava/Jni"); jmethodID methodId = (*env)->GetMethodID(env, jclazz, "printString", "(Ljava/lang/String;)V"); jobject jobject1 = (*env)->AllocObject(env, jclazz); jstring jstring1 = (*env)->NewStringUTF(env, "i am ard"); (*env)->CallVoidMethod(env, jobject1, methodId, jstring1); } /** * 讓C代碼調用sayHello(String s) * 該方法是靜態的 */ JNIEXPORT void JNICALL Java_zhy_ccalljava_Jni_callbackSayHello (JNIEnv *env, jobject obj){ jclass jclazz = (*env)->FindClass(env, "zhy/ccalljava/Jni"); jmethodID methodId = (*env)->GetStaticMethodID(env, jclazz, "sayHello", "(Ljava/lang/String;)V"); //jobject jobject1 = (*env)->AllocObject(env, jclazz); sayHello方法是靜態的 此步驟省掉 jstring jstring1 = (*env)->NewStringUTF(env, "i am static mothod"); (*env)->CallStaticVoidMethod(env, jclazz, methodId, jstring1); }
3:在MainActivity中調用的步驟爲:
package zhy.ccalljava; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ Jni jni; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); jni = new Jni(); findViewById(R.id.add).setOnClickListener(this); findViewById(R.id.string_void).setOnClickListener(this); findViewById(R.id.print).setOnClickListener(this); findViewById(R.id.static_hello).setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.add: jni.callbackAdd(); break; case R.id.string_void: jni.callbackHelloFromJava(); break; case R.id.print: jni.callbackPrintString(); break; case R.id.static_hello: jni.callbackSayHello(); break; } } }
補充:獲取java方法簽名:在build->intermediates->classes->debug 目錄下 javah -s 報名.類名
在C方法中打印log信息的方法:1;導庫文件
#include <android/log.h> #define LOG_TAG "m_tag" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
2;在build.gradle的ndk配置中加log,如:
apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "zhy.ccalljava" minSdkVersion 17 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk{ moduleName "ccalljava" ldLibs "log" } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.1.0' testCompile 'junit:junit:4.12' }
3;打印信息
LOGE("value=%d\n", value);