Android使用JNI

Android安卓中jni封装代码打包为aar 前文已经介绍jni编译c++代码且已经成功封装成java,但是c++是以源代码形式继承在app中,本文介绍如何将前述jni c++代码以隐藏源代码封装成aar的形式。 阅读详情

参考:

JNI官方:http://developer.android.com/training/articles/perf-jni.html

JNI入门:http://blog.sina.com.cn/s/blog_5f35912f0100vvnn.html

http://blog.sina.com.cn/s/blog_5de73d0b0101chk1.html

http://wenku.baidu.com/view/d670c823a5e9856a56126051.html


Java中的native函数与jni中的C函数是怎样联系起来的:

(1)Test.java,分别代表了四种java函数:非static无参函数、static无参函数、非static有参函数、static有参函数。


package com.jeremyfeinstein.slidingmenu.example;

public class Test {
	public native String test();
	public native static void test2();
	public native void test3(String str);
	public native static void test4(String str);
}

(2)使用javah.exe生成com_jeremyfeinstein_slidingmenu_example_Test.h,点击:(关于javah.exe和NDK的配置请参见:ANDROID 一键搞定JNI创建C头文件),如下所示:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_jeremyfeinstein_slidingmenu_example_Test */

#ifndef _Included_com_jeremyfeinstein_slidingmenu_example_Test
#define _Included_com_jeremyfeinstein_slidingmenu_example_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_jeremyfeinstein_slidingmenu_example_Test
 * Method:    test
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test(JNIEnv *, jobject);

