Android NDK开发基础

2023-05-16

文章目录

      • cmake语法基础
        • cmake添加日志:
        • cmake增加宏
        • 字符串比较
        • cmake在build.gradle中传递编译参数到cmake
      • 通过javah生成native对应的c++头文件
      • jni和java之间字符串的相互操作
      • JavaVM和JNIEnv
      • 字符串的编码
      • native方法静态注册和动态注册
        • 静态注册
        • 动态注册
      • extern c
      • C++中STATIC和SHARE库类型的区别
      • c++控制so导出的函数符号的可见性
      • jni处理异常
      • NDK工具使用:
        • JNI heap

根据日常学习持续更新中

cmake语法基础

cmake添加日志:

message([<mode>] “message text” …)

Record the specified message text in the log. If more than one message string is given, they are concatenated into a single message with no separator between the strings.

mode参数可以有不同的选项,一般不会选择ERROR级别,ERROR会停止cmake运行

  • WARNING: CMake Warning, continue processing.
  • 还有其他很多mode可以参考下面的cmake_message

如果要在日志中打印变量的值的话可以使用${}在引号中包裹变量

message(CHECK_FAIL “missing components: ${variable}”)

message(WARNING  " add definition ")

参考:cmake_message

cmake增加宏

add_definitions(-DDEBUG) 是定义宏-D后面是宏的名称,在c++代码中我们可以使用ifdef DEBUG 来使用我们的编译参数

字符串比较

if ("${variable}" STREQUAL "true"){
}else{
}

获取编译参数重传递到cmake的值,然后比较字符串然后进行判断

cmake在build.gradle中传递编译参数到cmake

 //cmake 的参数配置入口
         externalNativeBuild {
            cmake {
                  // 指定一些编译选项
                cppFlags "-std=c++11 -frtti -fexceptions"
                //如何向变量传递参数,对应的格式如下(arguments "-D变量名=参数")
                arguments '-DANDROID_PLATFORM=android-24', '-DANDROID_STL=c++_static', '-DANDROID_STL=c++_shared'
               // 也可以使用下面这种语法向每个变量传递多个参数(参数之间使用空格隔开),格式如下
               // arguments "-D变量名=参数1 参数2"
                arguments  "-DANDROID_CPP_FEATURES=rtti exceptions"

            }
        }

参考:
https://blog.csdn.net/ljx1400052550/article/details/117280541

通过javah生成native对应的c++头文件

在方法参数前添加native关键字
例如:

    public native String get();

javah 输入命令的目录需要是包名的根目录,也就是需要包含包名
终端路径:/Users/lxd/code/Android/lxdAndroidStart/app/src/main/java
命令:javah com.example.androidstart.JniTest

jni和java之间字符串的相互操作

    const char *str = env->GetStringUTFChars(jstr, JNI_FALSE);
    int len = env->GetStringUTFLength(jstr);
    printf("from java str=%s, len=%d", str, len);
    env->ReleaseStringUTFChars(jstr, str);

在这里插入图片描述

    const char *str = "hello, world";
    return env->NewStringUTF(str);

在这里插入图片描述
方法签名生成:
javap
-s 输出内部类型签名
传入-s后面的参数需要是classes,可以通过javac获取
javac 编译java文件生成class文件/或者可以去项目编译中的中间产物中去寻找class文件
c++ lambda
Lambda表达式完整的声明格式如下:

[capture list] (params list) mutable exception-> return type { function body }

  • capture list:捕获外部变量列表
  • params list:形参列表
  • mutable指示符:用来说用是否可以修改捕获的变量
  • exception:异常设定
  • return type:返回类型
  • function body:函数体

链接:
https://www.cnblogs.com/DswCnblog/p/5629165.html

JavaVM和JNIEnv

JavaVM
JavaVM再Android中只有一个,JavaVM带有函数表,允许你创建和销毁JavaVM。
JNIEnv
JNIEnv提供了大多数的JNI函数,对于C语言的代码,本地函数都需要接收JNIEnv为第一个参数,而对于C++,JNIEnv不需要作为参数传入
JNIEnv用做线程私有存储,因此,不能在线程间共享JNIEnv变量,如果一个代码块没有JNIEnv,可以通过JavaVM去获取
在jni.h的定义中,针对c++和c的不同,有着不同的定义,因此两种语言混用的时候需要注意。
在这里插入图片描述

字符串的编码

