概述
使用Makefile构建工具完成jni的开发一般会比较繁琐,其实现的基本步骤如下:
- 编写实现jni的java文件
- 使用javac 命令编译java文件为class文件(javac Mp3Encoder.java)
- 使用javah命令编译class文件生成一个jni的头文件(javah -jni cn.enjoytoday.mp3encoder.Mp3Encoder)
- 将jni头文件复制到jni目录,并建立一个cpp的实现文件实现该JNI头文件的函数
- 编写Android.mk文件,加入上步的本地代码,利用ndk-build生成动态链接库
- java代码中加载生成好的动态链接库,并调用native方法
实施过程
本案例结合一个通过JNI来打印“Hello,Mp3 encoder!”的基础工程实现。
- 创建工程,编写实现jni的java文件Mp3Encoder,代码如下: public class Mp3Encoder {
public native void encode();
} - 完成工程编译生成对应的class文件,或直接通过javac命令生成class文件,这里使用javac命令生成class文件,如下:
hfcai@hfcai-Lenovo-XiaoXin-V4000:~/Mp3Encoder/app/src/main/java$ javac cn/enjoytoday/mp3encoder/Mp3Encoder.java
hfcai@hfcai-Lenovo-XiaoXin-V4000:~/Mp3Encoder/app/src/main/java$ cd cn/enjoytoday/mp3encoder/
hfcai@hfcai-Lenovo-XiaoXin-V4000:~/Mp3Encoder/app/src/main/java/cn/enjoytoday/mp3encoder$ ll
总用量 20
drwxrwxr-x 2 hfcai hfcai 4096 8月 10 06:35 ./
drwxrwxr-x 3 hfcai hfcai 4096 8月 8 20:48 …/
-rw-rw-r-- 1 hfcai hfcai 880 8月 9 08:18 MainActivity.java
-rw-r–r-- 1 hfcai hfcai 236 8月 10 06:35 Mp3Encoder.class
-rw-rw-r-- 1 hfcai hfcai 98 8月 9 22:10 Mp3Encoder.java
hfcai@hfcai-Lenovo-XiaoXin-V4000:~/Mp3Encoder/app/src/main/java/cn/enjoytoday/mp3encoder$
- 使用javah命令编译class文件生成一个jni的头文件,Android Studio和Eclipse也可以通过编译的方式生成该头文件,但这里为了更加清楚的了解整个实现过程,采用命令的方式实现.如下:
如上,cn_enjoytoday_mp3encoder_Mp3Encoder.h为生成的jni头文件,文件名定义格式为包名+类名.h。如下为生成的内容:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class cn_enjoytoday_mp3encoder_Mp3Encoder */
#ifndef _Included_cn_enjoytoday_mp3encoder_Mp3Encoder
#define _Included_cn_enjoytoday_mp3encoder_Mp3Encoder
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: cn_enjoytoday_mp3encoder_Mp3Encoder
* Method: encode
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_cn_enjoytoday_mp3encoder_Mp3Encoder_encode
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
该文件不可修改,这里定义了一个方法Java_cn_enjoytoday_mp3encoder_Mp3Encoder_encode,需要在对应的c文件中实现它。
- 将jni头文件复制到jni目录,并建立一个cpp的实现文件实现该JNI头文件的函数,创建Mp3Encoder.cpp文件如下:
#include <jni.h>
#include <android/log.h>
#include <string.h>
#include “cn_enjoytoday_mp3encoder_Mp3Encoder.h”
#define LOG_TAG “mp3encoder”
#define LOGI(…) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, VA_ARGS)
JNIEXPORT void JNICALL Java_cn_enjoytoday_mp3encoder_Mp3Encoder_encode
(JNIEnv *, jobject){
LOGI(“encoder encode!”);
}
在jni下添加Android.mk文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -lm -llog
LOCAL_MODULE := audioencoder
LOCAL_LDFLAGS := -Wl,--build-id
LOCAL_SRC_FILES := \
/home/hfcai/Mp3Encoder/app/src/main/jni/Android.mk \
/home/hfcai/Mp3Encoder/app/src/main/jni/Mp3encoder.cpp \
LOCAL_C_INCLUDES += /home/hfcai/Mp3Encoder/app/src/main/jni
LOCAL_C_INCLUDES += /home/hfcai/Mp3Encoder/app/src/debug/jni
include $(BUILD_SHARED_LIBRARY)
build.gradle设置ndk编译:
android {
compileSdkVersion 28
defaultConfig {
applicationId "cn.enjoytoday.mp3encoder"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
//ndk-build
ndk{
moduleName "audioencoder"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
//ndkBuild
externalNativeBuild {
ndkBuild {
path file("src/main/jni/Android.mk")
}
}
}
需要在项目的根目录gradle.properties中添加
android.deprecatedNdkCompileLease=true
注意 :Android studio 从3.1.4之后将不再支持make方式使用ndk.
- 加载调用native方法 Mp3Encoder.java
package cn.enjoytoday.mp3encoder;
public class Mp3Encoder {
static {
System.loadLibrary("audioencoder");
}
public native void encode();
}
//调用
new Mp3Encoder().encode();
如上,实测可以实现log打印.