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

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.xdnf.cn/news/19881.html

相关文章:

  • % g++ *.cpp ...: fatal error: ‘opencv2/opencv.hpp‘ file not found 1
  • 数论常见公式定理大全
  • 无需服务器,免费、快捷的一键部署前端 vue React代码--PinMe
  • 嵌入式学习 51单片机基础
  • 《微服务协作实战指南:构建全链路稳健性的防御体系》
  • AR技术赋能风电运维:精准、高效、智能
  • 算法模板(Java版)_非负整数的高精度运算
  • 【论文阅读】Jet-Nemotron: 高效语言模型与后神经网络架构搜索
  • 研发团队缺乏统一文档模板怎么办
  • 服务器的监控和管理手段有哪些?
  • 【LeetCode牛客数据结构】单链表的应用——环形链表及链表分割问题详解
  • 【Python3教程】Python3高级篇之多线程
  • Chrome浏览器调用ActiveX控件之allWebOffice在线编辑控件
  • 记录收入最高的一次私活 选号网,需要大量卖号的人可能需要,比如游戏脚本批量跑的号
  • 电脑配置不足怎么办,告别硬件束缚,川翔云电脑
  • 从Oracle到PostgreSQL的数据库迁移
  • MySQL中binlog、redolog与undolog的不同之处解析
  • 传统大数据 Hadoop 和 云原生湖仓 Databend 对比
  • Spring MVC + JSP 项目的配置流程,适合传统 Java Web 项目开发
  • LangGraph 重要注意事项和常见问题
  • 猫头虎AI分享:无需OCR,基于ColQwen2、Qwen2.5和Weaviate对PDF进行多模态RAG的解决方案
  • 基于STM32的居家养老健康安全检测系统
  • 中文分词器之结巴分词
  • GPT-Realtime 弹幕TTS API 低延迟集成教程
  • leetcode111. 二叉树的最小深度
  • 2025华为最值得入的耳机,真的赢麻了!
  • golang 依赖管理
  • 【C++详解】C++11(三) 可变参数模板、包扩展、empalce系列接⼝、新的类功能
  • 大数据开发环境搭建(Linux + Hadoop + Spark + Flink + Hive + Kafka)
  • ELK 统一日志分析系统部署与实践指南(下)