使用Android Studio 进行NDK开发和调试

尽管Android Studio已经越来越流行了,但很多人还是习惯于Eclipse或源码环境下开发JNI应用。个人认为使用Android Studio作NDK开发是必然趋势,所以本文将简单介绍如何在Android Studio上实现NDK开发。

简介

JNI

JNI 是Java Native Inteface的缩写,是Java中定义的一种用于连接Java和C/C++接口的一种实现方式。

NDK

NDK 是 Native Developmentit的缩写,是Google在Android开发中提供的一套用于快速创建native工程的一个工具。
使用这个工具可以很方便的编写和调试JNI的代码。

NDK可从官网AndroidDevTools(个人网站)下载。

Gradle

Gradle 是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置。

以往Android NDK开发需要在Eclipse或源码环境下,建立并配置Android.mk和Application.mk,且还要通过java命令生成.h头文件,才能编译生成so库。但在Android Studio中这些步骤都不需要,因为Gradle足够强大,只需配置Gradle即可编译生成so库。

gradle-experimental插件

在2015年5月的Google I/O大会上, Google宣布Android Studio开始支持NDK开发,通过和JetBrains的合作,将Clion整合进了Android Studio 1.3,并免费支持NDK C++开发。

同年7月,在Android Studio 1.3版本上添加了gradle-experimental插件,该插件支持NDK开发和调试,且带有代码不全和重构等高级功能。

CAVEAT: Note that this plugin is a preview of the plugin for feedback on performance and NDK integration. The Gradle API for the new component model is not final, which means each plugin will only work with a specific version of Gradle.
Additionally, the DSL may also change.

目前这个插件是预览插件,并不是正式的。意味着插件只能运行在特定的Gradle版本上。并且DSL(领域特定语言)也要改变。

使用Experimental插件进行NDK开发

使用Experimental插件的必要条件

1、Gradle-2.5或更高版本
2、Android Studio 1.3 RC1或更高版本
3、Android NDK r10e 或更高版本
4、Build Tools 19.0.0 或更高版本

每个版本的experimental插件需要特定的Gradle版本

Plugin Version Gradle Version
0.1.0 2.5
0.2.0 2.5
0.3.0-alpha3 2.6
0.4.0 2.8
0.6.0-alpha1 2.8
0.6.0-alpha5 2.10
0.7.0-alpha1 2.10

NDK开发步骤

1、新建一个Android标准工程

2、按F4打开工程配置

3、使用experimental插件需要对以下三个文件做修改:

./build.gradle
./app/build.gradle
./gradle/wrapper/gradle-wrapper.properties
./gradle/wrapper/gradle-wrapper.properties

将distributionUrl改用gradle-2.10版本


    distributionUrl=https\\://services.gradle.org/distributions/gradle-2.10-all.zip
./build.gradle

使用com.android.tools.build:gradle-experimental代替 com.android.tools.build:gradle


    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            //classpath 'com.android.tools.build:gradle:2.0.0'
            classpath "com.android.tools.build:gradle-experimental:0.7.0-alpha4"

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

这部分改动比较大,修改及注释如下:


    // 用com.android.model.application 代替 com.android.application
    apply plugin: 'com.android.model.application'

    // 将原来的配置用 model{}包起来
    model {
        android {
            // 取值必须使用 “=” 形式
            // 否则会报 “Error:Cause: org.gradle.api.internal.ExtensibleDynamicObject” 错误
            compileSdkVersion = 23
            buildToolsVersion = '23.0.2'

            defaultConfig {
                // 取值必须使用 “=” 形式
                applicationId = "com.connorlin.jnitest"
                //这里要注意是 xxSdkVersion.apiLevel
                // 否则会报 “Unable to load class com.android.build.gradle.managed.ProductFlavor_Impl”错误
                minSdkVersion.apiLevel = 15 
                targetSdkVersion.apiLevel = 23
                versionCode =  1
                versionName = "1.0"
            }

            // 配置NDK
            ndk {
                // 生成so的名字,是必须的
                moduleName ="JNITest"
                toolchain = 'clang'
                CFlags.add('-std=c99')
                // 添加依赖库
                ldLibs.addAll(['android','OpenSLES', 'log'])
                // 生成不同abi体系的so库
                abiFilters.addAll(['armeabi', 'armeabi-v7a', 'arm64-v8a',
                                   'x86', 'x86_64',
                                   'mips', 'mips64'])
            }

            buildTypes {
                release {
                    minifyEnabled = false
                    // 这里注意:使用proguardFiles.add()方法
                    proguardFiles.add(file('proguard-rules.txt'))
                }
            }
        }
    }

