美文网首页
Hello NDK!

Hello NDK!

作者: czins | 来源:发表于2017-05-07 02:06 被阅读21次

    NDK 开发变得越来越重要,接下来介绍一下 Android Studio 下 NDK 开发环境配置:
    功能需求:1.打开文件写入日志,2.读取日志的内容

    1.创建一个项目,在项目的创建一个 FileLogger.java,里面有下面两个函数:

    static {
            // 加载的动态库.so文件,注意这里不用加lib前缀,系统会默认添加
            System.loadLibrary("file_logger");
        }
    
        /**
         * 写入 Log 到文件
         * @param log_path     日志文件的路径
         * @param message     消息内容
         */
        public static native void writeLogFile(String log_path, String message);
    
    
        /**
         * 读取日志文件
         * @param log_path  日志文件的路径
         * @return 读取 Log 文件的内容
         */
        public static native String readLogFile(String log_path);
    
    1. 打开 Terminal 控制台,生成 JNI 的头文件:
    // 进入java的目录
    cd app/src/main/java
    // 利用javac创建头文件
    javah com.andon.colbert.ndkdemo.FileLogger
    

    3.创建 JNI 目录:

    app -> New -> Folder -> JNI Folder 
    

    在创建的 jni 目录下,创建 include 目录存放生成的JNI头文件

    Paste_Image.png

    (注意):切换到 Android 模式下看到的是 cpp 名称,而非 jni。

    Paste_Image.png

    4.在app根目录下创建 CMakeLists.txt

    add_library( # 模块的名称.
                file_logger
    
                # 设置模块为共享库.
                SHARED
    
                # 指定模块的源文件.
                src/main/jni/file_logger.cpp )
    
    # 指定源文件引用头文件的搜索目录
    include_directories(src/main/jni/include/)
    
    # 指定NDK变量引用NDK的模块,储存在NDK中
    find_library( 
                 # NDK 的变量名
                 log-lib
    
                 # 引用的NDK模块名称,这里引用了 android 的 log 库
                 log )
    
    # 链接模块到一个或多个其他链接库上
    target_link_libraries( # 链接的目标模块
                          file_logger
    
                          # 这里指定了将 android 的 log库 链接到 file_logger 上
                          ${log-lib} )
    
    1. 配置 gradle,将项目关联到 CMakeLists.txt 文件


      屏幕快照 2017-05-07 上午1.51.03.png
      屏幕快照 2017-05-07 上午1.53.37.png

      同步gradle后生成的目录结构:


      屏幕快照 2017-05-07 上午1.55.07.png
      生成的gradle,多了以下代码:
    屏幕快照 2017-05-07 上午1.56.29.png

    一般我们可能只会生成armeabi下的so库,所以我们可以再配置以下配置节:

    ndk {
        abiFilters 'armeabi', 'x86' // 这里配置 x86 可以供在模拟器下测试使用。
    }
    ```
    
    6.在cpp目录下创建c++文件,编写 file_logger.cpp 文件:
    ```
    #include <jni.h>
    #include "com_andon_colbert_ndkdemo_FileLogger.h"
    #include <stdio.h>
    #include <string.h>
    #include <android/log.h>
    #include <errno.h>
    
    #define LOG_I(...) __android_log_print(ANDROID_LOG_INFO, "file_logger", __VA_ARGS__)
    #define LOG_E(...) __android_log_print(ANDROID_LOG_ERROR, "file_logger", __VA_ARGS__)
    
    JNIEXPORT void JNICALL Java_com_andon_colbert_ndkdemo_FileLogger_writeLogFile
            (JNIEnv *env, jclass type, jstring log_path, jstring message) {
        const char *path = env->GetStringUTFChars(log_path, 0);
        FILE *log_file = fopen(path, "w+");
        env->ReleaseStringUTFChars(log_path, path);
        if (log_file == NULL) {
            LOG_E("日志文件打开失败!errno: %d", errno);
            return;
        }
        const char *content = env->GetStringUTFChars(message, 0);
        const size_t count = env->GetStringUTFLength(message);
        env->ReleaseStringUTFChars(message, content);
        // 写入文件
        size_t w_count = fwrite(content, sizeof(char), count, log_file);
        if (w_count == count) {
            LOG_I("日志写入成功!");
        }
        // 关闭文件
        fclose(log_file);
    }
    
    JNIEXPORT jstring JNICALL Java_com_andon_colbert_ndkdemo_FileLogger_readLogFile
            (JNIEnv *env, jclass type, jstring log_path) {
        const char *path = env->GetStringUTFChars(log_path, 0);
        FILE *log_file = fopen(path, "r");
        env->ReleaseStringUTFChars(log_path, path);
        if (log_file == NULL) {
            LOG_E("日志文件打开失败!errno: %d", errno);
            return NULL;
        }
        // 将文件指针指向文件的末尾
        fseek(log_file , 0 , SEEK_END);
        // 获取当前指针的位置,就是文件的大小
        size_t file_size = ftell(log_file);
        if(file_size == 0L) {
            LOG_E("日志文件为空!");
            fclose(log_file);
            return NULL;
        }
        // 分配内存空间
        char* content = (char*) malloc(file_size);
        if(content == NULL) {
            LOG_E("内存空间不足!");
            fclose(log_file);
            return NULL;
        }
        // 将文件指针指向文件的头部
        fseek(log_file, 0, SEEK_SET);
       // 读取文件的全部内容
        fread(content, sizeof(char), file_size, log_file);
        content[file_size] = '\0'; // 追加字符串结束符。
        fclose(log_file);
        jstring message = env->NewStringUTF(content);
        free(content);
        return message;
    }
    ```
    
    7.在androidTest中编写测试文件:
    ```
    @Test
    public void testFileLogger() {
        String message = "Hello NDK!";
        File dir = new File(Environment.getExternalStorageDirectory(), "demo");
        if (!dir.exists()) {
             dir.mkdirs();
        }
        String path = dir.getAbsolutePath() + "/log.txt";
        FileLogger.writeLogFile(path, message);
        String content = FileLogger.readLogFile(path);
        assertEquals(message, content);
    }
    ```
    至此,Hello NDK! 就写完了,别忘了加文件读写权限哦,编译测试时,为了方便我把 targetSdkVersion 设置成了22,否则会打开文件失败。

    相关文章

      网友评论

          本文标题:Hello NDK!

          本文链接:https://www.haomeiwen.com/subject/hzzytxtx.html