NDK开发

什么是JNI

JNI为Java Native Interface(Java本地接口),它是为Java调用c/c++封装的一个接口,可以说是Java代码与C/C++之间互调的一个桥梁。

什么是NDK

NDK是Android提供的工具集,使用它可进行交叉编译,帮助开发者快速开发C/C++的动态库。

使用NDK的好处

  • 安全性:so库被反编译很困难
  • 方便性:可以使用当前已有的C/C++开源库
  • 移植性:C/C++的库可到别的平台上运用

前期配置

  1. 下载NDK
    这里写图片描述
  2. 关联
    local.properties文件下
ndk.dir=E\:\\Android\\sdk\\ndk-bundle

为了兼容老的NDK
gradle.properties文件下

android.useDeprecatedNdk=true;
  1. 为了方便,可在File–>Setting–>Tools–>External Tools中进行以下配置
    这里写图片描述
    配置将Java代码中的本地方法编译成C/C++头文件
    配置将Java代码中的本地方法编译成C/C++头文件
    配置将C/C++文件编译成so文件
    这里写图片描述

开发流程

  1. 创建一个类,并在类里面写方法(桥梁)
    public native String sayHello();

  2. 在gradle中的defaultConfig配置

ndk{
    moduleName "JniTest" //so文件:lib+moduleName+.so
    abiFilters "armeabi","armeabi-v7a","arm64-v8a","x86" ,"mips","mips64"//cpu类型
}

3.添加两个mk文件

  • Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := JniTest//编译到的so库
LOCAL_SRC_FILES := hello.c//要编译的c文件
LOCAL_SRC_FILES := Test.c
include $(BUILD_SHARED_LIBRARY)
  • Application.mk
    APP_ABI :=all//表示编译为所有指定类型的so文件

4.在刚刚创建的Java类(含有本地方法native)中右键,External Tools->javah -jni,等待编译后便会生成一个C/C++的头文件,如下图
这里写图片描述
5.创建C/C++文件

#include "com_sendi_ndkdemo_JNITest.h"
/*
jstring:返回值
Java_类全名_方法名
JNIEnv* env:里面有很多方法
jobject jobj:谁调用这个方法就是谁的实例
*/
JNIEXPORT jstring JNICALL Java_com_sendi_ndkdemo_JNITest_sayHello
  (JNIEnv *env, jobject jobj){

  //  char* text="I am from c";
    return (*env)->NewStringUTF(env,"I am from c");
}

6.生成so文件
右键c/c++文件,External Tools–>ndk -build,然后生成相应的包
这里写图片描述
7.接下来是在main文件下创建一个文件名为jniLibs的文件夹,将刚刚生成的libs里面的内容拷贝过来
这里写图片描述
OK,接下来正式进入使用阶段

Java调用C

这里举一个简单的例子:
首先创建一个刚刚定义了native方法的类对象,然后直接调用该native方法

       String result=new JNITest().sayHello();
       Log.i(TAG, "onCreate: result==="+result);

运行后会发现报错,原因是没有加载我们编译好的库(这里比较容易忘记),在刚刚的JNI类里边添加:

{
        System.loadLibrary("JniTest");//表示加载名字为JniTest的库
    }

这时候在运行一次,发现成功了。

C调用Java

C调用Java其实就是Java先调用C代码,然C代码里面通过反射对Java的代码进行调用,下面举个简单的例子

  • 创建一个本地方法和待C调用的方法
/**
     * 调用此方法后,让C代码调用下边的方法
     */
    public native void callbackHelloFromJava();
 public void helloFromJava() {
        Log.i("SENDI", "c call Java");
    }
  • 然后进行编译出.h文件
  • c文件的代码
#include "com_sendi_ccalljava_JNI.h"
#include <stdlib.h>
#include <stdio.h>
JNIEXPORT void JNICALL Java_com_sendi_ccalljava_JNI_callbackHelloFromJava
    (JNIEnv *env, jobject jobj){
      //获得字节码
      //第二个参数为要调用Java函数所在的类全名
          jclass jclazz=(*env)->FindClass(env,"com/sendi/ccalljava/JNI");
          //得到方法
          //最后一个参数为方法签名
          jmethodID jmethodIDs=(*env)->GetMethodID(env,jclazz,"helloFromJava","()V");
          //获得该实例
          jobject jobject=(*env)->AllocObject(env,jclazz);
          //调用方法
          (*env)->CallVoidMethod(env,jobject,jmethodIDs);
    };

获取方法签名
1. 编译
2. 进入到build-intermadiates-classes-debug
3. 执行javap -s 全类名

  • 编译成so文件,步骤跟上述相同。
  • 在Java中调用本地方法,步骤依然相同
  • 最后可以看到打印SENDI :c call Java

在这过程中有问题可以留言或评论,大家一起交流交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值