前言
小编对接的安卓测试项目团队中有部分团队使用
C++
开发项目代码,出于好奇去学习了解了一下在安卓项目中集成C++
代码的方法,下面和大家分享一下。在安卓开发中经常会遇到需要通过
java
调用其它语言编写的代码的情况,这主要是由于以下几方面的原因:
1.运行效率高:在高性能要求的需求中,使用本地代码效率更高,如使用
C
、C++
编写算法执行效率更高。2.代码安全性高:
Java
是半解释性语言,容易被反汇编得到源码,而C
、C++
等本地代码则不会。3.扩展性好:可以使用其他语言开发的开源库。
4.易于复用:用本地代码开发的代码不仅在
Android
中使用,还可嵌入到其他类型平台上使用。
使用
C\C++
开发的代码通常编译成so
文件对外提供,以便在安卓或其他类型平台上使用。最近在尝试编译C\C++
代码产生so
文件的时候总结发现so
文件的编译产生方式大概经历了3个阶段:
第一个阶段:通过
Android.mk
文件和Application.mk
文件编译产生so
文件;第二个阶段:通过
Gradle
提供的gradle-experimental
插件编译产生so
文件;第三个阶段:目前最常用的方式是使用
CMake
和Gradle
编译出so
文件。下面通过一个安卓调用C++代码打印字符串的实例介绍一下在
Android Studio
中使用最新的编译方式编译出so
文件的步骤。
第一步:新建工程
新建工程:打 开
AS
,新建工程。
设置
NDK
路径:创 建完工程之后先点击右上角的Project Structure
按钮设置NDK
路径,如果没有设置的话则使用IDE
提供的下载路径。
下载
SDK
工具 :下载界面如下图,需要安装LLDB
、CMake
、NDK
三个工具:
另外,本人使用的
Gradle
版本如下:
第二步:JNI编程
JNI
是java
调用C\C++
代码的接口定义规范,是实现安卓调用C\C++
代码必不可少的一部分,下面是本实例中JNI
实现相关代码。定义
JNI
接口 :创建一个java
文件,在其中声明java
与native
交互的代码,注意方法需要使用native
进行修饰。生成
C\C++
头文件 :在Terminal
中执行下面两句命令,可以看到在工程目录中会产生一个cpp
文件夹,并且生成了MyNDK
的头文件。cd app/src/main/javajavah -d ../cpp com.example.ndkdemo.MyNDK
编写
C\C++
实现代码 :在cpp
路径下创建一个.cpp
文件,并且在.cpp
文件中编写与java
文件中声明的native
方法相对应的C++
代码实现,需要注意的是在.cpp
文件中需要将"."
写成"_"
。#include "com_example_ndkdemo_MyNDK.h"JNIEXPORT jstring JNICALL Java_com_example_ndkdemo_MyNDK_getHelloString (JNIEnv *env, jclass jclass){ return env->NewStringUTF("Hello JNI!!!!!");}
第三步:配置编译文件
Gradle
需要通过调用CMake
编译脚本将C\C++
代码编译为java
可以调用的外部链接库,所以接下来需要进行Gradle
和CMake
的配置。配置
CMakeLists
:在app
目录下创建CMakeLists.txt
文件并且在其中声明工程要生成的动态库。配置项目
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'}
配置部分新增加了两部分
externalNativeBuild
代码,但是这两部分的功能不同:1) 编译参数 & 编译平台 指定 :
defaultConfig
目录下的是告诉程序编译出什么样的so
文件。其中,cppFlags
是C++
编译器的参数;ab
iFilters
是过滤器,只会编译生成声明的CPU
架构so
文件。2) 编译路径 指定 :
android
目录下的是告诉程序如何去编译,path
是CMakeLists.txt
文件目录的地址。
第四步:编译&验证
编译生成
so
文件 :到现在为止,编译so
文件的准备工作已经都完成了,这时候只要重新点击一下make Project
就好了。然后我们就可以发现在app
目录下生成了.externalNativeBuild
文件夹,同时在app\build\intermediates\cmake\debug\obj
目录下生成我们所需要的目标so
文件。
调用
JNI
:现在在我们声明的getHelloString()
方法之前加载刚才声明产生的so
库,然后再在程序中调用getHelloString()
方法就可以执行so
库中对应的C++
代码了。
开始执行 :运行结果如下:
结束语
上面是小编自己学习使用
CMake
和Gradle
编译so
文件的详细步骤。但在新版的
Android Studio
中已经支持直接创建Native C++
的工程,在这个工程中直接集成了所有需要配置编译so
的文件,可以在这类项目的基础上进行修改编译出目标so
文件,更加简单方便。
本文分享自微信公众号 - 搜狗测试(SogouQA)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。