Android 生成SO - 基础工程创建

最近需要给小伙伴扫盲一下如何使用Android Studio 生成一个SO文件,网上找了很多都没有合适的样例,那只能自己来写一个了。

原先生成SO是一个很麻烦的事情,现在Android Studio帮忙做了很多的事情,基本只要管好自己的C代码即可。

创建工程

  • C++ Standard :使用下拉列表选择你希望使用哪种 C++ 标准。选择 Toolchain Default 会使用默认的 CMake 设置。

 创建后报错的问题

 这个是由于我默认使用的 java 1.8 ,需要至少升级到 java11

创建完成后的工程样式

工程解析 

native-lib.cpp

这个工程我是这样理解的,native-lib.cpp 是实际编写C++代码的部分,这里来定义方法

#include <jni.h>
#include <string>
#include <android/log.h>extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {std::string hello = "Hello from C++";// 使用 android log输出日志__android_log_print(ANDROID_LOG_INFO, "log", "Hello log from JNI function");return env->NewStringUTF(hello.c_str());
}

extern "C" JNIEXPORT jstring JNICALL

在 JNI(Java Native Interface)中,extern "C" 用于指定 C++ 函数按照 C 语言的命名和调用约定来处理。JNIEXPORTJNICALL 是 JNI 提供的宏,通常用于声明 JNI 函数,这两个宏通常会展开为适合当前环境的修饰符。

  • extern "C" 告诉编译器按照 C 语言的规则处理函数 stringFromJNI
  • JNIEXPORT 表示该函数将被导出供 JNI 调用。
  • JNICALL 是一个宏,用于设置正确的调用约定。

include

上面 include 就是C当中引入相关库的地方。

这里我加了  #include <android/log.h> 用于使用Android log 方法:__android_log_print

这里不可以直接使用C原生的 printf("Hello log from JNI function\n")

因为在 Android 开发中,printf 输出的内容通常不会直接显示在 Logcat 中。Android 应用默认会将 stdoutstderr 重定向到 /dev/null,因此 printf 的输出不会在 Logcat 中出现

Java_com_example_myapplication_MainActivity_stringFromJNI

  • Java: 这个部分表示这是一个 JNI 函数的标识符,表明该函数是与 Java 代码进行交互的本机方法。

  • com_example_myapplication_MainActivity: 这部分指定了 Java 类的完整路径,即 com.example.myapplication.MainActivity。这个路径应该与包名和类名一致,使用下划线 _ 替代点号 .

  • stringFromJNI: 这部分是 Java 类中方法的名称,这个名称应该与 Java 类中定义的native方法名称一致。也就是 :public native String stringFromJNI();

CMakeLists.txt 

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html# Sets the minimum version of CMake required to build the native library.cmake_minimum_required(VERSION 3.22.1)# Declares and names the project.project("myapplication")# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.add_library( # Sets the name of the library.myapplication# Sets the library as a shared library.SHARED# Provides a relative path to your source file(s).native-lib.cpp)# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.find_library( # Sets the name of the path variable.log-lib# Specifies the name of the NDK library that# you want CMake to locate.log)# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.target_link_libraries( # Specifies the target library.myapplication# Links the target library to the log library# included in the NDK.${log-lib})

这里逐条解析

  • cmake_minimum_required(VERSION 3.22.1)

这个指定了构建该项目所需的最低 CMake 版本为 3.22.1、

  • project("myapplication")

声明并命名项目为 "myapplication"

  • add_library

创建并命名一个库,设置为 SHARED 类型,并提供源代码文件的相对路径。在此示例中,创建了名为 myapplication 的共享库,并提供了 native-lib.cpp 源文件的路径。

  • find_library

在系统路径中搜索指定的预构建库,并将其路径存储为变量。在这里,查找名为 log 的 NDK 库,并将路径存储在 log-lib 变量中。

  • target_link_libraries

指定要链接到目标库的库。在这里,将 myapplication 目标库链接到 log NDK 提供的 log 库。


所以当你需要改变生成的so的名称时,需要改动 add_library中的myapplication以及关联target_link_libraries中的值,不然报错。

同时,可以看到 find_library 作用是引入log库,如果不使用log,那么这个就并不是必须的,如果我在native-lib.cpp 中不使用那句  __android_log_print ,那么就可以精简为:

cmake_minimum_required(VERSION 3.22.1)project("myapplication")add_library(myapplication SHARED native-lib.cpp)

MainActivity

