Android游戏开发实践(1)之NDK与JNI开发03

Android游戏开发实践(1)之NDK与JNI开发03

前面已经分享了两篇有关Android平台NDK与JNI开发相关的内容。以下列举前面两篇的链接地址,感兴趣的可以再回顾下。那么,这篇继续这个小专题,主要分享下AndroidStudio下的NDK与JNI开发的相关操作以及简述下CMake的使用。最后,会以一个实例来结束这个小专题的分享,那个,就放在最后一篇吧。

传送门:
Android游戏开发实践(1)之NDK与JNI开发01
Android游戏开发实践(1)之NDK与JNI开发02

本文的目录如下:

  • 1、环境搭建
  • 2、创建一个支持C/C++的项目
    • 2.1 新建项目
    • 2.2 扩展现有项目
  • 3、AndroidStudio与Gradle
    • 3.1 project/build.gradle
    • 3.2 project/settings.gradle
    • 3.3 module/build.gradle

<h3 id="get-start">1、 环境搭建</h3>

要让AndroidStudio支持NDK开发,除了需安装AndroidStudio2.2以上的版本。还得安装NDKCMakeLLDB等工具。
在AndroidStudio中选择Tools->Android->SDK Manager->SDK Tools。如图:

这里简单介绍下:
NDK:是Android开发本地C/C++代码的一套工具集。
CMake:一套跨平台的构建工具,可以Gradle脚本配合使用来构建你的本地库。在AndroidStudio中,Google默认和推荐使用CMake进行编译,当然,你仍然可以继续使用ndk-build来编译你的本地代码。注意:32位的操作系统可能会装不上。
LLDB: 一种调试器,Android Studio中可以使用它来调试本地代码。

<h3 id="new-project">2、 创建一个支持C/C++的项目</h3>

这里所说的创建一个支持C/C++的项目,可以理解为创建一个NDK项目,但又包含两种方式,分别是从零开始新建一个支持C/C++开发的项目和在原有项目的基础上让它支持C/C++开发。下面对这两种方式分别进行说明下。

<h5 id="new-project1">2.1 新建项目</h5>

如果安装好了,上面介绍的几个工具(主要是NDK),并且AndroidStudio2.2以上的版本,新建项目的时候,会看到这个选项。如图:


创建项目时,勾选C++支持。


项目中所用的C++标准可以选择默认或者支持C++11,以及是否支持异常和rtti特性。


创建完项目,会比一般的Android项目多出cpp目录以及CMakeLists.txt的文件。


这里指定NDK的路径。即,上面环境搭建里安装的ndk,会下载到AndroidStudio根目录下的ndk-bundle文件夹中。


make一下当前新创建的工程,默认会在build/cmake/debug/obj/下生成相应的动态库。

<h5 id="new-project2">2.2 扩展现有项目</h5>

要让现有的Android项目能调用本地C/C++代码或者支持C/C++开发,只需要在原来项目的基础稍加修改即可。步骤如下:


切换到project视图,打开module即上图的app模块,在src/main下右键New->Directory,填写一个文件名,例如:cpp


在刚建的cpp路径下,右键New->C/C++ Source File,输入文件名,若要一并生成相应的.h文件,勾选Create an associated header选项即可。注意,后面可以指定源文件的后缀,例如:.cxx,.hxx


在module的根目录即上图的app根目录,右键New->File,输入CMakeLists.txt。注意:文件名必须为CMakeLists.txt


在module的根目录即上图的app根目录,选择Link C++ Project with Gradle,然后,找到刚创建的CMakeLists.txt文件。将CMakeLists.txt关联到项目中。注意,Build System仍可以选择ndk-build方式进行编译。

当然,这步操作也可以手动完成,相当于在当前module下的build.gradle脚本中,添加了如下代码,

android {
    //指定使用CMake编译----------------
    externalNativeBuild {
        cmake {
            path 'CMakeLists.txt'
        }
    }
    //--------------------------------
} 

打开新建的CMakeLists.txt文件,输入如下代码:

cmake_minimum_required (VERSION 3.4.1)

add_library (hellojni SHARED src/main/cpp/hellojni.cpp)

分别指定CMake要求的版本,add_library中参数分别是,指定生成库的名称,生成库的类型,默认是静态块,即:·a,源码的路径。这里实例只简单介绍下CMake的用法,后续会有专门一篇来介绍下CMake更多高级的用法。

以上完毕,在make一下当前工程,或者rebuild一下,不出意外会在build/intermediates/cmake/debug路径下生成各种libhellojni.so文件。

<h3 id="as-gradle">3、AndroidStudio与Gradle</h3>

上面提到,将CMakeLists.txt关联到项目中,会在build.gradle脚本中,添加一段代码即可。可能刚接触AndroidStudio(特别是使用其它IDE开发的,例如:eclipse等)对Gradle不是很了解,这里就抛砖引玉下,简要讲述下gradle脚本的使用。

