首页 > 其他分享 >Android JNI/NDK环境的配置与Demo编译

Android JNI/NDK环境的配置与Demo编译

时间:2024-05-23 18:18:58浏览次数:22  
标签:NDK Java Demo 代码 JNI jni Android

一、背景

​ JNI(Java Native Interface)和NDK(Native Development Kit)在Android开发中扮演着重要的角色。

JNI,即Java本地接口,是Java平台的一部分,它允许Java代码与其他语言写的代码进行交互。通过JNI,Java代码可以调用本地应用程序或库中的代码,也可以被本地代码调用。这主要使得Java能够和本地其他类型语言(如C、C++)进行交互。JNI的一个主要用途是,当Java层的应用代码需要执行一些计算密集型或者对实时性要求高的任务时,可以通过JNI调用本地层的C/C++代码来提高性能。同时,JNI也允许Java调用由C/C++实现的驱动,从而扩展JAVA虚拟机的能力。

而NDK,即本地开发工具包,是一组工具的集合,它允许开发者使用C和C++代码来开发Android应用的部分组件。NDK提供了必要的工具链和库,帮助开发者编译和构建本地代码(C/C++代码),生成可以在Android应用中使用的本地库(.so文件)。NDK的主要用途包括:提高应用的性能,通过使用C/C++代码实现关键部分来优化性能;复用现有的C/C++代码库,无需将其重写为Java代码;访问低级系统API和硬件,例如直接操作图像数据或使用特定的硬件指令。

总的来说,JNI和NDK在Android开发中主要用于提高应用的性能、复用代码、访问底层硬件和操作系统特性等。例如,游戏开发可以通过NDK和JNI调用原生代码,实现高质量的游戏体验;使用C或C++语言可以更方便地调用系统提供的接口,实现更安全和更高效的文件操作。

二、NDK的环境搭建

  1. Java环境:正常的classpath和javahome的配置。

  2. ndk:在androidstudio中配置好了ndk环境

补充:ndk环境搭建

在 Android Studio 中配置环境以便能够开发本地代码(如 C 或 C++)涉及到几个步骤。

1. 下载 NDK
下载NDK包:https://developer.android.google.cn/ndk/downloads?hl=zh-cn

2. 在 Android Studio 中配置 NDK 路径
(1)点击菜单栏的 File -> Project Structure
(2)在左侧面板中,选择 SDK Location。(原来设置过就不用管)
(3)在 Android NDK location 字段中,点击右侧的 ... 按钮。(注:如果这里是灰色的就说明你没有下载ndk包)
(4)浏览并选择你之前解压 NDK 的目录。
(5)点击 OK 保存设置。
    
3. 在你的项目中配置 CMake 或 ndk-build
	Android Studio 支持 CMake 和 ndk-build 作为构建本地代码的工具。你需要选择其中一个,并在你的项目中配置它。

(1)CMake 配置:
	在你的项目根目录下创建一个名为 CMakeLists.txt 的文件(如果尚未创建)。
在这个文件中,定义你的本地源代码和构建规则。
在 app 模块的 build.gradle 文件中,添加对 CMake 的支持。例如:
gradle
android {  
    ...  
  
    defaultConfig {  
        ...  
  
        externalNativeBuild {  
            cmake {  
                cppFlags ""  
            }  
        }  
    }  
  
    externalNativeBuild {  
        cmake {  
            path "CMakeLists.txt"  
            version "3.10.2" // 使用你安装的 CMake 版本  
        }  
    }  
}

(2)ndk-build 配置:【比较常用】
	在你的项目根目录下创建一个名为 Android.mk 和一个名为 Application.mk 的文件(如果尚未创建)。
在这些文件中,定义你的本地源代码和构建规则。
在 app 模块的 build.gradle 文件中,添加对 ndk-build 的支持。例如:
gradle
android {  
    ...  
  
    defaultConfig {  
        ...  
  
        ndk {  
            moduleName "your_module_name" // 替换为你的模块名  
        }  
    }  
  
    sourceSets.main {  
        jni.srcDirs = [] // 禁用默认的 jni 源目录  
        jniLibs.srcDirs = ['libs'] // 指定你的 .so 文件目录,记得.so文件要放到这里
    }  
}

4. 同步你的项目
	点击 Android Studio 工具栏中的 Sync Now 按钮,以确保你的项目配置已正确同步。

5. 编写和构建本地代码
	现在你可以在你的项目中编写本地代码,并使用 Android Studio 的构建系统来编译它。你应该能够在 app/build/intermediates/cmake 或 app/build/intermediates/ndkBuild(取决于你使用的构建系统)目录下找到生成的 .so 文件。

