Android如何调用so文件

Stella981
• 阅读 1177

前言

小编对接的安卓测试项目团队中有部分团队使用C++开发项目代码,出于好奇去学习了解了一下在安卓项目中集成C++代码的方法,下面和大家分享一下。

在安卓开发中经常会遇到需要通过java调用其它语言编写的代码的情况,这主要是由于以下几方面的原因:

  • 1.运行效率高:在高性能要求的需求中,使用本地代码效率更高,如使用CC++编写算法执行效率更高。

  • 2.代码安全性高Java是半解释性语言,容易被反汇编得到源码,而CC++等本地代码则不会。

  • 3.扩展性好:可以使用其他语言开发的开源库。

  • 4.易于复用:用本地代码开发的代码不仅在Android中使用,还可嵌入到其他类型平台上使用。

使用C\C++开发的代码通常编译成so文件对外提供,以便在安卓或其他类型平台上使用。最近在尝试编译C\C++代码产生so文件的时候总结发现so文件的编译产生方式大概经历了3个阶段:

  • 第一个阶段:通过Android.mk文件和Application.mk文件编译产生so文件;

  • 第二个阶段:通过Gradle提供的gradle-experimental插件编译产生so文件;

  • 第三个阶段:目前最常用的方式是使用CMakeGradle编译出so文件。

下面通过一个安卓调用C++代码打印字符串的实例介绍一下在Android Studio中使用最新的编译方式编译出so文件的步骤。

第一步:新建工程

新建工程:打 开 AS ,新建工程。

Android如何调用so文件

Android如何调用so文件

设置 NDK 路径:创 建完工程之后先点击右上角的 Project Structure 按钮设置 NDK 路径,如果没有设置的话则使用 IDE 提供的下载路径。

Android如何调用so文件

Android如何调用so文件

下载SDK工具 :下载界面如下图,需要安装 LLDBCMakeNDK 三个工具:

Android如何调用so文件

另外,本人使用的 Gradle 版本如下:

Android如何调用so文件

第二步:JNI编程

JNIjava调用C\C++代码的接口定义规范,是实现安卓调用C\C++代码必不可少的一部分,下面是本实例中JNI实现相关代码。

定义JNI接口 :创建一个 java 文件,在其中声明 javanative 交互的代码,注意方法需要使用 native 进行修饰。

Android如何调用so文件

生成C\C++头文件 :在 Terminal 中执行下面两句命令,可以看到在工程目录中会产生一个 cpp 文件夹,并且生成了 MyNDK 的头文件。

cd app/src/main/javajavah -d ../cpp com.example.ndkdemo.MyNDK

Android如何调用so文件

编写C\C++实现代码 :在 cpp 路径下创建一个 .cpp 文件,并且在 .cpp 文件中编写与 java 文件中声明的 native 方法相对应的 C++ 代码实现,需要注意的是在 .cpp 文件中需要将 "." 写成 "_"

Android如何调用so文件

#include "com_example_ndkdemo_MyNDK.h"JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_MyNDK_getHelloString   (JNIEnv *env, jclass jclass){   return env->NewStringUTF("Hello JNI!!!!!");}

Android如何调用so文件

第三步:配置编译文件

Gradle需要通过调用CMake编译脚本将C\C++代码编译为java可以调用的外部链接库,所以接下来需要进行GradleCMake的配置。

配置CMakeLists :在 app 目录下创建 CMakeLists.txt 文件并且在其中声明工程要生成的动态库。

Android如何调用so文件

配置项目build.gradle文件

apply plugin: 'com.android.application'android {compileSdkVersion 28defaultConfig {applicationId "com.example.ndkdemo"minSdkVersion 19targetSdkVersion 28versionCode 1versionName "1.0"testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"externalNativeBuild {cmake {cppFlags ""abiFilters 'arm64-v8a', 'armeabi-v7a' //生成多个版本的so文件}}}externalNativeBuild {cmake {path "CMakeLists.txt"}}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}}tasks.withType(JavaCompile){options.encoding = "UTF-8"}dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])implementation 'com.android.support:appcompat-v7:28.0.0'implementation 'com.android.support.constraint:constraint-layout:1.1.3'testImplementation 'junit:junit:4.12'androidTestImplementation 'com.android.support.test:runner:1.0.2'androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'}

Android如何调用so文件

配置部分新增加了两部分 externalNativeBuild 代码,但是这两部分的功能不同:

1) 编译参数 & 编译平台 指定defaultConfig 目录下的是告诉程序编译出什么样的 so 文件。其中, cppFlagsC++ 编译器的参数; ab iFilters 是过滤器,只会编译生成声明的 CPU 架构 so 文件。

2) 编译路径 指定android 目录下的是告诉程序如何去编译, pathCMakeLists.txt 文件目录的地址。

第四步:编译&验证

编译生成so文件 :到现在为止,编译 so 文件的准备工作已经都完成了,这时候只要重新点击一下 make Project 就好了。然后我们就可以发现在 app 目录下生成了 .externalNativeBuild 文件夹,同时在 app\build\intermediates\cmake\debug\obj 目录下生成我们所需要的目标 so 文件。

Android如何调用so文件

调用JNI :现在在我们声明的 getHelloString() 方法之前加载刚才声明产生的 so 库,然后再在程序中调用 getHelloString() 方法就可以执行 so 库中对应的 C++ 代码了。

Android如何调用so文件

开始执行 :运行结果如下:

Android如何调用so文件

结束语

上面是小编自己学习使用 CMakeGradle 编译 so 文件的详细步骤。

但在新版的 Android Studio 中已经支持直接创建 Native C++ 的工程,在这个工程中直接集成了所有需要配置编译 so 的文件,可以在这类项目的基础上进行修改编译出目标 so 文件,更加简单方便。
Android如何调用so文件

Android如何调用so文件

本文分享自微信公众号 - 搜狗测试(SogouQA)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
梦
3年前
微信小程序new Date()转换时间异常问题
微信小程序苹果手机页面上显示时间异常,安卓机正常问题image(https://imghelloworld.osscnbeijing.aliyuncs.com/imgs/b691e1230e2f15efbd81fe11ef734d4f.png)错误代码vardate'2021030617:00:00'vardateT
Stella981 Stella981
3年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这