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.mzph.cn/news/739333.shtml

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

相关文章

【梳理】k8s使用Operator搭建Flink集群(高可用可选)

文章目录 1. 架构图2. helm 安装operator3. 集群知识k8s上的两种模式&#xff1a;Native和Standalone两种CR 4. 运行集群实例Demo1&#xff1a;Application 集群Demo2&#xff1a;Session集群优劣 5. 高可用部署问题1&#xff1a;High availability should be enabled when sta…

3.1_2 覆盖与交换

3.1_2 覆盖与交换 &#xff08;一&#xff09;覆盖技术 早期的计算机内存很小&#xff0c;比如IBM 推出的第一台PC机最大只支持1MB大小的内存。因此经常会出现内存大小不够的情况。 后来人们引入了覆盖技术&#xff0c;用来解决“程序大小超过物理内存总和”的问题。 覆盖技术的…

DevOps-Jenkins-CI持续集成操作

创建项目 创建个web项目 我这里直接用Spring Web自动生成的demos 启动项目&#xff0c;访问展示如下默认页面信息 项目新增Docker构建配置 在项目下新建docker目录&#xff0c;新增Dockerfile、docker-compose.yml文件 Dockerfile文件&#xff0c;将mytest.jar 复制到容器的…

移动硬盘无法读取怎么修复?分享三个简单方法

移动硬盘作为现代数据存储的重要工具&#xff0c;一旦出现故障&#xff0c;往往会让我们感到焦虑和困惑。当移动硬盘无法读取时&#xff0c;我们需要冷静分析并采取适当的措施来修复它。本文将为您介绍三种有效的修复方法。 一、检查物理连接与驱动程序 当移动硬盘无法读取时&…

LiveGBS流媒体服务器中海康摄像头GB28181公网语音对讲、语音喊话的配置

LiveGBS海康摄像头国标语音对讲大华摄像头国标语音对讲GB28181语音对讲需要的设备及服务准备 1、背景2、准备2.1、服务端必备条件&#xff08;注意&#xff09;2.2、准备语音对讲设备2.2.1、不支持跨网对讲示例2.2.2、 支持跨网对讲示例 3、开启音频开始对讲4、搭建GB28181视频…

动手学深度学习-注意力机制Transformer

注意力机制 1. 注意力提示 1.1. 生物学中的注意力提示 **自主性提示&#xff08;随意线索&#xff09;&#xff1a;收到认知和意识的控制&#xff0c;有主观意愿的推动。**如下图&#xff0c;所有纸制品都是黑白印刷的&#xff0c;但咖啡杯是红色的。 换句话说&#xff0c;这…

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

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

Python元组(Tuple)深度解析!

目录 1. 什么是元组&#xff1f; 2. 创建元组 3.访问元组 4.元组的运算 5.修改元组不可行 6.元组的应用场景 前面的博客里&#xff0c;我们详细介绍了列表&#xff08;List&#xff09;这一种数据类型&#xff0c;现在我们来讲讲与列表相似的一种数据类型&#xff0c;元组…

【Python】【Matplotlib】fig, ax = plt.subplots() 返回的fig和ax是什么?

【Python】【Matplotlib】fig, ax plt.subplots() 返回的fig和ax是什么&#xff1f; &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&a…

求职干货!如何自信地进行自我介绍和面试问答!

面试在求职过程中扮演着至关重要的角色。它不仅是雇主评估候选人能力和适应性的关键环节&#xff0c;也是候选人展示自我、展示技能和经验的绝佳机会。通过面试&#xff0c;雇主可以更直接地了解候选人的沟通能力、解决问题的能力以及团队合作精神&#xff0c;这些都是成功工作…

ChatGPT GPT4科研应用、数据分析与机器学习、论文高效写作、AI绘图技术

原文链接&#xff1a;ChatGPT GPT4科研应用、数据分析与机器学习、论文高效写作、AI绘图技术https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247596849&idx3&sn111d68286f9752008bca95a5ec575bb3&chksmfa823ad6cdf5b3c0c446eceb5cf29cccc3161d746bdd9f2…

实例成员、静态成员

一、静态成员先于实例成员存在 类被加载到内存时&#xff0c;静态变量分配内存空间&#xff0c;静态方法分配入口地址 只有创建对象之后&#xff0c;实例变量分配内存空间&#xff0c;实例方法分配入口地址 当再创建对象时&#xff0c;实例方法不再分配入口地址&#xff0c;…

【Java从发入门到精通】Java StringBuffer 和 StringBuilder 类

Java StringBuffer 和 StringBuilder 类 当对字符串进行修改的时候&#xff0c;需要使用 StringBuffer 和 StringBuilder 类。 和 String 类不同的是&#xff0c;StringBuffer 和 StringBuilder 类的对象能够被多次的修改&#xff0c;并且不产生新的未使用对象。 在使用 Stri…

蓝桥杯[OJ 3412]-最小化战斗力差距-CPP-贪心

目录 一、问题描述&#xff1a; 二、整体思路&#xff1a; 三、代码&#xff1a; 一、问题描述&#xff1a; 二、整体思路&#xff1a; 首先每个值都有可能为min(b)&#xff0c;那么对于每个可能为min(b)的值&#xff0c;要使得max(a)尽可能小&#xff0c;因此枚举所有相差最…

高颜值抓包工具Charles,实现Mac和IOS端抓取https请求

Hi&#xff0c;大家好。在进行测试的过程中&#xff0c;不可避免的会有程序报错&#xff0c;为了能更快修复掉Bug&#xff0c;我们作为测试人员需要给开发人员提供更准确的报错信息或者接口地址&#xff0c;这个时候就需要用到我们的抓包工具。 常见的抓包工具有Fiddler、Char…

【NR技术】 3GPP支持无人机服务的关键性能指标

1 性能指标概述 5G系统传输的数据包括安装在无人机上的硬件设备(如摄像头)收集的数据&#xff0c;例如图片、视频和文件。也可以传输一些软件计算或统计数据&#xff0c;例如无人机管理数据。5G系统传输的业务控制数据可基于应用触发&#xff0c;如无人机上设备的开关、旋转、升…

Oracle之ADG与DG的区别?

在上云后的Oracle数据灾备场景中&#xff0c;我们经常听到DBA迁移工程师讲到“在这个项目中用ADG进行数据实时备份&#xff0c;ADG比DG更好&#xff01;”。究竟ADG作Oracle数据灾备的优势在什么地方&#xff1f; 一、ADG主要解决了DG时代读写不能并行的问题 DG时代的数据同步…

c# winform部门管理系统

c# winform部门管理系统 数据库SQL语句脚本代码 CREATE TABLE Department(DepartmentID INT PRIMARY KEY IDENTITY(1,1),Name NVARCHAR(50) NOT NULL ); SELECT * FROM Department -- 插入部门数据 INSERT INTO Department (Name) VALUES (人力资源部); INSERT INTO Departmen…

【c 语言 】移位操作符详解

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;C语言 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步&…

C++感受1-打开浏览器,线上玩转C++

介绍了五款在线编译、编译、运行的C线上环境。并选择其中的 “在线GDB” 网站动手编写、运行第一个C程序 “Hello World”&#xff0c;同时和线下IDE进行对比。 1. 课堂视频 打开浏览器&#xff0c;线上玩转C 2. 在线C编译环境对比 onlinegdb &#xff1a; www.onlinegdb.comr…