JNI开发基础篇:Java类调用C库或者方法

Maybe i walk slowly,but i will never give up

创建新的工程

在JNI开发中与C语言的结合,所以我们在创建新的项目的时候,建议添加C库的支持。(因为会有代码自动提示)如下:
这里写图片描述

勾选 Include C++ Support

然后一路next。在于平常创建项目中不同的是最后会有一个这样的选择:
这里写图片描述

下面的两个框可选可不选。
Exceptions Support(异常报错)
Runtime Type Information Support(运行支持)

创建完的工程如下:

这里写图片描述

附:
在这里说一下不同的开发环境所遇到不同的问题。

AS:2.2.2 或者更高
ndk:version 16.0
sdk:

该版本下创建的工程,项目中会自动帮我们生成cpp文件夹,并且在项目中的`build.gradle`中默认配置Cmark。
like this:

android {
   ···
    defaultConfig {
       ···
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}
并且生成一个默认的文件`CMakeLists.txt`
like this:

文件中前面有 `#`的均是说明信息,我直接在这里删掉了

cmake_minimum_required(VERSION 3.4.1)

add_library( 
             native-lib   
             #指定生成os文件的名称,但是注意,在androidstudio中生
             #成的os文件会在指定名前面添加 lib 关键词,所以我们平常
             #看到的os文件都是类似`libxxxxxx.os`

             src/main/cpp/native-lib.cpp
             #项目中C/C++的源代码位置,如果有多个,可以接着写下去
             #eg:src/main/jni/test.c
             #eg: src/main/jni/JNI.c
 )



find_library( 
              log-lib

              log )

target_link_libraries( # Specifies the target library.
                       # 指定目标library
                       # 解释说明我们可以自定多个library。
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )


这就是我目前相应版本下创建项目中的内容。

之前的1.xx版本是没有这些自动生成文件,是需要自己在`build.gradle`中自己配置脚本

like this:
//配置ndk
        ndk{
            moduleName "native-lib"//os文件名称
            abiFilters "arm64-v8a","x86","x86_64"
            //支持CPU,默认会生成目前android手机所有可能的CPU
            ldLibs "log" //支持log输出
        }

正题:
Java 类 调用 C 方法、函数

1:创建一个java类:

package com.wedfrend.jni;

public class JNI {

    /**
     * 调用C语言中的加法运算
     * @return
     */
    public native int add();

    /**
     * 检查密码是否正确
     * @param pwd
     * @return  正确,返回200 错误返回500
     */
    public native int CheckPassWord(String pwd);

}

这里所有的java方法,必须使用nativie关键字。

2:创建c中的方法。

2.1:直接在java的方法中,选中方法,按住alt+enter按钮。根据提示生成

这里写图片描述

这样生成的方法在另外一个文件中会生成如下的方法:

/**
1:这个方法便是JIN调用的时候,在C语言中应该声明的方法

2:JNIEXPORT  ---> 自动生成,可删除

3:jint    ---->  经过JNI协议规定,返回值。等值于 java中的int

4:JNICALL ----> 可删除

5:Java_   ----> JNI协议,必须添加

6:com_wedfrend_jni_    ---> 所在类的包名,java中的 . 变化为 _

7: INI_  --->类名

8:add  ---> 方法名

9: (JNIEnv *env, jobject instance) 两个固定参数,*env JNI中与c之间调用的主要二级指针。  instance 上下文参数
*/

JNIEXPORT jint JNICALL
Java_com_wedfrend_jni_JNI_add(JNIEnv *env, jobject instance) {

    // TODO

}
2.2:自己知道上面的书写方式,自己写。

2.3:使用如下方法。

2.3.1
cmd --》进入到项目中的java文件夹下,调用javah com.wedfrend.jni.JNI

F:\ASTestApplication\JNIApplications\app\src\main\java>javah com.wedfrend.jni.JNI
错错误误: 编编码码GBK的的不不可可映映射射字字符符
错错误误: 编编码码GBK的的不不可可映映射射字字符符
错错误误: 编编码码GBK的的不不可可映映射射字字符符

编码错误是因为我们使用了中文,不过没什么影响。如果使用英文写注释,则不会出现这种错误了。

这样会生成一个.h文件,如图:

这里写图片描述

打开如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_wedfrend_jni_JNI */

#ifndef _Included_com_wedfrend_jni_JNI
#define _Included_com_wedfrend_jni_JNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_wedfrend_jni_JNI
 * Method:    add
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_wedfrend_jni_JNI_add
  (JNIEnv *, jobject);

/*
 * Class:     com_wedfrend_jni_JNI
 * Method:    CheckPassWord
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_wedfrend_jni_JNI_CheckPassWord
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif
说明:
JNIEXPORT jint JNICALL Java_com_wedfrend_jni_JNI_CheckPassWord
 (JNIEnv *, jobject, jstring);

  和上面的解释一样,之所以多了个参数,那是因为我们java方法中带参

不过这样的生成是没有参数值,只有参数类型,需要自己添加

2.3.2

这里写图片描述

debug处,使用cmd进入到该文件目录下,执行

javah com.wedfrend.jni.JNI

同样会生成一个头文件。

以上3中方法便是如何生成JNI下的.h方法

step3:在项目中创建一个jni文件夹,与java同等级的jni文件夹,并将.h文件拖入jni问价夹中

这里写图片描述

step4: 在jni中创建一个c源文件,然后引入头文件

这里写图片描述

此时你在打开 java类的时候,不会报错,反而会出现
这里写图片描述

按钮,点击之后便可以直接跳转到头文件中。

step5:在C中实现方法功能。

#include <string>
#include "com_wedfrend_jni_JNI.h"
/**
下面的是引入打印模式,在c语言中可以执行输出内容
*/
#include "android/log.h"
#define LOG_TAG "com.wedfrend.cNative"
#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__)



/**
 * 两个数相加
 */
JNIEXPORT jint JNICALL Java_com_wedfrend_jni_JNI_add
        (JNIEnv * env, jobject jobj){
    int a = 10;
    int b = 5l;
    return a+b;
};

/**
 * 验证密码是否正确
 */
JNIEXPORT jint JNICALL Java_com_wedfrend_jni_JNI_CheckPassWord
        (JNIEnv * env, jobject instance, jstring jstr){

    /*讲一个字符串转化为char指针*/
    //const char *userPsw = env->GetStringUTFChars(jstr, 0);
    const char *userPsw = (*env)->GetStringUTFChars(env,jstr,0);
    char* basePsw = "123456";
    LOGD("userPsw---------%d\n",*userPsw);
    /**
    *strcmp string库中提供比较两个字符串相等的方法。
    *返回一个int类型值,这边很有意思的。
    */
    if(strcmp(userPsw,basePsw)==0){
        return 200;
    }else{
        return 500;
    }

};

6:activity或者class中直接调用C语言中的方法:

6.1
TextView tv = (TextView) findViewById(R.id.sample_text);
/*实例化你的native类,并且需要在该类中添加动态加载库的方法

     {
        System.loadLibrary("native");
    }
*/
 tv.setText(new JNI().CheckPassWord("123456")+"");
6.2

在JNI类中动态加载库,如下:
package com.wedfrend.jni;

public class JNI {
    {
        System.loadLibrary("native-lib");
    }

    /**
     * 调用C语言中的加法运算
     * @return
     */
    public native int add();

    /**
     * 检查密码是否正确
     * @param pwd
     * @return  正确,返回200 错误返回500
     */
    public native int CheckPassWord(String pwd);


    public native String getName(String name);

}

7:运行结果展示:

/*
打印输出功能查看:

12-18 15:34:42.229 7964-7964/com.wedfrend D/com.wedfrend.cNative: userPsw———123456
12-18 15:34:42.239 7964-7964/com.wedfrend D/SecWifiDisplayUtil: Metadata value : SecSettings2
*/

生成的os文件:
这里写图片描述

JNI开发基础篇:C语言调用Java中的方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值