当前位置: 首页 > news >正文

Android --- 搭建JNI框架

JNI(Java Native Interface,Java 本地接口)是 Java 平台提供的一种编程框架,用于实现 Java 代码与其他编程语言(主要是 C/C++)之间的交互。它的核心作用是打破 Java 的跨平台特性限制,让 Java 程序能够调用本地代码(如操作系统底层 API、硬件驱动、高性能计算库等),同时也允许本地代码调用 Java 方法。

在android平台搭建JNI框架:
Step1. 明确jni要封装的其他编程语言(主要是 C/C++)的函数并提供给java调用的接口
为了方便举例,在C++库中定义了一个加法函数
此代码库在后续的步骤中会使用mk编译成.so库
sum_test.h

#ifndef SUM_TEST_H
#define SUM_TEST_H#include <cstdint>uint32_t additionTest(uint32_t a, uint32_t b);#endif // SUM_TEST_H

sum_test.cpp

#include "sum_test.h"
#include <android/log.h>#define LOG_TAG "LibSum"uint32_t additionTest(uint32_t a, uint32_t b) {__android_log_print(ANDROID_LOG_DEBUG, "yuan", "additionTest() start!! (I'm from libsum)");return a + b;
}


Step2. 编写Java类:声明native方法
Java 层声明本地方法:在 Java 类中用native关键字声明需要调用的本地方法(无方法体)
注意要使用静态代码块加载含本地方法的动态链接库(要调用的C/C++库的名字去掉lib)

AppInstance.java

package com.app.test;public class AppInstance {static {System.loadLibrary("sum_jni");}public native int additionTest(int a, int b);}

Step3. 生成JNI头文件:使用javac和javah命令
3.1 用source和lunch加载一下环境变量
source build/envsetup.sh
lunch 编译目标数字编号
3.2 使用javac命令生成头文件
prebuilts/jdk/jdk9/linux-x86/bin/javac -h ./vendor/xxx/packages/apps/AppTest/jni/ ./vendor/xxx/packages/apps/AppTest/src/com/app/test/AppInstance.java
命令解读:
① prebuilts/jdk/jdk9/linux-x86/bin/javac     在代码的以下路径有javac编译器工具
② ./vendor/xxx/packages/apps/AppTest/jni/     jni头文件的生成路径
③ ./vendor/xxx/packages/apps/AppTest/src/com/app/test/AppInstance.java     要编译的java文件
执行此命令会在/vendor/xxx/packages/apps/AppTest/jni路径下自动生成com_app_test_AppInstance.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_app_test_AppInstance */#ifndef _Included_com_app_test_AppInstance
#define _Included_com_app_test_AppInstance
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     com_app_test_AppInstance* Method:    additionTest* Signature: (II)I*/
JNIEXPORT jint JNICALL Java_com_app_test_AppInstance_additionTest(JNIEnv *, jobject, jint, jint);#ifdef __cplusplus
}
#endif
#endif

Step4. 根据头文件实现jni代码(可以用C/C++编写)
com_app_test_AppInstance.cpp

#include "com_app_test_AppInstance.h"
#include "../libsum/sum_test.h"
#include <android/log.h>extern "C" {JNIEXPORT jint JNICALL Java_com_app_test_AppInstance_additionTest(JNIEnv* env, jobject obj, jint a, jint b) {__android_log_print(ANDROID_LOG_DEBUG, "yuan", "Java_com_app_test_AppInstance_additionTest() start!! ""(I'm from libsum_jni)");return additionTest(a, b);}
}

① 注意要引用.so库中要调用的函数所在的头文件
② 函数是根据从java中传入的参数并调用.so库中的函数


Step5. 编写Android.mk将java层、jni层、C/C++库的代码编译到android平台
① .so库层
编译出.so库,分别将64位和32位的.so push到车机的system/lib64和system/lib路径下

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)LOCAL_MODULE := libsumLOCAL_SRC_FILES := sum_test.cppLOCAL_SHARED_LIBRARIES := libloginclude $(BUILD_SHARED_LIBRARY)

② jni层
编译出.so库,分别将64位和32位的.so push到车机的system/lib64和system/lib路径下
注意要添加对①的依赖:LOCAL_SHARED_LIBRARIES :=  libsum

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)LOCAL_MODULE := libsum_jniLOCAL_SRC_FILES := \com_app_test_AppInstance.cppLOCAL_C_INCLUDES := \$(JNI_H_INCLUDE)LOCAL_SHARED_LIBRARIES := \libbase \liblog \libsum \include $(BUILD_SHARED_LIBRARY)