java中字符串使用的是UTF-16编码,
JNI中使用 utf-8 表示字符串,UTF-8是变长编码的unicode,一般ascii字符是1字节,中文是3字节;
c/c++使用的是原始数据,ascii就是一个字节了,中文一般是GB2312编码,用两个字节来表示一个汉字。
所以三种类型的字符串如果含有中文的时候需要特殊转换下

native方法静态注册和动态注册

首先我们在java中使用native关键字声明这个方法是native方法,然后使用静态注册或者动态注册,将native方法和c++实现绑定

public native void nativeStaticRegister();

静态注册

生成native方法对应的c++头文件
使用javah生成class文件对应的头文件,-d 第一个参数是输出路径,第二个参数是src目录下的类的全名
在对应的Terminal路径输入命令,我的路径是这个/Users/XXX/code/Android/NativeJni/app/src/main/java

javah -d …/cpp/ com.example.nativejni.CallBackClass

输入了上面的命令后就会在 cpp 目录下生成对应的cpp头文件
直接cpp文件中输入native方法名,as会提示回车后自动补全

或者我们将公共部分提出来,写成一个宏,然后使用宏

#define FFMPEG_FUNC(RETURN_TYPE, FUNC_NAME, ...) \
    JNIEXPORT RETURN_TYPE JNICALL Java_com_example_nativejni_MainActivity_##FUNC_NAME \
    (JNIEnv *env, jclass thiz, ##__VA_ARGS__)

动态注册

动态注册我们在JNI_OnLoad方法中使用RegisterNatives进行注册,将java的native方法和c++进行绑定。
因为绑定的时候需要字节码的方法签名:
获取方法签名的方式

extern c

c++中jni的方法前都有个这个关键字,
不带extern c编译出来的so中的符号

_Z46Java_com_example_nativejni_MainActivity_getvalP7_JNIEnvP8_jobject

带extern c

Java_com_example_nativejni_MainActivity_getval

带extern c编译出来的符号才符合jni命名,extern c让编译器使用c的编译规则编译指定代码
查看so中符号的方法:
在我们的ndk目录下,比如我的路径是

ndk/21.4.7075529/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/
aarch64-linux-android-nm

在这个terminal执行 ./aarch64-linux-android-nm so路径
就会展示出so的符号列表(对于debug包apk中解压出来的so自己试了下需要加上-D参数才能显示动态链接符号)

./aarch64-linux-android-nm --help 查看-D参数的含义
-D, --dynamic Display dynamic symbols instead of normal symbols

参考:https://blog.csdn.net/sinat_36817189/article/details/110423243

C++中STATIC和SHARE库类型的区别

STATIC静态库:变异的时候会将程序和静态库进行链接,可执行程序中会包含当前的静态库,多个可执行程序会有多份静态库。
SHARED动态库:动态库的调用和链接是在运行时,可执行程序中并不包含动态库,多个可执行程序共享一份动态库

c++控制so导出的函数符号的可见性

  1. 当-fvisibility=hidden时动态库中的函数默认是被隐藏的即 hidden. 除非显示声明为__attribute__((visibility("default"))).

  2. 当-fvisibility=default时动态库中的函数默认是可见的.除非显示声明为__attribute__((visibility("hidden")))

jni处理异常

    if (env->ExceptionOccurred()) {
        LOGI("occurred lxd exception");
        env->ExceptionClear();
    }

链接:

java JNI官方教程

NDK工具使用:

ndk-stask查看崩溃堆栈

$NDK/ndk-stack -sym $PROJECT_PATH/obj/local/armeabi-v7a -dump foo.txt

上面的foo.txt指的是崩溃的堆栈,可以从崩溃的日志中拷贝出来,要从*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***开始拷贝,要包含这个

 ./ndk-stack --help
usage: ndk-stack.py [-h] -sym SYMBOL_DIR [-i INPUT]

Symbolizes Android crashes.

optional arguments:
  -h, --help            show this help message and exit
  -sym SYMBOL_DIR, --sym SYMBOL_DIR
                        directory containing unstripped .so files
  -i INPUT, -dump INPUT, --dump INPUT
                        input filename

See <https://developer.android.com/ndk/guides/ndk-stack>.

上面的-sym传入的SYMBOL_DIR要求是unstripped,unstripped是啥意思呢

在我们编译so生成的产物下面,cmake的产物没有strip,so会大很多
在这里插入图片描述
striped目录下面会有去处符号的so,体积会小很多
在这里插入图片描述
/Users/lxd/Library/Android/sdk/ndk/21.4.7075529/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin
strip工具目录

链接:
官方ndk-stack使用教程
https://blog.csdn.net/yangzex/article/details/126581161

addr2line查看代码位置
// 0x12345678为堆栈地址,替换为实际崩溃地址我们可以查看到我们的代码崩溃的位置

aarch64-linux-android-addr2line -e libxxx.so 0x12345678

readelf -d libxxx.so查看其依赖库:

./aarch64-linux-android-readelf --help
-d --dynamic Display the dynamic section (if present)
-s --syms Display the symbol table(查看符号表)

objdump 反汇编so文件

./arm-linux-androideabi-objdump –S libxx.so

JNI heap

参考:
https://blog.csdn.net/u011686167/article/details/124132719

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

Android NDK开发基础 的相关文章

  • 一个强大的iOS瀑布流布局LBWaterFallLayout

    文章目录 效果图实现思路实现原理核心计算逻辑实现代码协议文件 h 文件 m 文件 使用方法 效果图 实现思路 UICollectionView的精髓就是UICollectionViewLayout UICollectionViewLayou
  • vue3使用websocket简易封装,包含错误重连机制

    websocket实现的全双工通信 xff0c 真真太香了 xff0c 以下是笔者在使用时 xff0c 自己封装的一个简易js工具 若需要源码 xff0c 请移步这里 1 初始化连接 64 description 初始化websocket
  • CentOS7.2安装pyspider

    按照pyspider官方QuickStart xff0c 安装pyspider之前先安装pip xff0c 下面命令直接摘抄了 http blog csdn net myfancysky article details 48847971 w
  • Cannot find module ‘@/xxx‘ or its corresponding type declarations.Vetur(2307)

    问题 开发 vue3 43 ts 项目 xff0c 使用了 monorepo 多个项目在同一个仓储 xff0c 但是在 script 标签里引 ts 文件报错了 xff0c vetur 插件没有应用项目下 tsconfig 配置 xff0c
  • C++学习笔记(《C++新经典》基础部分)

    文章目录 第 9 章 指针9 2 变量的指针和指向变量的指针变量9 2 3 指针变量作为函数参数 第 10 章 结构体与共用体10 1 结构体类型定义 xff0c 结构体变量的定义 引用与初始化10 1 1 定义一个结构体类型10 1 2
  • 汇编中基本的数据类型

    1 字节 xff08 DB xff09 define byte 一个字节有8位二进制组成 xff0c 其最高位是第7位 xff0c 最低位是第0位 在表示有符号数时 xff0c 最高位就是符号位 00001001 xff1d 9 10001
  • 不改HOST,另类打开谷歌搜索的方法

    Google 国内外镜像地址 xff1a http www opengg cn http www gfsoso com http www xiexingwen com http www wow com http www 886404 com
  • x86汇编指令详解

    80x86指令系统 80x86指令系统 xff0c 指令按功能可分为以下七个部分 1 数据传送指令 2 算术运算指令 3 逻辑运算指令 4 串操作指令 5 控制转移指令 6 处理器控制指令 7 保护方式指令 3 3 1数据传送指令 数据传送
  • 汇编指令解释大全

    汇编语言指令详讲 2011 05 13 17 31 32 标签 xff1a it 分类 xff1a 汇编 C C java VB编程 AAA 未组合的十进制加法调整指令 AAA ASCII Adgust for Addition 格式 AA
  • 基于 SpringBoot + Vue 实现的可视化拖拽编辑的大屏项目

    一个基于 SpringBoot 43 Vue 实现的可视化拖拽编辑的大屏项目 AJ Report AJ Report由 安吉加加 开源的一个BI平台 xff0c 酷炫大屏展示 xff0c 能随时随地掌控业务动态 xff0c 让每个决策都有数
  • 汇编语言总结笔记

    汇编语言初识 xff08 一 xff09 开始学习汇编语言 xff0c 对相关的所学知识做个总结 xff0c 希望对自己可以有所提高 1 在计算机中数的表示方式 因为计算机中只能存储二进制数 xff0c 所以一般都是通过二进制直接进行存储
  • Ubuntu18.04重启后无法进入图形化界面

    如果你没有瞎卸载很多东西的话 xff0c 先在字符界面输入你的用户名和密码 xff0c 先尝试这个命令 xff1a sudo systemctl isolate graphical target 不行的话 xff0c 我的解决办法 xff1
  • STM32按键外部中断控制LED流水灯-HAL库

    续上一篇 基于HAL库的32流水灯 http t csdn cn 30QT4 一 硬件选用上 xff0c 我们增加一个四角按键 二 原理图设计 xff0c 上也增加一个开关 LED0 LED2 gt PA0 PA2引脚 KEY1 gt PA
  • Linux系统下定时关机命令shutdown

    接触过linux系统的都知道shutdown命令用于安全的关闭 重启计算机 xff0c 用决定命令shutdown不仅可以实现定时关机 xff0c 还可以由用户自己决定关机时的参数 xff1a 以下简单了解一下同样的功能在linux下使用s
  • 解决Ubuntu 显卡驱动升级导致的 显卡驱动和内核版本不匹配的问题

    解决Ubuntu 显卡驱动升级导致的 显卡驱动和内核版本 xff08 同时内核存在问题 xff09 不匹配的问题 不要轻易升级显卡驱动版本 xff01 xff01 xff01 xff01 xff01 xff01 xff01 xff01 xf
  • Nginx+Consul_Upsyc动态切换配置实现动态流量切换

    Nginx 43 Consul Upsyc动态切换配置 大纲 基础概念安装流程测试例子 基础概念 动态配置可以让nginx在不停机的情况下 xff0c 实现动态的切换后端负载的服务器 xff0c 为各种发布方式提供基础的流量切换工作 htt
  • [AHK]实现Word保存前先更新目录

    重新定义热键Ctrl 43 s 用AHK重新定义Ctrl 43 s热键 xff0c 实现当按Ctrl 43 s后 xff0c 会先更新Word中插入的目录 AHK源代码 span class token punctuation span 作
  • win10把中文用户名改为英文用户名的两种方法

    电脑安装好win10系统后后创建了一个中文名的账户 xff0c 进入系统发现C User下的文件夹是中文名 xff0c 虽然中文名方便识别 xff0c 但是这样有一个很不好的地方 xff0c 那就是很多软件安装在个路径下 xff0c 有些软
  • [QMT]08-从本地行情数据解析历史K线信息

    用python解析QMT本地数据 获取本地行情数据 get local data field list 61 stock code 61 period 61 39 1d 39 start time 61 39 39 end time 61
  • Nginx+keepalived实现nginx高可用

    提前备好两台服务器 xff08 主 xff1a 192 168 2 34 xff0c 备 xff1a 192 168 2 24 xff09 xff0c 并安装好nginx xff0c nginx安装此文不做赘述 1 下载keepAlived

随机推荐

  • 提取括号中的内容

    正则能解决不嵌套的括号内容提取问题 遇到一个问题 xff0c 就是需要提取字符串中每一个中括号里的内容 xff0c 在网上搜了一下 xff0c 发现用正则表达式 可以提取中括号中的内容 xff0c 以下面文本为匹配对象 xff1a Perf
  • [AHK]将字符转换成莫尔斯电码

    这个程序可以在记事本中使用 当用户按下空格键时 xff0c 程序会获取当前选中的文本 xff0c 并将其转换为莫尔斯电码播放出来 如果用户选中的文本包含非摩尔斯电码字符 xff0c 程序会自动忽略它们 将字符转换成莫尔斯电码 这个程序可以在
  • 开放原子训练营(第二季)RT-Thread Nano学习营刘玉宽

    目录 前言 RT Thread简介 搭建开发环境 实验过程 1 LED 使用示例 2 按键使用示例 3 自动化执行的示例 4 自定义 msh 命令 5 多线程示例 6 定时器示例 7 消息队列示例 8 摩斯电码使用 实验总结 前言 4月22
  • 关于主机远程唤醒(WOL,Wake on Lan)的几种方法

    WOL 网络唤醒功能非常实用 xff0c 譬如可以用手机遥控电脑开机 xff0c 开启其他房间里的电脑或 NAS xff0c 控制办公室多台电脑批量开关机等 虽然 WOL 主要是在局域网使用 xff0c 但如果配置好公网访问 xff0c 还
  • 双拼和简拼兼容的方案

    双拼和简拼兼容的方案 http wubi sogou com bbs viewthread php tid 61 155980 作者 xff1a Thunk 在双拼状态下 xff0c 如果提供简拼输入 xff0c 往往会增加重码 xff0c
  • cmd /c和cmd /k

    cmd c和cmd k http leaning javaeye com blog 380810 java的Runtime getRuntime exec commandStr 可以调用执行cmd指令 cmd c dir 是执行完dir命令
  • 9 种流行的文件、文件夹比较工具点评 (转贴)

    1 FCU 推荐 xff1a 主页 xff1a http fcu smibe com 功能 xff1a 目录比较 xff0c 文件比较 特点 xff1a 文件比较以三个窗口显示 上部分的左侧窗口和右侧窗口为原始比较文件 xff0c 不同部分
  • 64位windows10,打不chm文件问题,终于解决了。。。

    公司新给配了一台win10笔记本 xff0c 发现打不开chm文件 xff0c 度娘给的方案都是修改文件属性解除锁定之类的 xff0c 根本解决不了问题 经过几天研究 xff0c 发现将chm文件拖放到 SysWOW64中的hh exe可以
  • 蓝牙键盘无法连接 ,win10要求输入pin码可是却不显示pin码

    解决方案 xff1a 打开 设备和打印机 xff0c 切换到在设备上输入密码就可以显示PIN码
  • Vue3-使用axios发起网络请求

    即使是小型项目也会涉及到请求后端API xff0c 除非你的网站展示的是一些不需要维护的静态数据 xff0c 第三篇文章我们来给Vue项目搞上axios 何为Axios xff1f 请看官方对Axios的描述 xff0c 传送门 官方文档
  • linux查看防火墙,开放端口

    1 查看防火墙状态 xff1a active running 即是开启状态 systemctl status firewalld 2 如果不是显示active状态 xff0c 需要打开防火墙 systemctl start firewall
  • UOS 欢迎信息

    赛题 2 操作系统配置 所处区域 CST 8 系统环境语言 English US UTF 8 键盘 English US 注意 当任务是配置TLS 请把根证书或者自签名证书添加到受信任区 控制台登陆后不管是网络登录还是本地登录 都按下方欢迎
  • Vue3-浏览器兼容性 IE篇

    在前端做适配的时候有些客户使用了比较旧的浏览器如IE8 9等 xff0c 前端技术栈中有些功能会出现异常或者无法显示页面 xff0c 记录几个常用的方法对不兼容的浏览器抛出友好异常 检测是否为IE浏览器 span class token k
  • HTTPS-自签证书macOS必须使用thisisunsafe

    HTTPS是站点部署的发展趋势 xff0c 由于HTTP的一系列安全问题 例如网络嗅探时数据报文默认是明文传输 xff0c 容易遭受MitM攻击篡改数据等等 什么是MITM 中间人攻击 xff1f 在内网环境部署站点的时候 xff0c HT
  • Linux-SMTP中继服务器搭建

    本文介绍使用Linux搭建SMTP服务器 xff0c 通过搭配DNS记录修改达到SPF认证的目的 本文参考 xff1a SMTP搭建教程 硬件要求 CPU span class token punctuation span 2C4T 主存
  • Swift5-引入SnapKit

    适用于因网络情况 xff0c 按照SnapKit官方手册引入失败或下载过慢的情况 请先核对Xcode和Swift版本 Xcode Version span class token operator span Version span cla
  • Vue3-减少应用部署打包体积的N种方式【持续更新】

    Vue3默认支持OptionsAPI和Composition API 混编的方式进行开发 xff0c 如果在新系统建设过程中完全抛弃了OptionsAPI方式 xff0c 可以使用vite定义全局变量来告诉Vue关闭对OptionsAPI的
  • Golang-简单-找不同

    题 xff1a 给定两个字符串 s 和 t xff0c 它们只包含小写字母 字符串 t 由字符串 s 随机重排 xff0c 然后在随机位置添加一个字母 请找出在 t 中被添加的字母 示例 1 xff1a 输入 xff1a s 61 abcd
  • Golang-简单-判断子序列

    题 xff1a 给定字符串 s 和 t xff0c 判断 s 是否为 t 的子序列 字符串的一个子序列是原始字符串删除一些 xff08 也可以不删除 xff09 字符而不改变剩余字符相对位置形成的新字符串 xff08 例如 xff0c 34
  • Android NDK开发基础

    文章目录 cmake语法基础cmake添加日志 xff1a cmake增加宏字符串比较cmake在build gradle中传递编译参数到cmake 通过javah生成native对应的c 43 43 头文件jni和java之间字符串的相互