初识NDK

Java调用外部库的实现的这种技术叫jni,java端定义功能接口,让外部库来实现,编译(打包)库的环境就是ndk环境。
环境配置:下载ndk环境包,解压,将ndk根目录配置到path路径下

JNI方法定义

Java native interface,java定义的公开给外部库实现功能的接口

public class JniUtil {
    public static native String sayHello();

    public static native int add(int a,int b);
}

使用javac将java文件编译为class文件

进入控制台,切换到java文件所在的目录,如:
C:\Users\Administrator>E:
E:\>cd E:\AT32\Android\code\JniDemo\src\com\xykj\utils\
使用javac命令编译class文件
javac JniUtil.java

如果编译的java类中引用其他的自定义类型,则在编译时需要使用-cp指定classpath

javac -cp E:\AT32\Android\code\JniDemo\src\ JniUtil.java

使用javah将class文件转为C/C++的头文件h文件

退出到src目录下
E:\AT32\Android\code\JniDemo\src\com\xykj\utils>cd ../../../
使用javah生成头文件
javah -d ../jni/ com.xykj.utils.JniUtil
如果有提示找不到类可以使用如下方式指定位置
javah -classpath . -d ../jni/ com.xykj.utils.JniUtil

头文件中函数结构

以JNIEXPORT开头返回值跟着类型,然后跟着JNICALL关键字(关联实现的目标)跟着java中定义的包名类名方法名(用Java_做前缀)
如Java中的方法:
public static native String sayHello();
对应的h文件的声明
JNIEXPORT jstring JNICALL Java_com_xykj_utils_JniUtil_sayHello(JNIEnv *, jclass);

头文件的代码如下
#include <jni.h>
/* Header for class com_xykj_utils_JniUtil */

#ifndef _Included_com_xykj_utils_JniUtil
#define _Included_com_xykj_utils_JniUtil
#ifdef __cplusplus
extern "C" {
    #endif
    /*
    * Class: com_xykj_utils_JniUtil
    * Method: sayHello
    * Signature: ()Ljava/lang/String;
    * /

    JNIEXPORT jstring JNICALL Java_com_xykj_utils_JniUtil_sayHello
        (JNIEnv *, jclass);

   /*
    * Class: com_xykj_utils_JniUtil
    * Method: add
    * Signature: (II)I
    */
    JNIEXPORT jint JNICALL Java_com_xykj_utils_JniUtil_add
        (JNIEnv *, jclass, jint, jint);
    #ifdef __cplusplus
}
#endif
#endif
定义实现文件
引入头文件,定义实现方法
#include "JniUtil.h"
/*
* Class: com_xykj_utils_JniUtil
* Method: sayHello
* Signature: ()Ljava/lang/String;
*/

JNIEXPORT jstring JNICALL Java_com_xykj_utils_JniUtil_sayHello
    (JNIEnv *env, jclass jobj){
        return (*env)->NewStringUTF(env,"Hello from JNI");
}

/*
* Class: com_xykj_utils_JniUtil
* Method: add
* Signature: (II)I
*/

JNIEXPORT jint JNICALL Java_com_xykj_utils_JniUtil_add
    (JNIEnv *env, jclass jobj, jint a, jint b){
        return a+b;
}
定义编译配置文件(mk文件):

在c文件的同目录下新建Android.mk,然后配置库名称以及要打包到库中的源文件(c文件)

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#配置库名称
LOCAL_MODULE := hello
#配置要打包到库中的原码
LOCAL_SRC_FILES := JniUtil.c

#使用Android的log打印
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
#编译为动态库
include $(BUILD_SHARED_LIBRARY)

其中配置中:=表示赋值 $表示引用

编译库:

进入工程目录下

E:\AT32\Android\code\JniDemo>
使用ndk-build工具编译
E:\AT32\Android\code\JniDemo>ndk-build

效果如下
Android NDK: Found platform level in ./project.properties. Setting APP_PLATFORM
to android-20.
Android NDK: WARNING: APP_PLATFORM android-19 is higher than android:minSdkVersi
on 15 in ./AndroidManifest.xml. NDK binaries will *not* be comptible with device
s older than android-19. See https://android.googlesource.com/platform/ndk/+/mas
ter/docs/user/common_problems.md for more information.
[arm64-v8a] Compile : hello <= JniUtil.c
[arm64-v8a] SharedLibrary : libhello.so
[arm64-v8a] Install : libhello.so => libs/arm64-v8a/libhello.so
[x86_64] Compile : hello <= JniUtil.c
[x86_64] SharedLibrary : libhello.so
[x86_64] Install : libhello.so => libs/x86_64/libhello.so
[mips64] Compile : hello <= JniUtil.c
[mips64] SharedLibrary : libhello.so
[mips64] Install : libhello.so => libs/mips64/libhello.so
[armeabi-v7a] Compile thumb : hello <= JniUtil.c
[armeabi-v7a] SharedLibrary : libhello.so
[armeabi-v7a] Install : libhello.so => libs/armeabi-v7a/libhello.so
[armeabi] Compile thumb : hello <= JniUtil.c
[armeabi] SharedLibrary : libhello.so
[armeabi] Install : libhello.so => libs/armeabi/libhello.so
[x86] Compile : hello <= JniUtil.c
[x86] SharedLibrary : libhello.so
[x86] Install : libhello.so => libs/x86/libhello.so
[mips] Compile : hello <= JniUtil.c
[mips] SharedLibrary : libhello.so
[mips] Install : libhello.so => libs/mips/libhello.so
Java中引入库

可以在java代码的任何地方,在一开始的时候使用System.loadLibary()方法加载,库的名称去掉文件的lib前缀以及.so的后缀(就是配置Android.mk中的LOCAL_MODULE值)

static{
System.loadLibrary("hello");
}
调用方法
TextView tv= (TextView) findViewById(R.id.tv);
tv.append(JniUtil.sayHello()+"\n");
tv.append("156+987="+JniUtil.add(156, 987));
Jni中操作java对象

在c代码中通过jni操作java对象可以理解为是使用java的Class反射的操作

如下:
public class MusicItem {
    private String name;
    private int duration;
    ...
}

jni中创建
JNIEXPORT jobject JNICALL Java_com_xykj_utils_JniUtil_load(JNIEnv *env, jclass jobj, jstring path){
    //获取Class实例Class.forName("包名类名");
    jclass musicClass = (*env)->FindClass(env,"com/xykj/bean/MusicItem");
    //创建对象
    //获取构造方法的id Method
    jmethodID construct = (*env)->GetMethodID(env,musicClass,"<init>","()V");
    jobject musicObj = (*env)->NewObject(env,musicClass,construct);
    //填充name属性
    //获取属性id Field
    jfieldID nameID = (*env)->GetFieldID(env,musicClass,"name","Ljava/lang/String;");
    jstring name = (*env)->NewStringUTF(env,"abc.mp3");
    (*env)->SetObjectField(env,musicObj,nameID,name);

    jfieldID durationID = (*env)->GetFieldID(env,musicClass,"duration","I");
    (*env)->SetIntField(env,musicObj,durationID,30000);
    return musicObj;
}
MVP关系图

这里写图片描述

图片画的不好,将就着看哈。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值