三、JNI类的编译与链接流程

在Android开发中,编译JNI(Java Native Interface)的.so(共享对象)库通常涉及几个步骤。以下是一个简化的流程,并附带一个示例来说明如何编译JNI库。

1. 编写Java类

首先,你需要一个Java类来声明本地方法。这些方法将由C/C++代码实现。

package com.example.testsdk.jni;
  
public class MyJniClass {  
    // 加载本地库  
    static {  
        System.loadLibrary("my-jni-lib");  
    }  
  
    // 声明本地方法  
    public native String nativeStringFromJNI();  
}

2. 生成JNI头文件

使用javah工具(在JDK中)从Java类生成JNI头文件。这个头文件将包含Java本地方法的C/C++签名。

 C:\Android-project\testSdk\app\src\main\java> javah -jni com.example.testsdk.jni.MyJniClass

这将在jni目录下生成一个名为com_example_testsdk_jni_MyJniClass.h的头文件。

3. 编写C/C++代码

实现Java中声明的本地方法。在C/C++代码中,你需要包含上面生成的头文件。

// jni/my_jni_lib.c  
#include <jni.h>  
#include "com_example_myjni_MyJniClass.h"  
  
JNIEXPORT jstring JNICALL  
Java_com_example_testsdk_jni_MyJniClass_nativeStringFromJNI(JNIEnv *env, jobject obj) {  
    return (*env)->NewStringUTF(env, "Hello from JNI!");  
}

4. 配置CMake或ndk-build

对于Android NDK项目,你需要配置CMake或ndk-build来编译C/C++代码。以下是一个简化的CMakeLists.txt示例:

# CMakeLists.txt  
cmake_minimum_required(VERSION 3.4.1) 

#添加自己的so库test-lib,设置一个名字,输出就是这个名字
add_library(  
    my-jni-lib  
    SHARED  
    my_jni_lib.c  
)  
  
find_library(  
    log-lib  
    log  
)  
 
#链接cpp文件
target_link_libraries(  
    my-jni-lib  
    ${log-lib}  
)

5. 在Android项目中配置NDK

在Android项目的build.gradle文件中,确保你已经配置了NDK。例如:

android {  
    ...  
  
    defaultConfig {  
        ...  
  
        externalNativeBuild {  
            cmake {  
                cppFlags ""  
            }  
        }  
    }  
  
    externalNativeBuild {  	
        cmake {  
            path "CMakeLists.txt"  
            version "3.10.2"  
        }  
    }  
}

6. 编译项目

​ 现在可以编译Android项目了。Gradle将使用CMake或ndk-build来编译C/C++代码,并生成.so库。这些库将被包含在APK中,并在运行时由Java代码加载。(通过build->make project或者rebuild project)

7. 在Java代码中加载和使用库

​ 在Java代码中,可以像之前那样使用System.loadLibrary("my-jni-lib")来加载库,并调用本地方法。

注意:这个示例假设已经在Android项目中正确设置了NDK和CMake。如果还没有设置,需要先下载NDK并在Android Studio中配置它。

8.测试so的正确性

  1. 在native类中加载so文件

     static {
            System.loadLibrary("my-jni-lib");
        }
    

    注意:我们生成的so文件名为libmy-jni-lib.so,但是我们不需要lib这个前缀,只需要把我们在cmake中配置的名字加载进去即可。

  2. 正常调用

     testJni = new TestJni();
     textView.setText(testJni.getMessage());
    

补充:

这段代码是Gradle构建脚本(通常用于Android应用或库的构建)中的一部分,特别是在配置Native Development Kit (NDK) 支持时。

这里,ndk 配置块定义了哪些ABI(Application Binary Interface)或CPU架构应该被编译和包含在最终的APK中。ABI决定了应用或库如何与设备的底层硬件进行交互。

具体解释如下:

x86_64:这是为基于x86架构的64位处理器编译的。这种架构主要在模拟器(如Android Studio的模拟器)和一些高端平板电脑或Chromebooks上使用。
armeabi-v7a:这是为基于ARM架构的32位处理器编译的,特别是那些支持ARMv7指令集的处理器。这是Android设备中最常见的架构之一,许多旧的和中端设备都支持它。
arm64-v8a:这是为基于ARM架构的64位处理器编译的,特别是那些支持ARMv8指令集的处理器。这种架构在现代高端Android设备上越来越普遍。
通过在ndk块中指定这些ABI,你可以确保你的应用或库在具有这些处理器架构的设备上运行时具有最佳性能。同时,这也允许你减少APK的大小,因为你不需要包含所有可能的ABI的二进制文件。