③ app层
编译出apk,在system/app下创建一个自己app名字的文件并push到这里(需要安装成系统app,否则无法访问system分区下的.so库)
注意要添加对②的依赖:LOCAL_JNI_SHARED_LIBRARIES := libsum_jni

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)LOCAL_PACKAGE_NAME := TestAppLOCAL_PRIVATE_PLATFORM_APIS := trueLOCAL_CERTIFICATE := platformLOCAL_PRIVILEGED_MODULE := falseLOCAL_USE_AAPT2 := trueLOCAL_PROGUARD_ENABLED := disabledLOCAL_DEX_PREOPT := falseLOCAL_RESOURCE_DIR := $(LOCAL_PATH)/resLOCAL_JNI_SHARED_LIBRARIES := libsum_jniLOCAL_STATIC_ANDROID_LIBRARIES:= androidx.appcompat_appcompat \androidx-constraintlayout_constraintlayoutinclude $(BUILD_PACKAGE)include $(call all-makefiles-under, $(LOCAL_PATH))


Step6. 在app内调用native方法
通过AppInstance实例调用native方法additionTest()
MainActivity.java

public class MainActivity extends Activity {private AppInstance appInstance = new AppInstance();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d("yuan", "onCreate() start!! (I'm from app)");int result = appInstance.additionTest(10, 20);Log.d("yuan", "result:" + result);}}

最终通过log输出来查看代码的调用流程:

$ logcat | grep yuan
05-20 02:27:14.883  3336 3336 D yuan            :  onCreate() start!! (I'm from app)
05-20 02:27:14.884  3336 3336 D yuan            : Java_com_app_test_AppInstance_additionTest() start!! (I'm from libsum_jni)
05-20 02:27:14.884  3336 3336 D yuan            : additionTest() start!! (I'm from libsum)
05-20 02:27:14.884  3336 3336 D yuan            : result:30

① app调用native方法
② 调用jni层函数
③ 调用.so库层函数
④ app通过jni的接口调用.so库成功~(返回结果30=10 + 20)

http://www.dtcms.com/a/362931.html

相关文章:

  • Nature | 克隆拷贝数多样性影响肺癌生存
  • Ubuntu系统镜像源配置
  • 什么是Z-score标准化
  • 传统企业数字化转型投入巨大却收效甚微,其根源究竟在哪?
  • QSlider 和 QProgressBar 的区别与实践
  • 【高等数学】第十一章 曲线积分与曲面积分——第一节 对弧长的曲线积分
  • 【2025终极对决】Python三大后端框架Django vs FastAPI vs Robyn,你的选择将决定项目生死?
  • 基于SQLite索引的智能图片压缩存储系统设计与实现
  • Postman接口测试工具:高效管理测试用例与环境变量,支持断言验证及团队协作同步
  • Unity学习----【数据持久化】二进制数据(五)--由Excel自动生成数据结构类与二进制文件
  • 向成电子惊艳亮相2025物联网展,携工控主板等系列产品引领智造新风向
  • 深度集成Dify API:企业级RAG知识库管理平台解决方案
  • 一款高效、强大的子域名爬取工具,帮助安全研究者和渗透测试人员快速收集目标域名的子域名信息
  • 【设计模式】三大原则 单一职责原则、开放-封闭原则、依赖倒转原则
  • 【linux】firewall防火墙
  • 社区医疗健康管理系统的设计与实现-(源码+LW+可部署)
  • css3元素倒影效果属性:box-reflect
  • Web2 vs Web3--差异一看就懂
  • 开发中使用——鸿蒙本地存储之收藏功能
  • webpack性能优化指南
  • 汽车制造工厂如何应用力控SCADA实现全方位智能监控与诊断
  • Spring Boot + Spring MVC 项目结构
  • Jenkins 拉取 Git 仓库时报错:there are still refs under ‘refs/remotes/origin/release‘
  • 在 Elasticsearch 中使用用户行为分析:使用 UBI 和 search-ui 创建一个应用程序
  • 【序列晋升】25 Spring Cloud Open Service Broker 如何为云原生「服务市集」架桥铺路?
  • 【JavaScript】前端两种路由模式,Hash路由,History 路由
  • UBUNTU之Onvif开源服务器onvif_srvd:2、测试
  • @Value注解底层原理(二)
  • 云端职达:你的AI求职专属猎头,颠覆传统招聘模式
  • 哈尔滨云前沿服务器托管与租用服务