前言
简单记录一下,方便自己查阅。
PS: Android jni开发主要依赖Android开发平台,sdk和ndk三个部分
Android SDK : Version 31
JAVA Sdk : java1.8
NDK : android-ndk-r21d
上面只是举个例子,具体环境需要自己搭建。
静态注册
静态注册:先由Java得到本地方法的声明,然后再通过JNI实现该声明方法。
- 优点: 理解和使用方式简单, 属于傻瓜式操作, 使用相关工具按流程操作就行, 出错率低
- 缺点: 当需要更改类名,包名或者方法时, 需要按照之前方法重新生成头文件, 灵活性不高
动态注册
动态注册:动态注册JAVA的Native方法,使得c/c++里面方法名 可以和 java 的Native方法名可以不同, 动态注册是将将二者方法名关联起来,以后在修改Native方法名时,只需修改动态注册关联的方法名称即可
- 优点: 灵活性高, 更改类名,包名或方法时, 只需对更改模块进行少量修改, 效率高
- 缺点: 对新手来说稍微有点难理解, 同时会由于搞错签名, 方法, 导致注册失败
正文
直入正题。本文介绍的是JNI静态注册。
第一步
新建一个Android 工程,这里命令为MyDeviceABI
然后新增一个DeviceABI.java
package com.biumall.mydeviceabi;
public class DeviceABI {
static {
//so库名也定义为DeviceABI
System.loadLibrary("DeviceABI");
}
// 定义一个接口
public static native String getDeviceABI();
}
第二步
使用Android Studio的Terminal
进入DeviceABI.java所在的目录,然后:
javac DeviceABI.java
然后退到MyDeviceABI\src\main\java目录下,执行
javah com.biumall.mydeviceabi.DeviceABI
生成
com_biumall_mydeviceabi_DeviceABI.h
我这里会改名字,具体看自己
DeviceABI.h
第三步
在MyDeviceABI工程根目录中创建jni目录
MyDeviceABI\jni
把DeviceABI.h(这里是生成的,没有改变)放入jni。
然后在jni目录中创建DeviceABI.c文件(从DeviceABI.h复制再改动的)
DeviceABI.c,完整版如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_biumall_mydeviceabi_DeviceABI */
#ifndef _Included_com_biumall_mydeviceabi_DeviceABI
#define _Included_com_biumall_mydeviceabi_DeviceABI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_biumall_mydeviceabi_DeviceABI
* Method: getDeviceABI
* Signature: ()Ljava/lang/String;
*/
// 此处开始有改动,其他的都是拷贝DeviceABI.h
JNIEXPORT jstring JNICALL Java_com_biumall_mydeviceabi_DeviceABI_getDeviceABI
(JNIEnv * env){
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#if defined(__ARM_PCS_VFP)
#define ABI "armeabi-v7a/NEON (hard-float)"
#else
#define ABI "armeabi-v7a/NEON"
#endif
#else
#if defined(__ARM_PCS_VFP)
#define ABI "armeabi-v7a (hard-float)"
#else
#define ABI "armeabi-v7a"
#endif
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#elif defined(__x86_64__)
#define ABI "x86_64"
#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */
#define ABI "mips64"
#elif defined(__mips__)
#define ABI "mips"
#elif defined(__aarch64__)
#define ABI "arm64-v8a"
#else
#define ABI "unknown"
#endif
return (*env)->NewStringUTF(env, "Compiled with ABI " ABI ".");
}
// 改动结束
#ifdef __cplusplus
}
#endif
#endif
PS: 如果你要复制,请记得改变函数名,这里函数涉及到包名。
第四部
这部分主要是新增Android.mk和Application.mk文件。
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := DeviceABI
LOCAL_SRC_FILES := DeviceABI.c
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := all
具体配置就不细说,后续会总结、
第五步
进入 MyDeviceABI\jni> 然后执行 ndk-build
如果程序或者配置没问题,就编译正常。
E:\MyDeviceABI\jni>ndk-build
[arm64-v8a] Compile : DeviceABI <= DeviceABI.c
[arm64-v8a] SharedLibrary : libDeviceABI.so
[arm64-v8a] Install : libDeviceABI.so => libs/arm64-v8a/libDeviceABI.so
[x86_64] Compile : DeviceABI <= DeviceABI.c
[x86_64] SharedLibrary : libDeviceABI.so
[x86_64] Install : libDeviceABI.so => libs/x86_64/libDeviceABI.so
[mips64] Compile : DeviceABI <= DeviceABI.c
[mips64] SharedLibrary : libDeviceABI.so
[mips64] Install : libDeviceABI.so => libs/mips64/libDeviceABI.so
[armeabi-v7a] Compile thumb : DeviceABI <= DeviceABI.c
[armeabi-v7a] SharedLibrary : libDeviceABI.so
[armeabi-v7a] Install : libDeviceABI.so => libs/armeabi-v7a/libDeviceABI.so
[armeabi] Compile thumb : DeviceABI <= DeviceABI.c
[armeabi] SharedLibrary : libDeviceABI.so
[armeabi] Install : libDeviceABI.so => libs/armeabi/libDeviceABI.so
[x86] Compile : DeviceABI <= DeviceABI.c
[x86] SharedLibrary : libDeviceABI.so
[x86] Install : libDeviceABI.so => libs/x86/libDeviceABI.so
[mips] Compile : DeviceABI <= DeviceABI.c
[mips] SharedLibrary : libDeviceABI.so
[mips] Install : libDeviceABI.so => libs/mips/libDeviceABI.so
我的编译成功后,libs中出现对应的so库等。
├─arm64-v8a
├─armeabi
├─armeabi-v7a
├─mips
├─mips64
├─x86
└─x86_64
因为我的存在libs,最后一步配置就是直接引用。
第六步
配置 so库,网上很多种,看自己习惯。
在工程中的build.gradle,新增如下内容:
android {
compileSdkVersion 31
// 略
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
可能存在问题
下面是我偷懒,复制时,出现的问题
java.lang.UnsatisfiedLinkError: No implementation found for java.lang.String com.biumall.mylog.DeviceABI.getDeviceABI() (tried Java_com_biumall_mylog_DeviceABI_getDeviceABI and Java_com_biumall_mylog_DeviceABI_getDeviceABI__)
at com.biumall.mylog.DeviceABI.getDeviceABI(Native Method)
at com.biumall.mylog.MainActivity$1.onClick(MainActivity.java:21)
这里是由于包名路径不对,导致找不到,所以不建议直接复制。
参考文章