代码改变世界

Android Studio NDK 学习之接受Java传入的Int数组

2015-08-25 16:59  雪夜&流星  阅读(2271)  评论(0编辑  收藏  举报

本博客是基于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