package com.example.myapplicationimport androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.widget.TextView;import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.myapplication.databinding.ActivityMainBindingpublic class MainActivity extends AppCompatActivity {// Used to load the 'myapplication' library on application startup.static {System.loadLibrary("myapplication");}private ActivityMainBinding binding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());// Example of a call to a native methodTextView tv = binding.sampleText;tv.setText(stringFromJNI());}/*** A native method that is implemented by the 'myapplication' native library,* which is packaged with this application.*/public native String stringFromJNI();}

这个其实没什么可以多说的,就是标准的调用,这里可以测试调用需要的代码。同时,因为so对 class的包名以及方法名固定的特性,使用so的地方也需要这里的代码。

SO编译

如果只是测试,可以直接run apk 。对应的文件会生成在如下位置。

此时,apk中只会包含和你测试设备相符合的so架构

但是当你需要多个架构时,需要在 build.gradle 中进行指定

然后直接编正式APK即可。

编完之后再apk 中可以获取到你需要的架构so

SO安全

这里额外聊一下这个事情,很多人觉得代码放在SO里面,别人不好反编译,更加的安全。

但是有一个盲点,就是别人在看完你的 Android 代码之后,读完你 native定义,可以直接使用你的so来进行操作。

例如你把关键的加密函数做成SO,明文 -> so -> 密文,或者 密文 -> so -> 明文,那别人直接调用你的so就解密了。特别是使用加固的项目,so很多都不加固,只加固java,这样反而不安全。

所以so至少要进行签名校验。当然so的校验也借助 java 的packagemanage,也就是容易被上层hook,这个我们有额外的对抗方案,这里不细说。

放一个so获取签名的代码在这里。具体的so代码后面有机会再开新坑

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_getAppSignature(JNIEnv *env,jobject obj) {jclass context_class = env->FindClass("android/content/Context");jmethodID method_getPackageManager = env->GetMethodID(context_class, "getPackageManager","()Landroid/content/pm/PackageManager;");jmethodID method_getPackageName = env->GetMethodID(context_class, "getPackageName","()Ljava/lang/String;");jobject context = obj;jobject package_manager = env->CallObjectMethod(context, method_getPackageManager);jstring package_name = static_cast<jstring>(env->CallObjectMethod(context,method_getPackageName));jclass package_manager_class = env->GetObjectClass(package_manager);jmethodID method_getPackageInfo = env->GetMethodID(package_manager_class, "getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");// 获取签名信息jobject package_info = env->CallObjectMethod(package_manager, method_getPackageInfo, package_name, 64);jclass package_info_class = env->GetObjectClass(package_info);jfieldID field_signatures = env->GetFieldID(package_info_class, "signatures","[Landroid/content/pm/Signature;");jobjectArray signatures = (jobjectArray) env->GetObjectField(package_info, field_signatures);jobject signature = env->GetObjectArrayElement(signatures, 0);jclass signature_class = env->GetObjectClass(signature);jmethodID method_toCharsString = env->GetMethodID(signature_class, "toCharsString","()Ljava/lang/String;");jstring signature_str = (jstring) env->CallObjectMethod(signature, method_toCharsString);return signature_str;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/274337.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据“隐领”未来!【隐私计算实训营】限时免费招募!

数智经济时代&#xff0c;为强化个人隐私信息保护&#xff0c;国家颁布了《国家安全法》、《网络安全法》、《数据安全法》等数据安全法律法规&#xff0c;并严厉处罚数据违规出海、侵权、滥用等问题。数据安全和隐私保护成为大家的共识。隐私计算技术在此背景下应运而生&#…

物联网云原生云边协同

文章目录 一、物联网平台设计1.物联网平台设计2.物联网平台实现 二、部署环境1.节点配置2.版本信息 三、物联网平台部署1.部署 Kubernetes 集群2.部署 KubeEdge3.部署 ThingsBoard 集群4.部署 ThingsBoard Edge4.1.创建 Edge 实例4.2.部署 PostgreSQL4.3.创建数据库4.4.部署 Th…

【C++】类与对象

文章目录 1. 面向过程与面向对象2. 类&#xff08;class&#xff09;类的作用域 3. 访问限定符封装 4. 类的实例化5. this指针6. 默认成员函数6.1 构造函数6.2 析构函数6.3 拷贝构造函数 1. 面向过程与面向对象 C语言是面向过程&#xff08;procedure-oriented&#xff09;的语…

“成像光谱遥感技术中的AI革命:ChatGPT应用指

遥感技术主要通过卫星和飞机从远处观察和测量我们的环境&#xff0c;是理解和监测地球物理、化学和生物系统的基石。ChatGPT是由OpenAI开发的最先进的语言模型&#xff0c;在理解和生成人类语言方面表现出了非凡的能力。本文重点介绍ChatGPT在遥感中的应用&#xff0c;人工智能…

数字脉搏:互联网的演进与社会脉络

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

React-路由小知识

1.默认路由 说明&#xff1a;当访问的是一级路由时&#xff0c;默认的二级路由组件可以得到渲染&#xff0c;只需要在二级路由的位置去掉path,设置index.属性为true。 2.404路由 说明&#xff1a;当浏览器输入ul的路径在整个路由配置中都找不到对应的pth,为了用户体验&#x…

【蓝桥杯】路径之谜(DFS)

一.题目描述 小明冒充 X 星球的骑士&#xff0c;进入了一个奇怪的城堡。 城堡里边什么都没有&#xff0c;只有方形石头铺成的地面。 假设城堡地面是 nn 个方格。如下图所示。 按习俗&#xff0c;骑士要从西北角走到东南角。可以横向或纵向移动&#xff0c;但不能斜着走&#x…

如何在Linux使用Docker部署Firefox并实现无公网IP访问本地浏览器

文章目录 1. 部署Firefox2. 本地访问Firefox3. Linux安装Cpolar4. 配置Firefox公网地址5. 远程访问Firefox6. 固定Firefox公网地址7. 固定地址访问Firefox Firefox是一款免费开源的网页浏览器&#xff0c;由Mozilla基金会开发和维护。它是第一个成功挑战微软Internet Explorer浏…

基于React低代码平台开发:直击最新高效应用构建

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》《项目实战》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录…

浅析开源内存数据库Fastdb

介绍&#xff1a; Fastdb是免费开源内存数据库&#xff0c;其优秀的性能&#xff0c;和简洁的C代码&#xff0c;让我学习使用过程中收益颇多&#xff0c;但是国内中文相关研究的文章相当稀少&#xff0c;外文我查询相当不便。有兴趣的朋友可以通过以下网站访问&#xff1a;Mai…

Redis 内存的优化

目录 前言 Redis 的内存碎片问题 判断Redis 内存碎片 如何清理内存碎片&#xff1f; 前言 我想讲一下怎么提高Redis 内存的利用率&#xff0c;redis 的数据是保存在内存中。对内存的利用率低&#xff0c;意味着存的数据很少&#xff0c;并不意味着就没有内存了&#xff0c…

【办公类-21-09】三级育婴师 视频转文字docx(等线小五单倍行距),批量改成“宋体小四、1.5倍行距、蓝色字体”

作品展示&#xff1a; 背景需求&#xff1a; 一、视频处理 1、育婴师培训的现场视频 2、下载视频&#xff0c;将视频换成考题名称 二、音频 视频用格式工厂转成MP3音频 3、转文字doc 把音频放入“网易云见外工作台”转换为“文字" 等待5分钟&#xff0c;音频文字会被写…

工地安全反光衣穿戴监测报警摄像机

工地安全反光衣穿戴监测报警摄像机是为了提高工地施工人员的安全意识和监管效率而设计的。这种设备结合了反光衣、监测系统和报警摄像机的功能&#xff0c;可以有效减少工地事故的发生。 首先&#xff0c;工地安全反光衣是一种具有高度可见度的服装&#xff0c;能够使穿戴者在夜…

混合测试写一写

题目 服务器IP地址规划&#xff1a;client&#xff1a;12.0.0.12/24&#xff0c;网关服务器&#xff1a;ens36:12.0.0.1/24、ens33&#xff1a;192.168.44.1/24&#xff0c;Web1&#xff1a;192.168.44.30/24&#xff0c;Web2&#xff1a;192.168.44.50/24&#xff0c;Nginx&am…

Draco点云压缩测试

ref&#xff1a;https://github.com/google/dracohttps://codelabs.developers.google.com/codelabs/draco-3d/index.html#6 Draco Draco 是一个用于编码压缩和解压缩 3D 几何网格和点云的库&#xff0c;从而改进 3D 图形的存储和传输该代码支持压缩点、连接信息、纹理坐标、颜…

男人的玩具系统wordpress外贸网站主题模板

垂钓用品wordpress外贸模板 鱼饵、鱼竿、支架、钓箱、渔线轮、鱼竿等垂钓用品wordpress外贸模板。 https://www.jianzhanpress.com/?p3973 身体清洁wordpress外贸网站模板 浴盐、防蚊液、足部护理、沐浴液、洗手液、泡澡用品wordpress外贸网站模板。 https://www.jianzhan…

【恒源智享云】conda虚拟环境的操作指令

conda虚拟环境的操作指令 由于虚拟环境经常会用到&#xff0c;但是我总忘记&#xff0c;所以写个博客&#xff0c;留作自用。 在恒源智享云上&#xff0c;可以直接在终端界面输入指令&#xff0c;例如&#xff1a; 查看已经存在的虚拟环境列表 conda env list查看当前虚拟…

隐私与创新的交汇点:Partisia Blockchain 重绘技术蓝图

正当我们在这个信息泛滥的时代寻找稳固的信任锚点时&#xff0c;区块链技术应运而生&#xff0c;然而&#xff0c;正如任何科技革命都会遇到的挑战&#xff0c;一个重要的问题摆在了我们面前&#xff1a;如何在不牺牲个人隐私的前提下&#xff0c;享受区块链技术带来的好处&…

【AI视野·今日NLP 自然语言处理论文速览 第八十四期】Thu, 7 Mar 2024

AI视野今日CS.NLP 自然语言处理论文速览 Thu, 7 Mar 2024 Totally 52 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers The Heuristic Core: Understanding Subnetwork Generalization in Pretrained Language Models Authors Adith…

python模块(二)

time模块 时间戳格式 import time data_timetime.time() print(data_time) #1702546257.544845 print(type(data_time)) #<class float> #打印自1970年到现在的时间 1702546257.544845 #打印123&#xff0c;每一次停4s while True:print(123)time.sleep(4)…