• Android Studio NDK 学习之接受Java传入的字符串


    本博客是基于Android Studio 1.3 preview版本,且默认你已经安装了Android SDK, Android NDK。

    用Android Studio新建一个工程叫Prompt,其目录结构如下:

    ├── Prompt.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 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

    2、接着创建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;
    }

    3、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");
        }
    }

    第二步,配置如下环境,执行编译命令:

    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 = 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")
        }
    }

    5、执行Build->Make Project,得到如下输出:

    1:27:09 PM Executing tasks: [:app:compileAllDebugSources, :app:compileAllDebugAndroidTestSources]
    1:27:10 PM Gradle build finished in 779ms

    6、执行Run,即可运行项目了。

    经验:

    1、遇到Gradle sync failed: Cause: org.gradle.api.internal.ExtensibleDynamicObject这种错误的解决办法:

      将Module下的build.gradle所有编译参数赋值都是采用xxx = xxx这种方式,而不能采用 xxx xxx这种赋值的方式

    2、Android Studio Gradle编译确实比Eclipse中采用Android Makefile要方便很多。

  • 相关阅读:
    java unicode转中文
    java常用
    Intellij IDEA常用快捷键——Mac版
    mac 快捷键
    thrift 学习
    ubuntu上的翻译软件,看论文神器
    linux中jupyter notebook中切换虚拟环境
    02_opencv_python_图像处理进阶
    01_opencv_python_基本图像处理
    python刷剑指offer(21-40)(一刷)
  • 原文地址:https://www.cnblogs.com/tanlon/p/4739171.html
Copyright © 2020-2023  润新知