注意:从Android Gradle Plugin 3.0开始,Google推荐只包含armeabi-v7a和arm64-v8a,因为Google Play会提供x86的二进制文件翻译服务。然而,如果你的应用或库对性能非常敏感,或者你正在使用模拟器进行开发,那么包含x86_64可能仍然是有意义的。

标签:NDK,Java,Demo,代码,JNI,jni,Android
From: https://www.cnblogs.com/lxpblogs/p/18209133

相关文章

  • Android11快速编译并替换framework.jar
    Android11快速编译并替换framework.jar在Android11之前修改了framework相关代码,只需makeframework就可以编译出framework.jar。在Android11,这个编译命令不起作用了,根据framework/base/目录下Android.bp中的提示:java_library{name:"framework-minus-apex",defaults:......
  • 同样的APP为何在Android 8以后网络感觉变卡?
    前言 在无线网络技术不断发展的今天,Wi-Fi已经成为了我们日常生活中不可或缺的一部分。无论是家庭娱乐、办公还是在线游戏,Wi-Fi都在提供着便捷的互联网接入服务。然而,在安卓8.1后,为了进一步延长安卓设备的待机时间。原生安卓(AOSP等)默认开启了全局省电(低功耗模式),该模式下W......
  • QGIS开发笔记(二):Windows安装版二次开发环境搭建(上):安装OSGeo4W运行依赖其Qt的基础环境De
    前言  使用QGis的目的是进行二次开发,或者说是融入我们的应用(无人车、无人船、无人机),本片描述搭建QGis二次基础开发环境,由于实在是太长了,进行了分篇:上半部分:主要是安装好后,使用QtCreator可以使用QGIs的apps下的Qt使用对应的编译器编译不带qgis的空工程。下半部分:在上半......
  • 基于ADB Shell 实现的 Android TV、电视盒子万能遥控器 — ADB Remote ATV
    ADBRemoteATVAndroidTV的遥控器,基于ADBShell命令ADBRemoteATV是一个AndroidTV的遥控器,基于ADBShell命令,泛用性更高。下面的shell命令,是软件的基本原理,通过shell命令可模拟物理遥控器的基本按键,此外还可以快捷启动指定APP、借助手机软键盘输入中/英字符等。......
  • Android-Studio-应用开发-全-
    AndroidStudio应用开发(全)原文:zh.annas-archive.org/md5/B5F07A8FF00989BA587D2F4F3EBF3E11译者:飞龙协议:CCBY-NC-SA4.0前言在过去的几年里,移动应用程序的受欢迎程度大幅上升,用户对此的兴趣仍在增长。移动操作系统不仅适用于智能手机,也适用于平板电脑,因此这些应用程序可......
  • Netty 客户端与服务端收发消息demo
    客户端与服务端收发消息,要实现的具体功能是:在控制台输入一条消息之后按回车键,校验完客户端的登录状态之后,把消息发送到服务端;服务端收到消息之后打印,并向客户端发送一条消息,客户端收到消息之后打印。 客户端NettyClientimportcom.xc.xcspringboot.x_netty.client.handler.*;......
  • netty 最简demo
    Netty是什么Netty到底是何方神圣?用一句简单的话来说就是:Netty封装了JDK的NIO,让你用得更方便,不用再写一大堆复杂的代码了。用官方正式的话来说就是:Netty是一个异步事件驱动的网络应用框架,用于快速开发可维护的高性能服务端和客户端。使用Netty而不使用JDK原生NIO的原因1.使用J......
  • qt之点的绘制示例demo
    #include"mainwindow.h"#include"ui_mainwindow.h"#include<QPainter>#include<QColor>QColorm_color;intm_x=0;intm_y=0;intm_w=0;intm_h=0;MainWindow::MainWindow(QWidget*parent):QMainWindow(parent)......
  • Android导出所有多语言字串到表格
    这种事情当然要写脚本完成啦,不然一个一个添加嘛?!!!python脚本:##注意:##1.有些语言的符号可能会乱码,比如es--->¡---->?##2.base_strings.xml必须包含所有key值,作为基准,否则可能会楼填。##3.使用:依次将不同语言的xml文件内容复制到target_strings.xml中,运行MergeLa......
  • Android查看apk安装包的AndroidManifest.xml文件
    Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解`Android查看apk安装包的AndroidManifest.xml文件日期:2020-4-19阿珏折腾代码浏览:946次评论:5条起因上周在做安卓系统的厂家推送功......