美文网首页
(二)Java 调用C 函数

(二)Java 调用C 函数

作者: 极客天空 | 来源:发表于2019-11-22 00:02 被阅读0次

    java 调用C 函数 通过以下四个案例 1.将传入的两个int 值相加并返回;2.将两个字符串拼接后返回;3.将数组中的每个元素增加10; 4.检查密码是否正确

    方法实现

    1. 编写native方法
    package domain.com.rrcc.javacallc;
    
    public class JNI {
    
        {
            System.loadLibrary("javacallc");
        }
    
        /**
         * 让C代码做加法运算,把结果返回
         * @param x
         * @param y
         * @return
         */
        public native int add(int x, int y);
    
        /**
         * 从java传入字符串,C代码进程拼接
         *
         * @param s I am from java
         * @return  I am form java add I am from C
         */
        public native String sayHello(String s);
    
        /**
         * 让C代码给每个元素都加上10
         * @param intArray
         * @return
         */
        public native int[] increaseArrayEles(int[] intArray);
        /*
         * 应用: 检查密码是否正确, 如果正确返回200, 否则返回400
         */
        public native int checkPwd(String pwd);
    }
    
    
    1. 通过javah命令 生成native方法对应的JNI函数声明头文件
    javah -d ../jni domain.com.rrcc.javacallc.JNI
    

    生成了jni目录以及下面的domain_com_rrcc_javacallc_JNI.h 头文件

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class domain_com_rrcc_javacallc_JNI */
    
    #ifndef _Included_domain_com_rrcc_javacallc_JNI
    #define _Included_domain_com_rrcc_javacallc_JNI
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     domain_com_rrcc_javacallc_JNI
     * Method:    add
     * Signature: (II)I
     */
    JNIEXPORT jint JNICALL Java_domain_com_rrcc_javacallc_JNI_add
      (JNIEnv *, jobject, jint, jint);
    
    /*
     * Class:     domain_com_rrcc_javacallc_JNI
     * Method:    sayHello
     * Signature: (Ljava/lang/String;)Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_domain_com_rrcc_javacallc_JNI_sayHello
      (JNIEnv *, jobject, jstring);
    
    /*
     * Class:     domain_com_rrcc_javacallc_JNI
     * Method:    increaseArrayEles
     * Signature: ([I)[I
     */
    JNIEXPORT jintArray JNICALL Java_domain_com_rrcc_javacallc_JNI_increaseArrayEles
      (JNIEnv *, jobject, jintArray);
    
    /*
     * Class:     domain_com_rrcc_javacallc_JNI
     * Method:    checkPwd
     * Signature: (Ljava/lang/String;)I
     */
    JNIEXPORT jint JNICALL Java_domain_com_rrcc_javacallc_JNI_checkPwd
      (JNIEnv *, jobject, jstring);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    
    1. 在步骤2生成的文件夹(jni)下创建并实现对应C/C++文件
      javacallc.c 文件
    //
    // Created by mac on 2019/11/21.
    //
    /**
     * jint:返回值
     * Java_全类名_方法名
     * JNIEnv *env:
     */
    #include "domain_com_rrcc_javacallc_JNI.h"
    #include <jni.h>
    #include <stdlib.h>
    #include <string.h>
    #include <android/log.h>
    #define LOG_TAG "System.out"
    #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
    
    /**
     * 把一个jstring转换成一个c语言的char* 类型.
     */
    char* _JString2CStr(JNIEnv* env, jstring jstr) {
        char* rtn = NULL;
        jclass clsstring = (*env)->FindClass(env, "java/lang/String");
        jstring strencode = (*env)->NewStringUTF(env,"GB2312");
        jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");
        jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312");
        jsize alen = (*env)->GetArrayLength(env, barr);
        jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);
        if(alen > 0) {
            rtn = (char*)malloc(alen+1); //"\0"
            memcpy(rtn, ba, alen);
            rtn[alen]=0;
        }
        (*env)->ReleaseByteArrayElements(env, barr, ba,0);
        return rtn;
    }
    
    jint JNICALL Java_domain_com_rrcc_javacallc_JNI_add
      (JNIEnv* env, jobject jo, jint ji, jint jj){
        int result = ji + jj;
        return result;
      }
    
    /*
     * Class:     domain_com_rrcc_javacallc_JNI
     * Method:    sayHello
     * Signature: (Ljava/lang/String;)Ljava/lang/String;
     */
    jstring JNICALL Java_domain_com_rrcc_javacallc_JNI_sayHello
            (JNIEnv * env, jobject job, jstring jstr){
    
        char* fromJava =_JString2CStr(env,jstr);//I am form java add I am from C
        //c:
        char* fromC = "add I am from C12";
        //拼接函数strcat
        strcat(fromJava,fromC);//把拼接的结果放在第一参数里面
        //jstring     (*NewStringUTF)(JNIEnv*, const char*);
        LOGD("fromJava===%s\n",fromJava);
        return  (*env)->NewStringUTF(env,fromJava);
    };
    
    
    /*
     * Class:     domain_com_rrcc_javacallc_JNI
     * Method:    increaseArrayEles
     * Signature: ([I)[I
     */
    JNIEXPORT jintArray JNICALL Java_domain_com_rrcc_javacallc_JNI_increaseArrayEles
            (JNIEnv * env, jobject jobj, jintArray jarray){
    
        //1.得到数组的长度
        //jsize       (*GetArrayLength)(JNIEnv*, jarray);
        jsize size = (*env)->GetArrayLength(env,jarray);
        //2.得到数组元素
        //jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
        jint*  intArray = (*env)->GetIntArrayElements(env,jarray,JNI_FALSE);
        //3.遍历数组,给每个元素加上10
        int i;
        for(i =0;i<size;i++){
    //        *(intArray+i) = *(intArray+i) + 10;
            *(intArray+i) +=  100;
    //        LOGD("*(intArray+i) === %d\n",*(intArray+i));
        }
        //4.返回结果
        return  jarray;
    
    };
    
    
    /*
     * Class:     domain_com_rrcc_javacallc_JNI
     * Method:    checkPwd
     * Signature: (Ljava/lang/String;)I
     */
    jint JNICALL Java_domain_com_rrcc_javacallc_JNI_checkPwd
            (JNIEnv * env, jobject jobj, jstring jstr){
    
        //服务器的密码是123456
        char* origin = "123456";
        char* fromUser = _JString2CStr(env,jstr);
    
        //函数比较字符串是否相同
        int code =  strcmp(origin,fromUser);
        LOGD("code===%d\n",code);
        if(code==0){
            return 200;
        }else{
            return 400;
        }
    
    };
    
    
    
    1. 配置gradle 文件 指定编译的不同CPU
    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 29
        defaultConfig {
            applicationId "domain.com.rrcc.javacallc"
            minSdkVersion 16
            targetSdkVersion 29
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
            ndk{
                moduleName "libjavacallc" //so文件: lib+moduleName+.so
                abiFilters "armeabi-v7a", "x86" //cpu的类型
            }
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
        externalNativeBuild {
            ndkBuild {
                path 'src/main/jni/Android.mk'
            }
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
    //    implementation 'com.android.support:appcompat-v7:29.+'
        implementation 'com.android.support:appcompat-v7:+'
        implementation 'com.android.support.constraint:constraint-layout:1.1.3'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'com.android.support.test:runner:1.0.2'
        androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    }
    
    
    1. 通过ndk-build 自动生成so文件

    在jni目录下创建Android.mk 文件

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

    module 处右键 选择 Link C++ Project with Gradle


    001.png

    生成so文件、然后拷贝到app的libs文件目录下


    002.png
    003.png
    1. 在项目具体调用实现
    package domain.com.rrcc.javacallc;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    
    public class MainActivity extends Activity {
        private JNI jni;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            jni = new JNI();
        }
        public void add(View view){
            int result =jni.add(99, 1);
            Log.e(MainActivity.class.getSimpleName(),"result==="+result);
        }
        public void string(View view){
            String result =jni.sayHello("I am from java ");
            Log.e(MainActivity.class.getSimpleName(), "result===" + result);
        }
        public void array(View view){
            int array[] = {1,2,3,4,5};
            int result[] =jni.increaseArrayEles(array);
            for(int i=0;i<result.length;i++){
                Log.e(MainActivity.class.getSimpleName(),"array["+i+"]==="+array[i]);
            }
        }
        public void checkpw(View view){
            int result =jni.checkPwd("123456");
            Log.e(MainActivity.class.getSimpleName(), "result===" + result);
        }
    }
    
    

    相关文章

      网友评论

          本文标题:(二)Java 调用C 函数

          本文链接:https://www.haomeiwen.com/subject/icgxwctx.html