从零开始编写JNI

2023-10-26

最近项目中用到了JNI,本以为很简单的,没想到花了我一天的时间才搞定。主要是在过程中遇到了一个大坑,下面就详细说说。

出现的问题是这样的:代码一运行到System.loadLibrary("xxx")时,就提示java.lang.UnsatisfiedLinkError(Failed to register native method xxx),很明显是在register时出错了,我经过多次尝试,才终于解决这个难题。借着这个问题,再来复习一下jni的整体编写流程吧!

话不多说,直接上代码,c文件如下:

#include <string.h>
#include <jni.h>
#include <android/log.h>
#include <sys/types.h>

#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#define  LOG_TAG1    "ctldevs-jni"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG1,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG1,__VA_ARGS__)

jstring native_stringFromJNI( JNIEnv* env  , jobject thiz )
{
    return (*env)->NewStringUTF(env, "Hello from JNI--Wangdong 111!");//打印字符串 
}

static const char *classPathName = "com/wdong/myapp/MainActivity";

//注意 第一列参数(stringFromJNI),不能带下划线
static JNINativeMethod methods[] = {
       {"stringFromJNI", "()Ljava/lang/String;", (void*)native_stringFromJNI},
};

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jclass clazz;

    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("ERROR: GetEnv failed\n");
        return JNI_ERR;
    }
    clazz = (*env)->FindClass(env,classPathName);
    if (clazz == NULL)
    {
        LOGE("Native registration unable to find class '%s'", classPathName);
        return JNI_ERR;
    }

    if((*env)->RegisterNatives(env, clazz, methods, NELEM(methods)) < 0)
    {
        LOGE("ERROR: MediaPlayer native registration failed\n");
           return JNI_ERR;
    }
 
   return JNI_VERSION_1_4;
}

之所以会报最开始的那个错,就是因为我给methods[]的第一个参数加了_,也就是写成了类似string_FromJNI这样,所以就报错了。因为这个小小的细节,耽误了我近一天的时间,真是有够郁闷的!

methods[]的第二个参数是 (参数)返回值 的形式,举几个例子:

jboolean ( JNIEnv* env  , jobject thiz, jint) 就是(I)Z

jint (JNIEnv* env  , jobject thiz, jint , jstring) 就是 (ILjava/lang/String;)I

void (JNIEnv* env  , jobject thiz, jint, jint) 就是(II)V

methods[]的第三个参数是固定写法,(void *)方法名

这样,一个完整的c文件就写好了,下面写Android.mk文件,用来编译,如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := libwdjni_devs
LOCAL_SRC_FILES := file.c
LOCAL_CFLAGS += -Wno-unused-const-variable -Wno-unused-variable -Wno-unused-parameter 
LOCAL_LDLIBS    := -llog 
include $(BUILD_SHARED_LIBRARY)

接着就该写调用的Java类了,关键代码(MainActivity.java)如下:

static {
        System.loadLibrary("wdjni_devs");/*加载JNI库*/
}

public native String stringFromJNI();

如此一来,就可以使用jni方法了。

Java的Android.mk如下:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_AAPT_INCLUDE_ALL_RESOURCE := true

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-java-files-under,src)

LOCAL_AAPT_FLAGS := \
    --auto-add-overlay \
    --extra-packages android.support.v7.appcompat \
	
LOCAL_STATIC_JAVA_LIBRARIES := \
	android-support-v4 \
    android-support-v7-appcompat \

LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/appcompat/res

LOCAL_JNI_SHARED_LIBRARIES := libwdjni_devs

#LOCAL_REQUIRED_MODULES := wdjni_devs

LOCAL_PACKAGE_NAME := MyApp
LOCAL_CERTIFICATE := platform

LOCAL_PRIVATE_PLATFORM_APIS := false

LOCAL_DEX_PREOPT := false

include $(BUILD_PACKAGE)

include $(call all-makefiles-under,$(LOCAL_PATH))

好了,这样的话,就可以通过mmm,来编译出apk和so库了。