/*
 * Class:     com_jeremyfeinstein_slidingmenu_example_Test
 * Method:    test2
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test2(JNIEnv *, jclass);

/*
 * Class:     com_jeremyfeinstein_slidingmenu_example_Test
 * Method:    test3
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test3(JNIEnv *, jobject, jstring);

/*
 * Class:     com_jeremyfeinstein_slidingmenu_example_Test
 * Method:    test4
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test4(JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif
在当前工程目录的jni目录下自动生成文件com_jeremyfeinstein_slidingmenu_example_Test.h,这个.h文件的名称组成是:java类Test的全称(包名+类名),jni就是通过这个名称组合来找到java类对应C/C++文件的,进而再根据C/C++函数名称来找到对应的调用函数,生成的具有jni格式的C/C++函数名称组成是:Java_包名_java类名_java类中的对应方法名(Java_Java类全称_Java类中对应的方法名),方法参数组成规则是:每个函数的第一个参数都是JNIEvn *类型的;如果函数在Java类中是static的函数,则第二个参数必须是jclass类型,代表当前Java类,如果函数在Java类中是非static类型的函数,则第二个参数必须是jobject类型的,代表的是当前Java类的实例对象;剩下的参数就和java类中的函数的参数一一对应了。

(3)在当前工程目录下的jni目录中找到生成的com_jeremyfeinstein_slidingmenu_example_Test.h,然后再新建一个com_jeremyfeinstein_slidingmenu_example_Test.c文件,并实现com_jeremyfeinstein_slidingmenu_example_Test.h中的所有函数,这里和C/C++的写法一样,只是必须按照jni的格式来写C/C++代码,或者是直接调用已经存在的C/C++代码,这些已经存在的C/C++代码存放的位置也是在当前工程目录下的jni目录中,这样在com_jeremyfeinstein_slidingmenu_example_Test.c中就可以直接遵照JNI标准来调用这部分C/C++代码了。除此之外,还有一点:在具有JNI格式的.c/.cpp文件中可以完全像C/C++文件一样使用C/C++语法,例如可以在.c/.cpp文件中写其他C/C++函数(供其他函数调用),只是这些函数本身必须遵照JNI格式;可以在jni下建立任意的C/C++文件,让程序具有jni格式的C/C++文件调用:


这个地方的test.c和test.h是完全用C/C++语法写的代码,可以在com_jeremyfeinstein_slidingmenu_example_Test.c中进行直接调用;



#include <stdio.h>
#include <jni.h>
#include "com_jeremyfeinstein_slidingmenu_example_Test.h"

JNIEXPORT jstring JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test(JNIEnv *env, jobject obj) {
	return (**env).NewStringUTF(env, "Say hello frome C to Android !");
}

JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test2(JNIEnv *env, jclass clz) {
}

JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test3(JNIEnv *env, jobject obj, jstring str) {
	
}

JNIEXPORT void JNICALL Java_com_jeremyfeinstein_slidingmenu_example_Test_test4(JNIEnv *env, jclass clz, jstring str) {
	
}

(4)上面.h和.c都完成之后,就必须在当前目录下写一个Android.mk文件,这个文件类似C/C++里的Makefile文件,但是Makefile中的依赖文件、编译规则等等都已经被Android系统完成了,Android.mk里的规则很简单,我们只需要按照模板修改添加需要编译的.c或.cpp文件和编译最终生成.so名称即可,关于Android.mk详细语法规则参见:http://blog.youkuaiyun.com/habbyge/article/details/11267081,这里需要特别注意:Android.mk的存放位置,必须和当前编译的C/C++(JNI格式)文件放在同意目录下。


LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE	:= test
LOCAL_SRC_FILES := com_jeremyfeinstein_slidingmenu_example_Test.c

include $(BUILD_SHARED_LIBRARY)

(5)之后,就可以使用NDK编译生成libtest.so文件了,点击:,这个文件被生成在当前工程目录下的libs/armeabi目录下(libs/armeabi/libtest.so),自此就可以在Java中使用这个C/C++代码了,具体使用方法,参见:http://blog.youkuaiyun.com/habbyge/article/details/19857113。



补充:

以上主要是介绍在Java中调用C/C++代码,下面说明C/C++调用Java代码的方法:

C++中调用Java会比较麻烦一些,因为需要在C++中获取Java的运行环境,并寻找我们要用的类和方法。首先我们需要了解几个概念

JavaVM:这个代表java的虚拟机。所有的工作都是从获取虚拟机的接口开始的,如何获取这个接口呢?我们之前导入C的组件时调用了:System.loadLibrary(“test”);

调用该方法时,java会先调用该组件的JNI_OnLoad()函数.其用途有二: 

一是:告诉java VM此C组件使用那一个JNI版本。如果你没有提供JNI_OnLoad()函数,VM会默认使用最老的JNI 1.1版本。由于新版的JNI做了许多扩充,如果需要使用JNI的新版功能,例如JNI 1.4的java.nio.ByteBuffer,就必须藉由JNI_OnLoad()函数来告知VM。

二是:由于VM执行到System.loadLibrary()函数时,就会立即先呼叫JNI_OnLoad(),所以C组件的开发者可以藉由JNI_OnLoad()来进行C组件内的初期值之设定,也就是获取JavaVM接口。

如:

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JniHelper::setJavaVM(vm); // 获取JavaVM接口
    return JNI_VERSION_1_4; // 告知java使用什么版本的VM
}

JNIEnv: 它代表Java环境。通过这个JNIEnv*指针,就可以对Java端的代码进行操作。如,创建Java类得对象,调用Java对象的方法,获取Java对象的属性等。通过之前获得的JavVM我们可以获取JNIEnv:

static bool getEnv(JNIEnv **env) {
    bool bRet = false;
    do {
        if (JAVAVM->GetEnv((void**)env, JNI_VERSION_1_4) != JNI_OK) {
            LOGD("Failed to get the environment using GetEnv()");
            break;
        }
        if (JAVAVM->AttachCurrentThread(env, 0) < 0) {
            LOGD("Failed to get the environment using AttachCurrentThread()");
            break;
        }
        bRet = true;
    } while (0);

    return bRet;
}

有了上面的准备,下面我们就可以开始调用java的东西了:

一:获取对象的类id

我们只要知道类的名字就可以通过JNIEnv来获取classid

jclass classID = pEnv->FindClass(className);

二:获取要调用的方法id,包括静态和普通方法。

    jmethodID methodID = pEnv->GetStaticMethodID(classID, methodName, paramCode);

    jmethodID methodID = pEnv->GetMethodID(classID,methodName, paramCode);

    这其中的最后一个参数代表方法的参数信息,因为java支持多态,只有完整的参数信息才可以找到唯一的方法。这个参数有着特定的格式,见附录。

三:调用方法,同样包括静态和普通。

    pEnv ->CallStatic***Method(classID,methodID);

    pEnv ->Call***Method(classID,methodID);

 不同的返回参数,调用不同的方法,如CallBooleanMethod,CallIntMethod,CallObjectMethod,CallStaticIntMethod等等。
函数签名是一个字符串:"(M)N",括号中的内容是函数的参数类型,括号后面表示函数的返回值。
字符  Java类型     C类型
V   void       void
Z   jboolean    boolean
I   jint        int
J   jlong      long
D   jdouble     double
F   jfloat       float
B   jbyte        byte
C   jchar        char
S   jshort       short
[I   jintArray    int[]
[F   jfloatArray  float[]
[B   jbyteArray   byte[]
[C   jcharArray   char[]
[S   jshortArray  short[]
[D   jdoubleArray double[]
[J   jlongArray   long[]
[Z  jbooleanArray boolean[]
    如果Java函数的参数是class,则以”L”开头,以”;”结尾,中间是用”/” 隔开的包及类名。而其对应的C函数名的参数则为jobject
   
 一个例外是String类,其对应的类为jstring
    Ljava/lang/String; String jstring
    Ljava/net/Socket; Socket jobject

    一个例外是String类,其对应的类为jstring
    Ljava/lang/String; String jstring
    Ljava/net/Socket; Socket jobject

    Ljava/lang/String; String jstring
    Ljava/net/Socket; Socket jobject
 

附:函数属性签名规则:

在GetMethodID最后一个参数是签名字符串,用来标示java函数和成员的唯一性。因为java中存在重载函数,所以一个函数名不足以唯一指定一个函数,这时候就需要签名字符串来指定函数的参数列表和返回值类型了。具体的每一个字符的对应关系如下数组则以”["开始,用两个字符表示

Android Studio 配置NDK,运行第一个hello-jni安卓程序详细步骤 0 前言    本文是我一边操作一边截图记录下来的。理论上来说,如果你环境没有大问题的话,是可以成功运行出结果的。 1 准备工作 已经安装好android studio,  我安装的版本是Android Studio 2.0 Preview已经下载并解压好android ndk, 我下载的版本是 android-ndk64-r10b-windows-x86_64     2 打开a 阅读详情

相关推荐

Android安卓中jni与Java之间传递复杂的自定义数据结构

前文[【Android安卓中封装opencv jni代码为Java类】](https://wanggao1990.blog.youkuaiyun.com/article/details/105179822)简单介绍了jni代码封装为Java接口代码,直接使用opencv的Mat对象的nativeObj作为指针传递进行赋值,以及传递基础类型参数。本文将实现更为复杂的结构对象传递,首先介绍jni基本的数据类型、接口函数和使用示例,再根据一个示例c++封装Java接口,最后说明jni的复杂数据结构传递实现。

热爱生活,忠于自己 1031

Java与C/C++互相调用

C/C++与java互相调用的方法

harmonyluo的博客 998

安卓大厂面试题_安卓开发面经_Android大厂面经(22/30)之JNI全解析

JNI开发是安卓开发必备技能,实用性100分,不过校招或者基础的社招面试时,面试官一般会问有没有用过JNI,用过就加分,讲述一下曾经使用的场景,没用过就下一个问题。所以对于基础面试级别的同学,知道简单的概念和使用方法就行了。

a763450633的博客 436

Android ——JNI基本了解与使用

JNI (Java Native Interface,Java本地接口)是一种编程框架,使得Java虚拟机中的Java程序可以调用本地应用/或库,也可以被其他程序调用。本地程序一般是用其它语言(C、C++或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序。Android NDK开发之JNI基础Android JNI详解JNI入门到精通: 用Java和C/C++打造高性能应用ANDROID STUDIO 创建一个JNI工程创建JNI基础工程并运行JNI基本知识(一)JNI编程原理。

qq_35231506的博客 2352

Android学习--JNI

JNI学习

a130226123的博客 2479

Virtualbox “Kernel driver not installed (rc=-1908)”问题全面解析与修复指南

本文全面解析了Virtualbox出现'Kernel driver not installed (rc=-1908)'错误的原因及修复方法。详细介绍了如何通过重新安装virtualbox-dkms、处理Secure Boot特殊情况等步骤解决该问题,并提供了预防措施与最佳实践,帮助用户避免类似错误再次发生。

weixin_30352645的博客 528

Android之 JNI详解

Android JNI详解

qq_29848853的博客 6442

全球尺度遥感云计算平台:Google Earth Engine

Google Earth Engine(GEE)是一个基于 Google 云服务基础设施的遥感大数据分析平台,它结合 Google 强大的云计算能力与 NASA、ESA、NOAA 等机构的空间数据,用于在全球尺度解决一些非常重要的社会问题:森林退化、粮食安全、灾害预警、水资源管理、气候监测以及环境保护等。 GEE 官方宣传视频(版权归 Google 所有) Spacefan 的视频 ·303播放 发展背景 2008 年,手握 40 多年 LandSat 数据的美国地质调查局(USG...

qq_41240287的博客 5013

Android中的JNI

JNI(Java Native Interface)是Java语言中用于与本地C/C++代码交互的特性,允许Java代码调用本地代码。JNI全称Java Native Interface,是Java语言与本地C/C++代码交互的标准方法。通过JNI,Java代码可以调用本地方法,这些方法以C或C++编写。这种机制使得Java程序能够充分利用底层系统功能,如图形处理、音频处理等。JNI的主要优点包括扩展Java程序的功能、提高性能以及保护代码安全。JNI也是Android的重要组成部分。

qq_55893245的博客 3735

ROS2理论与实践_宇树机器人Go2开发指南(文字)

本文介绍了Unitree Go2机器人ROS2开发环境的安装与配置流程。主要内容包括:1)从GitHub克隆unitree_ros2仓库;2)安装ROS2 Foxy版本依赖项;3)编译特定版本的CycloneDDS(0.10.2);4)编译unitree_go和unitree_api功能包;5)网络配置,包括设置静态IP和修改环境变量脚本setup.sh以指定网络接口。文章还提供了本地回环测试的替代方案,并建议配置完成后重启电脑。整个流程涉及ROS2环境切换、网络适配和编译安装等多个技术环节。

Li_Dongyi的博客 4204

Android安卓Bitmap底层JNI操作

1.添加依赖 头文件: #include <android/bitmap.h> 库依赖:CMakeLists.txt里需要添加jnigraphics库的依赖: target_link_libraries(${MY_LIBRARY_NAME} jnigraphics ... 2.主要方法介绍 2.1 AndroidBitmap_getInfo: 功能:获取Bitmap...

q345911572的博客 2279

主成分分析(PCA)简洁高效MATLAB实现详解

本文介绍了一个简洁高效的PCA算法实现。该实现通过SVD分解计算主成分,避免了显式协方差矩阵计算,支持两种降维方式:固定维度或按能量比例自动选择。核心步骤包括数据中心化、SVD分解和维度选择,代码量少但功能完整,适用于数据预处理、降维和特征提取等任务。实现中考虑了稀疏矩阵转换、默认参数处理等细节,可直接应用于MATLAB环境。

m0_62153576的博客 63

【安卓framework实战】Android JNI 分析与实践

Android JNI 分析与实践 JNI,即Java Native Interface的缩写,中文为Java本地调用,它连接了Java与Native之间的世界。 鉴于功力尚浅,本文从基本概念、原理与实战三个方面对JNI在安卓系统中的使用进行了粗浅的介绍,如果有兴趣可以自行阅读Jdk文档或者其他大神的资料。 通常我们在JDK源码中看到的方法,如果带有native,则表示这个方法是一个本地方法。Thread类中的几个方法,如java程序员经常使用的Thread.sleep(),就是一个native方法。 pa

qq_23542165的博客 788

GameFramework框架详解之 Network网络框架

NetworkManager只负责维护NetworkChannel,实际的有种我们简历网络连接的也是NetworkChannel作为一个网路频道,这样管理起来比较方便,比如:一个游戏可能有多个网络连接,那么我们建立多个网络频道即可,或者当我们一个网络频道断线后,我们可以直接再新建一个,防止数据混乱。/// /// 网络管理器。/// /// 网络频道。/// 用户自定义网络错误事件。/// 检查是否存在网络频道。/// 获取网络频道。/// 获取所有网络频道。

TxNet 3366

(四)C++自制植物大战僵尸游戏启动流程

鼠标左键单机VS2022上方工具栏中进行项目启动。第一次启动项目需要编译项目中所有代码文件,编译生成需要一定的时间。不同性能的电脑需要消耗的时间差别可能较大,通常在几分钟到几十分钟之间。编译成功后会自动启动运行游戏。qi编译成功后自动启动运行游戏如下图。

尔灵尔亿的博客 2466

Android安卓java中jni使用opencv native

前面文章 Android安卓java中使用opencv-android-sdk已经简要介绍如何在Android中使用opencv_sdk_for_java。这里介绍如何使用jni调用c++的opencv库,使用cmake管理并编译生成so库供android使用。 1、创建项目,配置环境 1.1创建项目 创建 “Native C++” 项目,也可以在已有项目中通过修改build.gradle实现。 ...

热爱生活,忠于自己 2479

第十六篇:Camx IFE 、OPE 各 port口功能定义

需要注意的是,类似 CSLTFEPortIdRawDump 是没有downscale功能的,所以如果遇到fov不正确的问题,可以排除下TFE这边的 output port是否被接到了 CSLTFEPortIdRawDump 上面来。我们知道Camx 的IFE 、OPE有不少的output port,各个port是有哪些功能的呢?老一点的框架平台,采用的TEF、OPE。

231

[jni] [android] 用C++开发安卓程序

原理 原理其实很简单 首先用FindClass()查找java类,然后用GetMethodID()得到构造函数 构造函数的函数名是“< init >”,返回类型为"V"(void) 最后直接用NewObject()创建一个按钮 回调部分受到了别人文章和快写代码的启发,把回调类的地址传递到java中,java类接收到事件后用地址作为参数调用本地方法,本地方法把地址转换为c++回调类,调用方法 代码 MainActivity.java package com.Diamond.ndk; impor

qq_53530146的博客 5655

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

android jni总结,安卓JNI总结

jvm将硬件、操作系统底层和应用层隔离开来,使得java成为了一种跨平台语音。java开发人员不需要关心硬件和操作系统的差异,jvm自动将class文件翻译成适合的机器语言。与此同时,很多优秀的库,或者操作系统如Linux,是由C/C++编写的,如果能使用java调用这些库,将会提高开发效率。jni就是java和C/C++代码之间的桥梁。通过JNI,java可以调用C/C++代码。安卓中JNI的使...

weixin_42537919的博客 425

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

安卓接JNI的具体流程

安卓接JNI的具体流程 本次使用开发环境Android Studio 3.4 折腾数天后终于弄明白,遇到各种问题,记录最方便的方法。。。 首先了解为什么要用到JNI //一般用到高速运算的程序都会使用JNI处理图片等等… 建立安卓项目的配置文件 --------------------------------------- apply plugin: ‘com.android.applicatio...

weixin_44055234的博客 1182

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Android JNI:深入分析安卓JNI原理

引言:分析Android源码6.0的过程,一定离不开Java与C/C++代码直接的来回跳转,那么就很有必要掌握JNI,这是链接Java层和Native层的桥梁,本文涉及相关源码: frameworks/base/core/jni/AndroidRuntime.cpp libcore/luni/src/main/java/java/lang/System.java libcore/luni...

不忘初心 3234

Android【JNI动态注册】安卓逆向 -热修复

这样也不会报错👆。

chezabo6116的博客 513

Android安卓中同时使用opencv_android_sdk和jni

前面两篇文章Android安卓java中使用opencv-android-sdk 和Android安卓java中jni使用opencv native 介绍了如何在安卓中使用 opencv的android sdk, 如何在jni中使用opencv库, 以及如何生成 c++类库。 1、介绍 这里我们将在安卓项目中,使用opencv java sdk, 以及通过jni 调用基于opencv c++自定义...

热爱生活,忠于自己 621

安卓JNI基础知识

JNI 是java原生接口(Java Native Interface),它定义了 Android 从受管理代码(使用 Java 或 Kotlin 编程语言编写)编译的字节码与原生代码(使用 C/C++ 编写)进行交互的方法,也就是安卓通过JNI技术提供Java调用C/C++或者C/C++调用Java的能力。JNI 不依赖于供应商,支持从动态共享库加载代码,虽然有时较为繁琐,但效率较高。

Watom_663的博客 1259

[安卓开发笔记二]android Studio通过jni调用C++代码

[安卓开发笔记二]android Studio通过jni调用C++代码 自己需要用到android studio开发安卓项目,为了效率需要用jni来调用C++底层代码,网上关于这方面的资源十分匮乏,自己踩了很多坑,总算明白android studio是如何进行jni的调用,记录与此,贡献自己的一点力量,让后来人少踩坑 1、开发ide:操作系统win7或者mac均可,这点没有关系哈 androi

u012341163的博客 1万+
上一篇: Java堆内存的10个要点
下一篇: Android JNI(实现自己的JNI_OnLoad函数)
HabbyGe
博客等级 码龄16年 46粉丝 143原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值