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要方便很多。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告