就写到这儿吧!如果你有什么疑问,欢迎留言跟我讨论哈~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从零开始编写JNI 的相关文章

  • chrome 检查器,远程调试在我的移动应用程序上不再正常工作

    我使用 Cordova Ionic 构建了一个渐进式 Web 应用程序 三年来的大部分时间里 我一直在使用开发工具来排除故障并分析我的应用程序的内部工作原理 然而 在过去的几周里 我认为自从 Chrome 更新到 v70 以来 开发工具无法
  • 移动网站 Facebook 使用 Facebook App 登录以获取登录详细信息

    使用网络浏览器 例如Android 上的 Chrome 如果移动网站要求用户登录 Facebook 而用户没有登录 则即使手机可能通过 Facebook 本机应用程序登录 Facebook 浏览器也会要求用户提供登录详细信息 有没有什么方法
  • 尝试在 Android 上使用 FFMPEG。编译但是还是不行

    首先 我尝试使用 ffmpeg 将图像数组编译成 Android 上的视频 我已经遵循了各种在线教程 并且已经能够编译 Android 的库 但仍然需要项目运行 我现在使用的存储库可以在这里找到 https github com Batte
  • 创建后如何更新使用 AlertDialog.builder 构建的 AlertDialog 列表中的项目数组

    我使用 AlertDialog builder 创建了一个对话框 显示可以检查的多项选择列表 我设置了初始的项目名称集及其检查状态 builder setMultiChoiceItems saveTargets names saveTarg
  • OneSignal 推送通知 单击以打开活动

    我集成了一个用于推送通知的信号库 我想在应用程序未运行时通过单击推送通知来打开特定活动 我收到推送通知 但当我单击通知时 应用程序崩溃了 这是我的通知接收器代码 public class ExampleNotificationOpenedH
  • 如何知道哪个用户正在尝试登录?

    用户是使用电子邮件和密码创建的 这就是我进行注册的方式 mSignup setOnClickListener new View OnClickListener Override public void onClick View v mEma
  • Android - 如何获取文本视图中字符的坐标

    是否可以从 Android 中的 TextView 中的字符获取 x 坐标 我不是在寻找 TextView 本身的坐标 我需要 TextView 中最后一个字符的坐标 多行 提前致谢 Java解决方案 以下是如何获得x and y特定字符的
  • Android HTTP-post AsyncHttpClient

    public void postLoginData AsyncHttpClient myClient new AsyncHttpClient RequestParams params1 new RequestParams params1 p
  • 如何在Android中使用QML - QWebView

    我想在 Android 中部署一个 YouTube 应用程序 但它只能在我的电脑上运行 在安卓上不起作用 它不加载任何视频 问题仅出在 QWebView 上 我使用了与此类似的代码 http doc qt io archives qt 5
  • 检查从 arrayadapter 获取的复选框

    我有标题清单 CheckBox 我想控制默认检查哪一个 所以我试图获得正确的视图并检查它 但由于某种原因它不起作用 知道为什么吗 form checkbox item xml
  • __stack_chk_fail_local 和 -fno-stack-protector - 如何让它工作?

    Update 我刚刚发现问题出在我的项目 libxml2 中包含的预构建库上 它是在启用堆栈保护的情况下构建的 因此依赖于 stack chk fail local方法 我现在已经重建了该库 fno stack protector也是 一切
  • 像 Google Play 商店一样在垂直 RecyclerView 中动态不同图像水平 RecyclerView

    我一直在关注这个教程 http android pratap blogspot co za 2015 12 horizo ntal recyclerview in vertical html http android pratap blog
  • 为什么 Android Eclipse 不断刷新外部文件夹并花费很长时间?

    我只有一部新的 Android 手机 我一直在修补一些基本的应用程序 每当我保存任何内容时 Eclipse 的 Android 插件就会刷新外部文件夹 这让我抓狂 通常我不会介意 但当需要 10 秒才能刷新时 我开始注意到 我已经搜索过 其
  • Android:TelephonyManager 类

    我不明白为什么 API 文档中这么写TelephonyManager类是public 但是当我尝试创建一个实例时 它说它不是公共类 并且无法从包中访问 我看到它也说使用Context getSystemService Context TEL
  • Firestore OncompleteListener [重复]

    这个问题在这里已经有答案了 我想看看这段代码的执行有什么错误 当我编译它时 它只返回 log 1 3 2 的值 并且我希望 log2 在 3 之前 Log d 1 antes de validar DocumentReference doc
  • Android - 带动画的可扩展 TextView

    我有一个TextView首先显示长文本的一小部分 用户可以按 查看更多 按钮来展开TextView并查看该文本的其余部分 进行测试 我可以通过简单地交换以下值来实现这一点TextView setMaxLines介于 4 之间 用于折叠 和
  • 如何在Android 11中获取dir文件列表

    我想编写自己的精简版文件浏览器 文件 API 现在不适用于外部存储 该版本还提供了对范围存储的改进 这使得开发人员可以更轻松地迁移到使用此存储模型 我不明白如何使用范围存储来访问 sdcard 如果您正在寻找文件选择器体验 存储访问框架 h
  • 为什么 fork 炸弹没有使 android 崩溃?

    这是最简单的叉子炸弹 我在许多 Linux 发行版上执行了它 但它们都崩溃了 但是当我在 android 终端中执行此操作时 即使授予后也没有效果超级用户权限 有什么解释为什么它没有使 Android 系统崩溃吗 一句话 ulimit Li
  • Android:防止嗅探(例如使用 CharlesProxy)SSL 流量

    我使用 Charles 检查将我的应用程序发送到 HTTPS 的数据 我在手机上安装了 Charles CA 证书 因此我能够解密每个 SSL 流量 但我发现一些应用程序无法看到 SSL 流量 我如何将这种行为实现到我自己的应用程序中 有了
  • 允许使用 SurfaceTexture 在 GLSurfaceView 渲染器中进行多通道渲染

    我正在显示视频GLSurfaceView使用需要连续应用多个着色器的自定义渲染器 目前 它可以成功地使用一个着色器 但我不确定如何扩展渲染管道以连续应用多个着色器 我知道有一些关于应用多个着色器的示例 使用FrameBuffers and

