本博客是基於Android Studio 1.3 preview版本,且默認你已經安裝了Android SDK, Android NDK。html
用Android Studio新建一個工程叫Prompt,其目錄結構以下:java
├── Prompt.imlandroid
├── appapi
│ ├── app.iml數組
│ ├── buildapp
│ ├── build.gradleide
│ ├── libs函數
│ ├── proguard-rules.progradle
│ └── srcui
├── build
│ └── intermediates
├── build.gradle
├── gradle
│ └── wrapper
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle
切換到android視圖,可見以下目錄:
第一步,編寫JNI代碼:
一、新建jni文件夾,在jni文件夾下建立logger.h,用來打印輸出日誌的,其內容以下:
#ifndef PROMPT_LOGGER_H_H #define PROMPT_LOGGER_H_H #include <jni.h> #include <android/log.h> /** * 定義log標籤 */ #define TAG "jni_logger" /** * 定義info信息 */ #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) /** * 定義debug信息 */ #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) /** * 定義error信息 */ #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) #endif //PROMPT_LOGGER_H_H
二、接着建立prompt_jni.c主要用來註冊綁定java函數和native函數,以及java函數在c中相應函數的具體實現, 內容以下:
#include "logger.h" #ifndef NULL #define NULL ((void *) 0) #endif /** * 獲取數組的大小 */ #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) #define JNIREG_CLASS "com/ndk/clarck/prompt/MainActivity" /** * 返回字符串 */ JNIEXPORT jstring JNICALL native_getLine(JNIEnv *env, jobject obj, jstring prompt) { char outbuf[128]; int len = (*env)->GetStringLength(env, prompt); (*env)->GetStringUTFRegion(env, prompt, 0, len, outbuf); return (*env)->NewStringUTF(env, outbuf); } /** * Java和JNI函數綁定 */ static JNINativeMethod method_table[] = { {"getLine", "(Ljava/lang/String;)Ljava/lang/String;", (void*)native_getLine}, }; /** * 註冊native方法到java中 */ static int registerNativeMethods(JNIEnv *env, const char* className, JNINativeMethod* gMethods, int numMethods) { jclass clazz; clazz = (*env)->FindClass(env, className); if (clazz == NULL) { return JNI_FALSE; } if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) { return JNI_FALSE; } return JNI_TRUE; } /** * 調用註冊方法 */ int register_ndk_load(JNIEnv *env) { return registerNativeMethods(env, JNIREG_CLASS, method_table, NELEM(method_table)); } JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK) { return result; } register_ndk_load(env); return JNI_VERSION_1_4; }
三、java層調用以下:
package com.ndk.clarck.prompt; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String getLine = getLine("Type a line:"); Log.d("Test", "getLine: " + getLine); } public native String getLine(String prompt); static { System.loadLibrary("prompt_jni"); } }
第二步,配置以下環境,執行編譯命令:
一、在local.properties配置SDK和NDK路徑以下:
sdk.dir=xxxx
ndk.dir=xxx
二、打開gradle-wrapper.properties,將其配置修改成使用Gradle 2.5來編譯(詳情參考:http://www.cnblogs.com/tanlon/p/4731283.html):
#Mon Aug 17 20:34:50 HKT 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
三、配置Project下面的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-experimental:0.2.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() } }
四、配置Module下面的build.gradle,其內容以下:
apply plugin: 'com.android.model.application' model { android { compileSdkVersion = 21 buildToolsVersion = "22.0.1" defaultConfig.with { applicationId = "com.ndk.clarck.prompt" minSdkVersion.apiLevel = 15 targetSdkVersion.apiLevel = 21 } } android.ndk { moduleName = "prompt_jni" ldLibs += ["log"] } android.buildTypes { release { minifyEnabled = false proguardFiles += file('proguard-rules.pro') } } android.productFlavors { create ("arm7") { ndk.abiFilters += "armeabi-v7a" } create ("arm8") { ndk.abiFilters += "arm64-v8a" } create ("x86-32") { ndk.abiFilters += "x86" } // for detailed abiFilter descriptions, refer to "Supported ABIs" @ // https://developer.android.com/ndk/guides/abis.html#sa // build one including all cpu architectures create("all") } }
五、執行Build->Make Project,獲得以下輸出:
1:27:09 PM Executing tasks: [:app:compileAllDebugSources, :app:compileAllDebugAndroidTestSources]
1:27:10 PM Gradle build finished in 779ms
六、執行Run,便可運行項目了。
經驗:
一、遇到Gradle sync failed: Cause: org.gradle.api.internal.ExtensibleDynamicObject這種錯誤的解決辦法:
將Module下的build.gradle全部編譯參數賦值都是採用xxx = xxx這種方式,而不能採用 xxx xxx這種賦值的方式
二、Android Studio Gradle編譯確實比Eclipse中採用Android Makefile要方便不少。