美文网首页
(二)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);
    }
}

相关文章

  • C_Cpp-C-JNI-NDK-Java

    一.介绍 二.C/C++和Java数据类型映射 三.在java中调用C/C++函数 1.在java中定义nativ...

  • C++子线程调用Java方法

    1. C++ 全局调用Java方法 之前讨论过,如何C++主线程中调用 Java 函数C++主线程调用Java方法...

  • (二)Java 调用C 函数

    java 调用C 函数 通过以下四个案例 1.将传入的两个int 值相加并返回;2.将两个字符串拼接后返回;3...

  • [转载]C语言函数调用栈

    原文地址:C语言函数调用栈(一)C语言函数调用栈(二) 0 引言 程序的执行过程可看作连续的函数调用。当一个函数执...

  • Python:函数

    函数 Python的函数其实和Java的C的函数差不多,这里只讲讲和Java不同的地方。注意:函数调用是通过栈(s...

  • 深入理解Android-JNI

    JNI概述 Java程序中的函数可以调用Native语言写的函数,Native一般指的是C/C++写的函数 Nat...

  • Java JNI使用

    什么是JNI? JNI是Java Native Interface的缩写,通过JNI,使得java调用c的函数成为...

  • JNI基本操作

    JNI(Java Native Interface) Java调用C/C++,C/C++调用Java的一套API ...

  • JNI开发极简教程

    JNI(Java Native Interface) Java调用C/C++,C/C++调用Java的一套API ...

  • Jni中c++访问java实例方法、静态方法、实例变量、静态变量

    c++调用Java静态方法 示例代码 代码分析 主要看 CallStaticVoidMethod 函数: claz...

网友评论

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

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