4、在Java文件(这里以JNIActivity为例)中添加代码


    static {
        System.loadLibrary("JNITest");
    }

    public native String testJni();

此时,native方法标红,提示如下:

testJni()方法上按快捷键Alt + Enter,出现如下提示

按回车,会自动在main目录下生成jni文件夹,内含JniDemo.c:


    #include <jni.h>

    JNIEXPORT jstring JNICALL
    Java_com_connorlin_jnitest_MainActivity_testJni(JNIEnv *env, jobject instance) {
        // TODO
        return (*env)->NewStringUTF(env, "returnValue");
    }

你会发现,Android Studio已经为我们自动生成JNI方法了,你只需要再写实现就可以了。

至此,最简单的NDK开发配置完毕。

其他配置,请参考官方文档,Demo可以参考官方Demo

换种方式进行NDK开发

既然预览版com.android.tools.build:gradle-experimental支持NDK,
那么正式版com.android.tools.build:gradle 是否也可以实现NDK开发呢?

经过实验,答案是可以的!

步骤

1、新建一个Android标准工程,并在工程设置中配置NDK路径。

2、打开 app level 的 build.gradle, 配置NDK


    ndk {
        moduleName "NdkJniDemo"          //生成的so名字
        abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库,可忽略
    }

然后点击右上角Sync Now, 会有如下错误提示:

按提示,在 gradl.properties 文件里加上android.useDeprecatedNdk=true即可。

3、在Java文件(这里以JNIActivity为例)中添加代码


    static {
        System.loadLibrary("JNITest");
    }

    public native String testJni();

接着在testJni()方法上按快捷键Alt + Enter并回车,

同样,会自动在main目录下生成jni文件夹,内含JniDemo.c:


    #include <jni.h>

但是,你会发现并不会自动生成JNI方法,这是因为使用experimental插件才会自动生成代码。

那自动生成代码该如何实现呢?

方法依然是使用gradle-experimental插件,但是不同的是,在app level的build.gradle中添加com.android.tools.build:gradle-experimental依赖。

4、在./app/build.gradle中添加gradle-experimental依赖


    dependencies {
        compile 'com.android.tools.build:gradle-experimental:0.7.0'
    }

再次在testJni()方法上按快捷键Alt + Enter并回车


    #include <jni.h>

    JNIEXPORT jstring JNICALL
    Java_com_connorlin_jnitest_MainActivity_testJni(JNIEnv *env, jobject instance) {
        // TODO
        return (*env)->NewStringUTF(env, "returnValue");
    }

你会发现成功自动生成JNI方法了。

副作用

这种方式有个副作用是 Run app 时可能会报错:

此时,只要将gradle-experimental依赖注释掉即可正常运行,同时会保持自动生成代码的功能,直到关闭工程。
这样我们在需要自动生成代码的时候,将gradle-experimental依赖再次打开即可。

NDK调试

默认情况下是不支持NDK调试的,但要支持NDK调试也很简单,只要做些简单配置即可。

1、打开JNI调试

2、配置Android Native - Debugger

3、下载LLDB 2.0

首次底部会报错

点击 Fix,提示下载LLDB 2.0,照做,下载安装即可。

4、完成NDK调试配置,可以正常调试了。

That's all!

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

推荐阅读更多精彩内容