本博客是基于Android Studio 1.3 preview版本,且默认你已经安装了Android SDK, Android NDK。
用Android Studio新建一个工程叫AndroidJNI_IntArray,其目录结构如下:
├── AndroidJNI_IntArray.iml
├── app
│ ├── app.iml
│ ├── build
│ ├── build.gradle
│ ├── libs
│ ├── proguard-rules.pro
│ └── src
├── build
│ └── intermediates
├── build.gradle
├── gradle
│ └── wrapper
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle
切换到android视图,可见如下目录:
第一步,编写JNI代码:
1、新建jni文件夹,在jni文件夹下创建logger.h,用来打印输出日志的,其内容如下:
#ifndef ANDROIDJNI_INTARRAY_LOGGER_H #define ANDROIDJNI_INTARRAY_LOGGER_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 //ANDROIDJNI_INTARRAY_LOGGER_H
2、接着创建intarray_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]))) /** * 指定要注册的类,对应完整的java类名 */ #define JNIREG_CLASS "com/ndk/clarck/MainActivity" /** * 返回数组中元素的和 */ JNIEXPORT jint JNICALL native_sumArray(JNIEnv *env, jobject obj, jintArray arr) { jint *carr; jint i, sum = 0; carr = (*env)->GetIntArrayElements(env, arr, NULL); if (carr == NULL) { return 0; } for (i = 0; i < 10; i++) { sum += carr[i]; } (*env)->ReleaseIntArrayElements(env, arr, carr, 0); return sum; } /** * Java和JNI函数绑定 */ static JNINativeMethod method_table[] = { {"sumArray", "([I)I", (void *)native_sumArray}, }; /** * 注册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; }
3、java层调用如下:
package com.ndk.clarck; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); int arr[] = new int[10]; for (int i = 0; i < 10; i++) { arr[i] = i; } int sum = sumArray(arr); Log.d("Test", "sum: " + sum); } public native int sumArray(int[] arr); static { System.loadLibrary("intarray_jni"); } }
第二步,配置如下环境,执行编译命令:
1、在local.properties配置SDK和NDK路径如下:
sdk.dir=xxxx
ndk.dir=xxx
2、打开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
3、配置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() } }
4、配置Module下面的build.gradle,其内容如下:
apply plugin: 'com.android.model.application' model { android { compileSdkVersion = 22 buildToolsVersion = "22.0.1" defaultConfig.with { applicationId = "com.ndk.clarck" minSdkVersion.apiLevel = 15 targetSdkVersion.apiLevel = 21 } } android.ndk { moduleName = "intarray_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") } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.2.0' }
5、执行Build->Make Project,得到如下输出:
Information:Gradle tasks [:app:assembleAllDebug] :app:copyArm64-v8aDebugAllIntarray_jniSharedLibraryGdbServer UP-TO-DATE :app:createArm64-v8aDebugAllIntarray_jniSharedLibraryGdbsetup :app:compileArm64-v8aDebugAllIntarray_jniSharedLibraryIntarray_jniMainC UP-TO-DATE :app:linkArm64-v8aDebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:stripSymbolsArm64-v8aDebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:arm64-v8aDebugAllIntarray_jniSharedLibrary :app:copyArmeabi-v7aDebugAllIntarray_jniSharedLibraryGdbServer UP-TO-DATE :app:createArmeabi-v7aDebugAllIntarray_jniSharedLibraryGdbsetup :app:compileArmeabi-v7aDebugAllIntarray_jniSharedLibraryIntarray_jniMainC UP-TO-DATE :app:linkArmeabi-v7aDebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:stripSymbolsArmeabi-v7aDebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:armeabi-v7aDebugAllIntarray_jniSharedLibrary :app:copyArmeabiDebugAllIntarray_jniSharedLibraryGdbServer UP-TO-DATE :app:createArmeabiDebugAllIntarray_jniSharedLibraryGdbsetup :app:compileArmeabiDebugAllIntarray_jniSharedLibraryIntarray_jniMainC UP-TO-DATE :app:linkArmeabiDebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:stripSymbolsArmeabiDebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:armeabiDebugAllIntarray_jniSharedLibrary :app:preBuild UP-TO-DATE :app:preAllDebugBuild UP-TO-DATE :app:checkAllDebugManifest :app:preAllReleaseBuild UP-TO-DATE :app:preArm7DebugBuild UP-TO-DATE :app:preArm7ReleaseBuild UP-TO-DATE :app:preArm8DebugBuild UP-TO-DATE :app:preArm8ReleaseBuild UP-TO-DATE :app:preX86-32DebugBuild UP-TO-DATE :app:preX86-32ReleaseBuild UP-TO-DATE :app:prepareComAndroidSupportAppcompatV72220Library UP-TO-DATE :app:prepareComAndroidSupportSupportV42220Library UP-TO-DATE :app:prepareAllDebugDependencies :app:compileAllDebugAidl UP-TO-DATE :app:compileAllDebugRenderscript UP-TO-DATE :app:generateAllDebugBuildConfig UP-TO-DATE :app:generateAllDebugAssets UP-TO-DATE :app:mergeAllDebugAssets UP-TO-DATE :app:generateAllDebugResValues UP-TO-DATE :app:generateAllDebugResources UP-TO-DATE :app:mergeAllDebugResources UP-TO-DATE :app:processAllDebugManifest UP-TO-DATE :app:processAllDebugResources UP-TO-DATE :app:generateAllDebugSources UP-TO-DATE :app:processAllDebugJavaRes UP-TO-DATE :app:compileAllDebugJavaWithJavac :app:copyMips64DebugAllIntarray_jniSharedLibraryGdbServer UP-TO-DATE :app:createMips64DebugAllIntarray_jniSharedLibraryGdbsetup :app:compileMips64DebugAllIntarray_jniSharedLibraryIntarray_jniMainC UP-TO-DATE :app:linkMips64DebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:stripSymbolsMips64DebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:mips64DebugAllIntarray_jniSharedLibrary :app:copyMipsDebugAllIntarray_jniSharedLibraryGdbServer UP-TO-DATE :app:createMipsDebugAllIntarray_jniSharedLibraryGdbsetup :app:compileMipsDebugAllIntarray_jniSharedLibraryIntarray_jniMainC UP-TO-DATE :app:linkMipsDebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:stripSymbolsMipsDebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:mipsDebugAllIntarray_jniSharedLibrary :app:copyX86DebugAllIntarray_jniSharedLibraryGdbServer UP-TO-DATE :app:createX86DebugAllIntarray_jniSharedLibraryGdbsetup :app:compileX86DebugAllIntarray_jniSharedLibraryIntarray_jniMainC UP-TO-DATE :app:linkX86DebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:stripSymbolsX86DebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:x86DebugAllIntarray_jniSharedLibrary :app:copyX86_64DebugAllIntarray_jniSharedLibraryGdbServer UP-TO-DATE :app:createX86_64DebugAllIntarray_jniSharedLibraryGdbsetup :app:compileX86_64DebugAllIntarray_jniSharedLibraryIntarray_jniMainC UP-TO-DATE :app:linkX86_64DebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:stripSymbolsX86_64DebugAllIntarray_jniSharedLibrary UP-TO-DATE :app:x86_64DebugAllIntarray_jniSharedLibrary :app:compileAllDebugSources :app:preDexAllDebug UP-TO-DATE :app:dexAllDebug :app:validateDebugSigning :app:packageAllDebug :app:zipalignAllDebug :app:assembleAllDebug Information:BUILD SUCCESSFUL Information:Total time: 2.772 secs Information:0 errors Information:0 warnings Information:See complete output in console
6、执行Run,即可运行项目了。
经验:
Error:Cause: com.android.build.gradle.managed.AndroidConfig Impl 原因:
defaultConfig 必须写成 defaultConfig.with