首先,AndroidStudio是基于IntelliJ IDEA的IDE,在AndroidStudio中新创建的Android工程都形如如下结构:

MyApp  
├── build.gradle  
├── settings.gradle  
└── app  
    ├── build.gradle  
    ├── build  
    ├── libs  
    └── src  
        └── main  
            ├── java  
            │   └── com.package.myapp  
            └── res  
                ├── drawable  
                ├── layout  
                └── etc.  

MyApp是项目名,app是模块名,一个项目下可以包含若干个模块。这与eclipse的结构不同,对应到eclipse中,app就相当于项目名,MyApp相当于工作空间。或者类似于VS中解决方案与项目的关系。以上目录结构关系,并不与实际磁盘上的目录结构对应。可以看到,在项目根目录下以及模块目录下,分别有三个.gradle文件。下面,就分别介绍这三个gradle脚本的用途,当然这里主要说的是在AndroidStudio下的gradle的相关使用。

在AndroidStudio中android项目是基于gradle进行构建的(eclipse中可以使用ant来做类似的工作),而gradle是一种基于Groovy语言的DSL(domain-specific language,领域专用语言),而Groovy又是一种基于JVM的动态语言。所以,有java基础的话,理解Groovy会更容易。有关Gradle文档可以看看这个:
https://docs.gradle.org/current/dsl/

<h5 id="project-build">3.1 project/build.gradle</h5>

该build.gradle位于项目的根目录,该文件是定义在这个工程下的所有模块的公共属性。默认如下:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

以下只是从表象说明下,但实质是Groovy相应的数据结构(闭包,Map等)调用相应方法来动态控制整个构建过程。有关Groovy的讨论可以看看3.3 module/build.gradle
buildscript:定义了全局的相关属性。
repositories:定义了远程仓库的源,即代表你的依赖包的来源。这里将jcenter()作为仓库。
dependencies:定义了android gradle plugin的版本。
allprojects:可以用来定义各个模块的默认属性,你可以不仅仅局限于默认的配置,未来你可以自己创造tasks在allprojects方法体内,这些tasks将会在所有模块中可见。
task clean:执行相关的清理任务。

<h5 id="as-settings">3.2 project/settings.gradle</h5>

该文件位于项目根目录下,也是项目的全局配置文件,该文件的内容如下:

include ':app'

如果,你的项目中有多个模块时,可以依次添加到该文件中。例如:

include ':app',':librarys:Mylibrary'

即在项目根目录下的librarys目录里有个Mylibrary库工程。

<h5 id="as-module">3.3 module/build.gradle</h5>

该文件位于当前模块的根目录下,通常情况下,该文件只对当前模块起作用。例如:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        applicationId "com.alphagl.test"
        minSdkVersion 19
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    externalNativeBuild {
        cmake {
            path 'CMakeLists.txt'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:24.2.1'
}

以上内容,要彻底弄清楚,得深究下Groovy语法。这里,只浅析下。
apply plugin: 'com.android.application':在Groovy中的调用为project.apply([plugin: 'com.android.application']),plugin: 'com.android.application会被作为一个Map参数传递给apply的方法。这里是要将该模块构建为一个应用,若要将模块构建库形式,可以传参为plugin: 'com.android.library

在Groovy中花括号包含的部分称为一个闭包(Closure)。上面的主要两部分androiddependencies,分别对应project中的方法,而参数是相应的闭包结构。通过上面的结构,可以知道该闭包结构还有闭包嵌套和相应的方法。
android:该方法包含了所有的Android属性,而唯一必须包含属性为compileSdkVersion和buildToolsVersion。
compileSdkVersion:该方法包含编译该app时候,使用到的api版本。
buildToolsVersion:该方法包含构建工具的版本号。
defaultConfig:该方法包含app的核心属性,该属性会覆盖在AndroidManifest.xml中的对应属性。
applicationId:该方法定义的属性会覆盖AndroidManifest文件中的包名package name属性。
minSdkVersion:该方法定义的属性表示最小支持api版本。同AndroidManifest中对应的属性。
targetSdkVersion:该方法定义的属性表示目标平台api版本。同AndroidManifest中对应的属性。
buildTypes:该方法定义了构建不同版本的app相关的属性。
release:配置release版本相关的属性。
minifyEnabled:是否进行混淆。
proguardFiles:定义混淆文件的位置。通过getDefaultProguardFile方法获取。
externalNativeBuild:native使用cmake编译。
dependencies:gradle默认的属性之一,定义了所有的依赖包。
compile:编译相应依赖的jar包。组织名,包名,版本号的结构。

以上只简单的列举了下部分属性,对gradle脚本有初步的了解。当然,Groovy在java领域还是有很多应用的。感兴趣的,可以深入了解下。

Groovy文档:
Groovy-Documentation

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容