代码改变世界

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

  雪夜&流星  阅读(313)  评论(0编辑  收藏  举报

本博客主要是在Ubuntu 下开发,且默认你已经安装了Eclipse,Android SDK, Android NDK, CDT插件。

在Eclipse中添加配置NDK,路径如下Eclipse->Window->Preferences->Android->NDK ,选择NDK的路径,然后Apply即可。

新建一个名为AndroidJNI_Prompt的Android工程,新建一个jni的文件夹,其目录下文件树列表如下:

├── jni
│   ├── Android.mk
│   ├── Application.mk
│   └── prompt
│      ├── Android.mk
│      ├── logger.h
│      └── prompt_jni.c

 

jni/Application.mk文件内容如下:

APP_ABI := all

APP_ABI具体参考如下:

By default, the NDK build system will generate machine code for the 'armeabi' ABI. This corresponds to an ARMv5TE based CPU with software floating point operations. You can use APP_ABIto select a different ABI.

For example, to support hardware FPU instructions on ARMv7 based devices, use:

          APP_ABI := armeabi-v7a

Or to support the IA-32 instruction set, use:

          APP_ABI := x86

Or to support the MIPS instruction set, use:

          APP_ABI := mips

Or to support all at the same time, use:

          APP_ABI := armeabi armeabi-v7a x86 mips

Or even better, since NDK r7, you can also use the special value 'all' which means "all ABIs supported by this NDK release":

          APP_ABI := all

For the list of all supported ABIs and details about their usage and limitations, please read CPU-ARCH-ABIS.

 

jni/Android.mk,主要用来指定顺序执行所有子文件夹下面的makefile文件,内容如下:

include $(call all-subdir-makefiles)

 

jni/prompt/Android.mk,主要用来指定需要编译出的动态库的名称,以及需要编译的源文件,内容如下:

复制代码
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE     := prompt_jni
LOCAL_SRC_FILES := prompt_jni.c

LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)
复制代码

 

 

jni/prompt/logger.h 主要用来在JNI层打印日志,内容如下:

复制代码
#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__)
复制代码

 

jni/prompt/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])))

/**
 * 指定要注册的类,对应的完整的java类名
 */
#define JNIREG_CLASS "com/clarck/jni/MainActivity"


/**
 * 返回字符串"Hello World!"
 */
JNIEXPORT jstring JNICALL native_getLine(JNIEnv *env, jobject obj, jstring prompt) {
    /*const jbyte *str;
   /* 取得 Java 字符串的 C 版本 */
    str = (*env)->GetStringUTFChars(env, prompt, NULL);
    if (NULL == str) {
        return NULL;
    }

    LOGI("%s", str);
   /* 至此完成对 str 的处理 */ (*env)->ReleaseStringUTFChars(env, prompt, str);
*/ 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); //返回jni的版本 return JNI_VERSION_1_4; }
复制代码

 

接着在Project中右键Android Tools->Add Native Support,最后java层调用如下:

复制代码
package com.clarck.jni;

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");
    }
}
复制代码

 

接着执行Ctrl+B编译即可。

 

编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示