AndroidStudio NDK环境3种搭建方式
一、前言
如今Android开发IDE都是使用的AndroidStudio,之前我写过一篇文章介绍的是如何在Eclipse中搭建NDK环境 Android NDK --初始android NDK
这边博客介绍下在AndroidStudio中搭建NDK环境的三种方式。
二、知识点概述
本片我们将从以下几点初步认识、创建Android NDK:
1.Java加载/调用NDK端的代码;
2.本地 c++代码的编写;
3.编写构建系统文件(android.mk、application.mk)
4.通过构建系统编译c++代码
4.1、通过Gradle搭建NDK环境;
4.2、通过NDKBuild搭建NDK环境(重点介绍);
4.3、通过CMake搭建NDK环境;
三、知识点详解
(1)Java加载/调用NDK端的代码
1、Java端代码:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("helloworld");
}
private TextView mDataView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mDataView = (TextView) this.findViewById(R.id.tv_data);
mDataView.setText(getStrFromNative());
}
private native String getStrFromNative();
}
2、在AndroidStudio打开命令行界面,cd app/src/main/java 运行
javah com.zhangjunling.ndk_environment_gradle.MainActivity
- 1
这时会自动在目录下生成一个com_zhangjunling_ndk_environment_gradle_MainActivity.h文件,把文件拷贝到 main/jni 目录中。
(2) 本地 c++代码的编写
由于本编只是介绍NDK环境的搭建问题,所以代码越简单越容易把所有的精力都放在环境搭建上,所以c++代码只是简单的 HelloWrold程序;
helloworld.cpp
#include "com_zhangjunling_ndk_environment_gradle_MainActivity.h"
JNIEXPORT jstring JNICALL Java_com_zhangjunling_ndk_1environment_1gradle_MainActivity_getStrFromNative
(JNIEnv *env, jobject obj){
return env->NewStringUTF("Hello. I'm form native");
}
(3)编写构建系统文件
在jni目录下创建Android.mk、Application.mk文件内容如下:
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := helloworld
LOCAL_SRC_FILES := helloworld.cpp
include $(BUILD_SHARED_LIBRARY)
APP_STL := gnustl_static
APP_ABI := armeabi
关于构建系统里面的键值对的含义,现在先不关心,下篇文章我会详细介绍;
(4)通过构建系统编译c++代码
通过Gradle搭建NDK环境
Gradle是androidstudio上的编译工具,我们可以通过从项目下的local.properties获取ndk.dir=xxxxxxxx,获取ndk-build路径,然后执行ndk-build便可以编译出需要的动态库文件;gradle的语法这里不在进行讲解,感兴趣的可以从网络上获取资料学习;
build.gradle代码如下:
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.zhangjunling.ndk_environment_gradle"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
jniLibs.srcDir 'src/main/libs'
jni.srcDirs = []
}
}
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
String getNdkBuildPath() {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def ndkBuildingDir = properties.getProperty("ndk.dir")
def ndkBuildPath = ndkBuildingDir
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
ndkBuildPath = ndkBuildingDir + '/ndk-build.cmd'
} else {
ndkBuildPath = ndkBuildingDir + '/ndk-build'
}
return ndkBuildPath
}
task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
println('executing ndkBuild')
def ndkBuildPath = getNdkBuildPath();
commandLine ndkBuildPath, '-j8', '-C', file('src/main').absolutePath
}
task ndkClean(type: Exec, description: 'clean JNI libraries') {
println('executing ndkBuild clean')
def ndkBuildPath = getNdkBuildPath();
commandLine ndkBuildPath, 'clean', '-C', file('src/main').absolutePath
}
clean.dependsOn 'ndkClean'
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'
}
- 1过工具栏 Build/ReBuild Project,观察到libs目录、obj目录自动产生,没有报错。这可以说明我们的配置没有什么问题;可以运行项目看到:
Hello. I'm form native
通过NDKBuild搭建NDK环境(重点介绍)
通过ndk-build交叉编译c++本地代码是我们重点学习的,后面我会重点介绍通过ndk-build交叉编译出我们需要的动态库。本篇只介绍环境的搭建。
Android.mk构建好了之后,ndk-build环境就比较简单了,步骤:
项目右键->Link C++ Project With Gradle
路径选择Android.mk 就OK 了。
通过CMake搭建NDK环境
CMake搭建NDK环境有两种方式:
1、与ndk-build相同
项目右键->Link C++ Project With Gradle
路径选择CMakeList.txt 就OK 了。
2、在Create Android Project的时候底部勾选Include C++ support,项目创建好了之后,自动创建好了NDK环境。我们可以在此基础上开发NDK。
项目路径:AndroidStudio环境搭建源码
三种方法 app/build.gradle文件内容如下:
import org.apache.tools.ant.taskdefs.condition.Os apply plugin: 'com.android.application' android { compileSdkVersion 28 defaultConfig { applicationId "com.example.myapplication" minSdkVersion 16 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk { moduleName "Test" ldLibs "log" // abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库,目前可有可无 } // 使用Cmake工具-way1 //start way1 // externalNativeBuild { // cmake { // cppFlags "" // abiFilters 'arm64-v8a','armeabi-v7a','x86','x86_64' // } // } } // // 配置CMakeLists.txt路径-way1 // externalNativeBuild { // cmake { // path "CMakeLists.txt" // 设置所要编写的c源码位置,以及编译后so文件的名字 // } // end way2 // 设置按android.mk 进行编译-way2 //start way2 externalNativeBuild { ndkBuild { path "src/main/jni/Android.mk" } } //end way2 buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } // sourceSets.main { // jni.srcDirs = ['src/main/jni', 'src/main/jni/'] // jniLibs.srcDirs "src/main/libs" // } sourceSets { main { jniLibs.srcDir 'src/main/libs' jni.srcDirs = [] } } compileOptions { sourceCompatibility = '1.8' targetCompatibility = '1.8' } buildToolsVersion = '28.0.3' } /* //begin -- way3 tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn ndkBuild } String getNdkBuildPath() { Properties properties = new Properties() properties.load(project.rootProject.file('local.properties').newDataInputStream()) def ndkBuildingDir = properties.getProperty("ndk.dir") def ndkBuildPath = ndkBuildingDir if (Os.isFamily(Os.FAMILY_WINDOWS)) { ndkBuildPath = ndkBuildingDir + '/ndk-build.cmd' } else { ndkBuildPath = ndkBuildingDir + '/ndk-build' } return ndkBuildPath } task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') { println('executing ndkBuild') def ndkBuildPath = getNdkBuildPath(); commandLine ndkBuildPath, '-j8', '-C', file('src/main').absolutePath } task ndkClean(type: Exec, description: 'clean JNI libraries') { println('executing ndkBuild clean') def ndkBuildPath = getNdkBuildPath(); commandLine ndkBuildPath, 'clean', '-C', file('src/main').absolutePath } clean.dependsOn 'ndkClean' //end-way3 */ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:2.0.0-alpha4' 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' }
在app/build.gradle同目录下的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. #CMakeLists.txt #指定需要CMake的最小版本 cmake_minimum_required(VERSION 3.4.1) # 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. # 设置so文件名称. Test # Sets the library as a shared library. SHARED # 设置这个so文件为共享. # Provides a relative path to your source file(s). # 设置这个so文件的源码文件. src/main/jni/Test.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. # 制定目标库. Test # Links the target library to the log library # included in the NDK. ${log-lib} )
在jni目录下的Android.mk内容如下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := Test LOCAL_SRC_FILES := Test.cpp LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
在jni目录下的Application.mk内容如下:
APP_MODULES := Test APP_PLATFORM := android-16 APP_ABI := all