Android Studio的JNI開發(fā)快餐教程
從eclipse換到Android Studio之后,原來(lái)的NDK集成已經(jīng)不能用了矿咕。同時(shí)技羔,AndroidStudio也是在快速迭代進(jìn)步中喷好,不僅支持內(nèi)置的ndk支持插件,還有支持外部編譯系統(tǒng)的plugin. 而且這還是在實(shí)驗(yàn)中的結(jié)果缅刽,在不久的將來(lái)啊掏,還可能有更新的變化。不過(guò)衰猛,萬(wàn)變不離其宗迟蜜,我們打好基礎(chǔ),形式上的東西跟著Android Studio變就好啡省。
舊式的NDK支持
首先說(shuō)明娜睛,既然是Android Studio認(rèn)為它已經(jīng)過(guò)時(shí)了髓霞,所以我們需要在gradle.properties中聲明一下我們還堅(jiān)持用這個(gè)屬性:
android.useDeprecatedNdk=true
下面我們看下,在build.gradle中如何使用這種老式的辦法:
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.0"
defaultConfig {
applicationId "com.yunos.xulun.testcppjni"
minSdkVersion 21
targetSdkVersion 24
versionCode 1
versionName "1.0"
ndk{
moduleName "testcppjni"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
這其中使用的plugin畦戒,是"com.android.application".
我們現(xiàn)在可以開始寫一個(gè)類測(cè)試一下:
package com.yunos.xulun.testcppjni;
public class TestCppJni {
static{
System.loadLibrary("testcppjni");
}
public static native int callCpp();
}
編譯之后方库,使用javah工具生成頭文件com_yunos_xulun_testcppjni_TestCppJni.h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_yunos_xulun_testcppjni_TestCppJni */
#ifndef _Included_com_yunos_xulun_testcppjni_TestCppJni
#define _Included_com_yunos_xulun_testcppjni_TestCppJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_yunos_xulun_testcppjni_TestCppJni
* Method: callCpp
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_yunos_xulun_testcppjni_TestCppJni_callCpp
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
然后我們寫一個(gè)C++函數(shù)去實(shí)現(xiàn)它:
#include "com_yunos_xulun_testcppjni_TestCppJni.h"
JNIEXPORT jint JNICALL Java_com_yunos_xulun_testcppjni_TestCppJni_callCpp
(JNIEnv *env, jclass obj){
return (jint)0;
}
將頭文件和cpp文件放到app/src/main/jni下面。
在Android工程中寫個(gè)類去引用這個(gè)本地方法障斋,就不多說(shuō)了纵潦。編譯運(yùn)行,就生成了libtestcppjni.so垃环。
還可以額外多設(shè)幾個(gè)屬性邀层,比如編譯選項(xiàng),比如生成什么架構(gòu)的庫(kù)晴裹,引入什么庫(kù)等等:
android {
compileSdkVersion 24
buildToolsVersion "24.0.0"
defaultConfig {
applicationId "com.yunos.xulun.testcppjni"
minSdkVersion 21
targetSdkVersion 24
versionCode 1
versionName "1.0"
ndk{
moduleName "testcppjni"
cFlags "-std=c++11"
abiFilters "arm64-v8a","armeabi", "armeabi-v7a", "x86"
ldLibs "log"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
新的實(shí)驗(yàn)性的編譯系統(tǒng)的NDK支持
其實(shí)被济,新的實(shí)驗(yàn)性編譯系統(tǒng),對(duì)于java的編譯也是變了不少涧团。
下面,我們follow步驟去升級(jí)到新的編譯系統(tǒng):
升級(jí)gradle的版本
首先经磅,要確保gradle的版本在2.10以上泌绣,我們都過(guò)修改gradle/wrapper下的gradle-wrapper.properties中的distributionUrl來(lái)實(shí)現(xiàn)這一點(diǎn)。
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
升級(jí)plug-in
我們修改build.gradle预厌,從正式版改成實(shí)驗(yàn)版阿迈,在我寫這篇文件時(shí),最新版本是0.8.0-alpah5轧叽。我們保守點(diǎn)苗沧,選個(gè)不帶alpha的0.7.2:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
修改代碼
經(jīng)過(guò)上一步的修改,系統(tǒng)已經(jīng)提示炭晒,無(wú)法找到我們之前用的"com.android.application"的包名了,所以我們要針對(duì)新的'com.android.model.applicaiton’包進(jìn)行修改:
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion 24
buildToolsVersion "24.0.0"
defaultConfig {
applicationId "com.yunos.xulun.testcppjni"
minSdkVersion.apiLevel 21
targetSdkVersion.apiLevel 24
versionCode 1
versionName "1.0"
buildConfigFields{
create() {
type "int"
name "VALUE"
value "1"
}
}
ndk {
moduleName "testcppjni"
cppFlags.add("-std=c++11")
ldLibs.add("log")
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file('proguard-rules.pro'))
}
}
productFlavors{
create("Flavor"){
applicationId "com.yunos"
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.0.0'
}
針對(duì)ndk部分待逞,moduleName部分不用變。但是像cppFlags和ldLibs現(xiàn)在要通過(guò)add方法來(lái)進(jìn)行添加了网严。
我們還可以加上調(diào)試和stl的支持:
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion 24
buildToolsVersion "24.0.0"
defaultConfig {
applicationId "com.yunos.xulun.testcppjni"
minSdkVersion.apiLevel 21
targetSdkVersion.apiLevel 24
versionCode 1
versionName "1.0"
buildConfigFields{
create() {
type "int"
name "VALUE"
value "1"
}
}
ndk {
moduleName "testcppjni"
cppFlags.add("-std=c++11")
ldLibs.add("log")
stl "stlport_shared"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file('proguard-rules.pro'))
ndk{
debuggable true
}
}
}
productFlavors{
create("Flavor"){
applicationId "com.yunos"
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.0.0'
}
直接調(diào)用NDK或者CMake
上面這兩種方式還不算完识樱,生命不息,折騰不止震束,讓我們一起跟隨Android Studio繼續(xù)折騰怜庸。
從2.2版本開始,Android Studio開始在64位OS上支持
這次我們直接調(diào)用NDK去build垢村。
之前我們一直沒(méi)有寫Android.mk割疾,現(xiàn)在要用NDK了,就寫一個(gè)吧:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := testcppjni
LOCAL_SRC_FILES := test.cpp
LOCAL_CFLAGS += -std=c++11
LOCAL_ARM_MODE := thumb
include $(BUILD_SHARED_LIBRARY)
Application.mk也寫個(gè)吧:
APP_ABI := armeabi armeabi-v7a arm64-v8a
然后改build.gradle:
android {
compileSdkVersion 20
buildToolsVersion "24.0.0"
externalNativeBuild{
ndkBuild{
path "Android.mk"
}
}
defaultConfig {
applicationId "com.yunos.xulun.testcppjni"
minSdkVersion 19
targetSdkVersion 19
externalNativeBuild {
ndkBuild {
targets "testcppjni"
arguments "NDK_APPLICATION_MK:=Application.mk"
cppFlags "-std=c++11"
abiFilters "armeabi-v7a", "armeabi","arm64-v8a"
}
}
}
綜述
從目前的情況看嘉栓,可以繼續(xù)用過(guò)時(shí)的老方法宏榕,因?yàn)楹髢煞N都還沒(méi)有正式發(fā)布驰凛。
有興趣的可以跟進(jìn)新的編譯系統(tǒng),升級(jí)到2.2之后担扑,也可以考慮使用externalNativeBuild恰响。