Android studio 中使用Jni

来源:互联网 发布:seajs 源码分析 玉伯 编辑:程序博客网 时间:2024/05/22 12:40

在使用Jni之前,我们需要对android studio进行一些配置:

有网的时候:在设置 - plugin - Android NDK Support 勾选--install plugin for disk
然后再打开设置---system setting--android SDK --sdk tool ---勾选上NDK
没网的时候:直接下载下来并进行解压
下载链接:点击打开链接
一、环境配置:
1、解压ndk到指定目录(该目录不能出现中文和空格)
修改系统的环境变量,在path里加上D:\soft\ndk\android_ndk_r10e;
2、创建Project
1)在local.properties文件里添加ndk路径ndk.dir=D\:\\soft\\ndk\\android_ndk_r10e
2)在build里添加
      ndk{         moduleName "Hello"  //可根据自己取,表示.so文件的前缀         ldLibs "log"  //打印日志         abiFilters "armeabi", "armeabi-v7a", "x86"  //指定CPU        }
注意://如果你编写的.c文件include的时候报红,在build.gradle里添加
        sourceSets.main {           jni.srcDirs 'src/main/source'          }
最后build.gradle的代码:
android {    compileSdkVersion 23    buildToolsVersion "23.0.2"    defaultConfig {        applicationId "com.suixi.ndkproject"        minSdkVersion 15        targetSdkVersion 23        versionCode 1        versionName "1.0"        ndk{            moduleName "javaCallC"            ldLibs "log"  //打印日志            abiFilters "armeabi", "armeabi-v7a", "x86"        }    }    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:23.2.1'    compile 'com.jakewharton:butterknife:6.0.0'}
3、兼容老的NDK
在gradle.properties里添加:
android.useDeprecatedNdk=true

二、若要在C语言中进行LOG日志
在build.gradle
    ndk{       moduleName "cCallJava"       ldLibs "log"  //打印日志       abiFilters "armeabi", "armeabi-v7a", "x86"       }

在.c文件中添加如下代码
   #include <android/log.h>   #define LOG_TAG "linzhenxiang"   #define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)   #define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)   #define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)<span style="font-family:Consolas;background-color:#ffffff"></span>

三、编写java调用c语言的方式

1、写一个java类JNI(类名可自取),用于写native代码
public class JNI {    public native String sayHello();//简单的调用    public native String sayAddHello(String s);//字符串拼接    public native int add(int x,int y);//加法运算    public native int[] increaseArray(int[] arr );//给数组的每个元素都增加10    public native int checkPwd(String s);//检查密码是否正确,并返回值}
2、动态的生成你所需要的C的头文件的两种方法
1)、在\NDKDEMO\app\src\main\java
执行命令:javah com.suixi.ndkproject.JNI(包名+类名)
2)、在studio底部中的terminal 里执行javah javah com.suixi.ndkproject.JNI

会自动生成如下的代码:
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_suixi_ndkproject_JNI */#ifndef _Included_com_suixi_ndkproject_JNI#define _Included_com_suixi_ndkproject_JNI#ifdef __cplusplusextern "C" {#endif/* * Class:     com_suixi_ndkproject_JNI * Method:    sayHello * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_suixi_ndkproject_JNI_sayHello  (JNIEnv *, jobject);/* * Class:     com_suixi_ndkproject_JNI * Method:    sayAddHello * Signature: (Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_suixi_ndkproject_JNI_sayAddHello  (JNIEnv *, jobject, jstring);/* * Class:     com_suixi_ndkproject_JNI * Method:    add * Signature: (II)I */JNIEXPORT jint JNICALL Java_com_suixi_ndkproject_JNI_add  (JNIEnv *, jobject, jint, jint);/* * Class:     com_suixi_ndkproject_JNI * Method:    increaseArray * Signature: ([I)[I */JNIEXPORT jintArray JNICALL Java_com_suixi_ndkproject_JNI_increaseArray  (JNIEnv *, jobject, jintArray);/* * Class:     com_suixi_ndkproject_JNI * Method:    checkPwd * Signature: (Ljava/lang/String;)I */JNIEXPORT jint JNICALL Java_com_suixi_ndkproject_JNI_checkPwd  (JNIEnv *, jobject, jstring);#ifdef __cplusplus}#endif#endif
3、在java中右键新建JniFodler,将上一步生成的.h文件移入改文件夹中

4、rebuild Project 下,会在build-->intermediates生成ndk文件夹


5、在JNI类下加载动态链接库
    public class JNI {    {        System.loadLibrary("javaCallC");//动态加载。so文件,只要在用之前加载就成,不一定在这个类里加载    }    public native String sayHello();//简单的调用    public native String sayAddHello(String s);//字符串拼接    public native int add(int x,int y);//加法运算    public native int[] increaseArray(int[] arr );//给数组的每个元素都增加10    public native int checkPwd(String s);//检查密码是否正确,并返回值   }
6、在jni文件夹下新建test.c文件,进行代码编写

#include "test.h"#include "com_suixi_ndkproject_JNI.h"#include <stdio.h>#include <stdlib.h>#include <android/log.h>#include <string.h>#define LOG_TAG "linzhenxiang"//打印日志的别名,可自己去#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)//jstring to char*  jString 转换成 char*指针char *jstringTochar(JNIEnv *env, jstring jstr) {    char *rtn = NULL;    jclass clsstring = (*env)->FindClass(env, "java/lang/String");    jstring strencode = (*env)->NewStringUTF(env, "utf-8");    jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");    jbyteArray barr = (jbyteArray) (*env)->CallObjectMethod(env, jstr, mid, strencode);    jsize alen = (*env)->GetArrayLength(env, barr);    jbyte *ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);    if (alen > 0) {        rtn = (char *) malloc(alen + 1);        memcpy(rtn, ba, alen);        rtn[alen] = 0;    }    (*env)->ReleaseByteArrayElements(env, barr, ba, 0);    return rtn;}JNIEXPORT jstring JNICALL Java_com_suixi_ndkproject_JNI_sayHello        (JNIEnv *env, jobject jobject1) {    // jstring     (*NewStringUTF)(JNIEnv*, const char*);    char *s = "I AM FROM C";    return (*env)->NewStringUTF(env, s);};/** * 返回带有参数的字符串 */JNIEXPORT jstring JNICALL Java_com_suixi_ndkproject_JNI_sayAddHello        (JNIEnv *env, jobject jobject1, jstring js) {    char *from = jstringTochar(env, js);    char *to = "I am from c";    strcat(from, to);//字符串拼接,会把拼接后的结果放在第一个参数里    return (*env)->NewStringUTF(env, from);};/** * 加法运算 */JNIEXPORT jint JNICALL Java_com_suixi_ndkproject_JNI_add        (JNIEnv *env, jobject jobject1, jint x, jint y) {    return x + y;};/** * 给数组的每个元素添加10 */JNIEXPORT jintArray JNICALL Java_com_suixi_ndkproject_JNI_increaseArray        (JNIEnv *env, jobject jobject1, jintArray array) {    //jsize       (*GetArrayLength)(JNIEnv*, jarray);    jsize size = (*env)->GetArrayLength(env,array);//获取数组的长度    //    jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);    jint* jint1 =  (*env)->GetIntArrayElements(env,array,JNI_FALSE);//获取数组中的元素    int i;    for(i=0;i<size;i++){        *(jint1+i)+=10;    }    return array;};/** * 检查密码是否正确 */JNIEXPORT jint JNICALL Java_com_suixi_ndkproject_JNI_checkPwd        (JNIEnv * env, jobject jobject1, jstring js){    char * from = jstringTochar(env,js);    char * origin = "123456";    //extern int    strcmp(const char *, const char *) __purefunc;    int code = strcmp(from,origin);//strcmp函数用于比较两个字符串是否相等    LOGE("code = %d",code);    if(code==0){        return 400;    }else{        return 200;    }};

7、在activity中实例化JNI,并进行调用
public class MainActivity extends Activity {    private JNI jni;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ButterKnife.inject(this);        jni = new JNI();    }    @OnClick({R.id.btn1,R.id.btn2,R.id.btn3,R.id.btn4,R.id.btn5})    public void onClick(View v){        switch (v.getId()){            case R.id.btn1:                String result = jni.sayHello();                Toast.makeText(this,result,Toast.LENGTH_LONG).show();                break;            case R.id.btn2:                String result1 = jni.sayAddHello("I am from java");                Toast.makeText(this,result1,Toast.LENGTH_SHORT).show();                break;            case R.id.btn3:                int result2 = jni.add(99,1);                Toast.makeText(this,result2+"==",Toast.LENGTH_SHORT).show();                break;            case R.id.btn4:                int[] arr = {1,2,3,4,5};                jni.increaseArray(arr);                for(int i=0;i<arr.length;i++){                    Log.e("iii",arr[i]+"==");                }                break;            case R.id.btn5:                String pwd = "1234566";                int code = jni.checkPwd(pwd);                Toast.makeText(this,code+"--",Toast.LENGTH_SHORT).show();                break;        }    }}

四:在C中调用Java的方式

1、写一个java类JNI(类名可自取),用于写native代码
public class JNI {    /**     * 当执行这个方法的时候,让C代码调用     * public void helloFromJava()     */    public native void callbackHelloFromJava();    public void helloFromJava() {        Log.e("TAG", "helloFromJava()");    }}
2、动态的生成你所需要的C的头文件的两种方法
1)、在\NDKDEMO\app\src\main\java
执行命令:javah com.suixi.ndkproject.JNI(包名+类名)
2)、在studio底部中的terminal 里执行javah javah com.suixi.ndkproject.JNI

3、在java中右键新建JniFodler,将上一步生成的.h文件移入改文件夹中
4、rebuild Project 下,会在build-->intermediates生成ndk文件夹

5、在JNI类下加载动态链接库
public class JNI {    {        System.loadLibrary("cCallJava");    }    /**     * 当执行这个方法的时候,让C代码调用     * public void helloFromJava()     */    public native void callbackHelloFromJava();    public void helloFromJava() {        Log.e("TAG", "helloFromJava()");    }}
6、编写.c文件
#include "Test2.h"#include <jni.h>#include <stdlib.h>#include <stdio.h>JNIEXPORT void JNICALL Java_com_suixi_myapplication_JNI_callbackHelloFromJava(JNIEnv *env, jobject instance) {    //jclass      (*FindClass)(JNIEnv*, const char*);   jclass jclazz = (*env)->FindClass(env,"com/suixi/myapplication/JNI");//第二个参数表示的是JNI所在的包名+类名    //第三个参数表示的是你要调用的java类中的方法,    //第四个参数表示的是签名:定位到JNI.class文件的位置,通过命令行:javap -s com/suixi/myapplication/JNI.class    //                       生成签名    jmethodID  jmethodID1 = (*env)->GetMethodID(env,jclazz,"helloFromJava","()V");    // jobject     (*AllocObject)(JNIEnv*, jclass);    jobject jobject1 = (*env)->AllocObject(env,jclazz);    //通过该方法调用即可    (*env)->CallVoidMethod(env,jobject1,jmethodID1);};
注意:GetMethodID的签名的生成方法
定位到:build-->intermediates-->classes-->debug
按住 shift+鼠标右键 ----->点击此处打开命令窗口
执行:javap -s com/suixi/myapplication/JNI.class
生成如下签名:

7、在activity中调用
public class MainActivity extends Activity {    private JNI jni;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ButterKnife.inject(this);        jni = new JNI();    }    @OnClick({R.id.bt1})    public void onClick(View v){        switch (v.getId()){            jni.callbackHelloFromJava();        }    }}
源码下载:下载代码

0 0