Android studio 中使用Jni

在使用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 __cplusplus
extern "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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值