随机推荐

  • DVWA-XSS (Stored) Low/Medium/High低中高级别

    作者简介 CSDN top100 阿里云博客专家 华为云享专家 网络安全领域优质创作者 推荐专栏 对网络安全感兴趣的小伙伴可以关注专栏 网络安全入门到精通 XSS Stroed 一 Low级别 二 Medium级别 三 Hign级别 这关是
  • 七、VPN技术之隧道技术原理与VPN技术原理(PPTP协议、L2TP协议、MPLS VPN、Web VPN)

    更多网络基础内容可见 网络基础学习目录及各章节指引 7 2 GRE 虽然计算机网络技术已经逐步发展完善和成熟 并且具有通用的OSI模型体系和TCP IP模型体系 但是各类厂商公司在研发自己的网络设备时 依旧会有自己私有协议的存在 当我们在发
  • Python3.7 Scrapy 执行爬虫任务提示:Unknown command: crawl

    Windows cmd 窗口执行爬虫任务指令 提示如下错误信息 错误的原因 误删了Scrapy 项目下的scrapy cfg的文件 导致上面错误情况的发生
  • Python 邻接矩阵实现无向图、有向图的三种方法,并绘图显示

    网上查了很多资料 发现主要是使用邻接表来实现图 并进行遍历的 而采用邻接矩阵的就非常少 不得已 就只有闭门造车 埋头苦修 小有成果 供后来学习者研究 通过二维数组建立无向图 通过二维数组建立有向图 通过边建立有向图 为方便查看 通过Netw
  • 【模块介绍】WS2812(硬件部分)

    目录 引脚定义 电气属性 电路连接 PCB 软件部分 引脚定义 这是数据手册中引脚定义图和连接方式 可以看出 这个灯是自带芯片控制R G B三色的亮度 可以通过上级的DOUT gt 下级的DIN来使其进行级联 电容官方建议是使用100nF
  • 【元壤教育AI提示工程系列】『KeepChatGPT教程』轻松解决ChatGPT网络报错,畅享无忧沟通!

    元壤教育 中国AIGC提示工程培训的佼佼者 关注 元壤教育 公众号 系统学习AIGC系列课程 提升您10倍生产力 装插件前是这样的 我们使用ChatGPT时 总是因为网络魔法不力的原因导致页面总是报错 如下图所示 装完插件后是这样的 外链图
  • Java整合Redis实现腾讯云短信服务(轻松入门,超详细)

    目录 Java使用腾讯云短信服务 一 短信服务简介 二 准备工作 二 Java操作 三 项目链接 Java使用腾讯云短信服务 一 短信服务简介 首先我们要大致知道短信服务是干什么的 云服务提供商通过短信服务向手机号发送短信 我们可以在云服务
  • PowerShell切换路径

    打开PowerShell 输入以下代码 加将要转换的路径 回车 Set location Path
  • iOS学习笔记一

    文章目录 一 深浅拷贝 二 消息转发机制 三 运行时添加一个类 一 深浅拷贝 浅拷贝只是将指针赋值 而深拷贝进行了内容传递 在Objective C中 NSObject的拷贝方式有两种 copy和mutablecopy 对于NSString
  • 我的2013

    今天是2013年的最后一天 天气格外的晴朗 站在公司的写字楼上 能够看到远处的山水 一直都习惯在一年的最后总结一下 总结自己哪些地方在成长 哪些地方有收获 哪些地方需要改进 但是最近一两年来 却很难回忆一些什么 因为每天都过的差不多 今天下
  • 96道前端面试题+前端常用算法

    这篇文章主要分享一些收集整理的面试题 希望能对大家有所帮助 字节 一面 1 说一下浏览器缓存 2 cookie 与 session 的区别 3 浏览器如何做到 session 的功能的 4 解释一下 csrf 和 xss 5 怎么防止 cs
  • TypeError: load() missing 1 required positional argument: ‘Loader‘

    最近使用yaml load 时报错 TypeError load missing 1 required positional argument Loader 记录原因 YAML 5 1版本后弃用了yaml load file 这个用法 因为
  • 面向对象编程思想

    面向对象编程思想 Object Oriented Programming 面向过程编程思想面向过程核心思想 自顶向下 逐步求精 面向对象编程思想面向对象核心思想 以对象为单位 将解决客观世界问题的方式方法引入到编程领域中 面向对象编程是面向
  • SpringBoot 2.x应用监控配置

    Springboot 2 x应用监控 作用 用于管理 监控应用 暴露自身信息 减少应用系统在采集应用指标的开发量 1 添加依赖
  • 区块链基本概念(一)

    区块链的基本概念 其概念为 区块链是一个去中心化的分布式数据库 改数据库有一串使用密码学方法产生的数据区块有序连接而成 区块中包含有一定时间内产生的无法被篡改的数据记录信息 区块中包含数据记录 当前区块根哈希 Hash 前一区块根哈希 时间
  • Java注解与反射详解

    Java注解与反射详解 注解 Annotations 是Java语言中的一项功能强大的特性 它们提供了一种在源代码中添加元数据的方式 注解可以用于标记 配置和处理程序中的元素 如类 方法 字段等 而反射 Reflection 是Java的一
  • 鸿鹄工程项目管理系统em Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统

    Java版工程项目管理系统 Spring Cloud Spring Boot Mybatis Vue ElementUI 前后端分离 功能清单如下 首页 工作台 待办工作 消息通知 预警信息 点击可进入相应的列表 项目进度图表 选择 总体或
  • [羊城杯 2023] web

    文章目录 D0n t pl4y g4m3 D0n t pl4y g4m3 打开题目 可以判断这里为php Development Server 启动的服务 查询得知 存在 PHP lt 7 4 21 Development Server源码
  • 第5讲 Java注释详解

    您的 关注 和 点赞 是认可 是支持 是动力 如意见相佐 可留言 本人必将竭尽全力试图做到准确和全面 终其一生进行修改补充更新 本文首发在IT羊资源网 IT羊资源网 网址 https www ityangzy com IT羊资源网是IT世界
  • 从零开始编写JNI

    最近项目中用到了JNI 本以为很简单的 没想到花了我一天的时间才搞定 主要是在过程中遇到了一个大坑 下面就详细说说 出现的问题是这样的 代码一运行到System loadLibrary xxx 时 就提示java lang Unsatisf