内容简介: 这个在写JNI的时候就很常见了,比如json库,C++自己是没有提供json库的,然后我们在写JNI的时候,通常需要和上层交互数据,较简单的就是json了,那么就拿json来做讲解吧。首先来找一个json库啦!OK,集成成功,但是太复杂,太麻烦了,每次要写那么一堆配置文件,少一个都不行,还要挨个的去改 include 想想都可怕,那么可不可以把这个jsoncpp打成库呢?那么我们就要考虑如下:
这个在写JNI的时候就很常见了,比如json库,C++自己是没有提供json库的,然后我们在写JNI的时候,通常需要和上层交互数据,较简单的就是json了,那么就拿json来做讲解吧。首先来找一个json库啦!
jsoncpp 本篇就用这个json库来做讲解吧,首先把代码clone下来。
源码集成进项目中
-
将include里的json文件夹拷贝到../app/src/main/cpp目录下;
-
将src/lib_json里面的文件除去 CMakeLists.txt拷贝到../app/src/main/cpp目录下;
-
最终如下:
-
修改../app/src/main/cpp/CMakeLists.txt如下:
cmake_minimum_required(VERSION 3.4.1) add_library( native_hello SHARED json_tool.h json_reader.cpp json_valueiterator.inl json_value.cpp json_writer.cpp version.h.in # 下面的cpp若是没有则新建一个,本文基于上篇文章 native_hello.cpp ) target_link_libraries( native_hello android log ) 复制代码
-
make build一下
What Are you!!!出错了,告诉在json_tool.h的第10行出错了,那行吧,点进去瞅一眼,如下:
哦,include错了,应该改为 #include “json/config.h” 那就改吧!cv过来的所有文件都得去查看一下(试想一下,若是cv过来的文件有1W个,咋办…,改完这个,将来别的地方在引用,又忘了那个曾经是改过的了,停!stop,我眼疼!)。
编写测试代码
-
打开../app/src/main/cpp/native_hello.cpp 更改如下:
// // Created by xong on 2018/9/28. // #include<jni.h> #include "json/json.h" #define XONGFUNC(name)Java_com_xong_andcmake_jni_##name extern "C" JNIEXPORT jstring JNICALL XONGFUNC(NativeFun_outputJsonCode)(JNIEnv *env, jclass thiz, jstring jname, jstring jage, jstring jsex, jstring jtype) { Json::Value root; const char *name = env->GetStringUTFChars(jname, NULL); const char *age = env->GetStringUTFChars(jage, NULL); const char *sex = env->GetStringUTFChars(jsex, NULL); const char *type = env->GetStringUTFChars(jtype, NULL); root["name"] = name; root["age"] = age; root["sex"] = sex; root["type"] = type; env->ReleaseStringUTFChars(jname, name); env->ReleaseStringUTFChars(jage, age); env->ReleaseStringUTFChars(jsex, sex); env->ReleaseStringUTFChars(jtype, type); return env->NewStringUTF(root.toStyledString().c_str()); } extern "C" JNIEXPORT jstring JNICALL XONGFUNC(NativeFun_parseJsonCode)(JNIEnv *env, jclass thiz, jstring jjson) { const char *json_str = env->GetStringUTFChars(jjson, NULL); std::string out_str; Json::CharReaderBuilder b; Json::CharReader *reader(b.newCharReader()); Json::Value root; JSONCPP_STRING errs; bool ok = reader->parse(json_str, json_str + std::strlen(json_str), &root, &errs); if (ok && errs.size() == 0) { std::string name = root["name"].asString(); std::string age = root["age"].asString(); std::string sex = root["sex"].asString(); std::string type = root["type"].asString(); out_str = "name: " + name + "\nage: " + age + "\nsex:" + sex + "\ntype: " + type + "\n"; } env->ReleaseStringUTFChars(jjson, json_str); return env->NewStringUTF(out_str.c_str()); } 复制代码
-
修改NativeFun类如下:
package com.xong.andcmake.jni; /** * Create by xong on 2018/9/28 */ public class NativeFun { static { System.loadLibrary("native_hello"); } public static native String outputJsonCode(String name, String age, String sex, String type); public static native String parseJsonCode(String json_str); } 复制代码
-
测试:
package com.xong.andcmake; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; import com.xong.andcmake.jni.NativeFun; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv_native_content = findViewById(R.id.tv_native_content); String outPutJson = NativeFun.outputJsonCode("xong", "21", "man", "code"); String parseJson = NativeFun.parseJsonCode(outPutJson); tv_native_content.setText("生成的Json:\n" + outPutJson + "\n解析:" + parseJson); } } 复制代码
结果如下图:
编译成库文件
OK,集成成功,但是太复杂,太麻烦了,每次要写那么一堆配置文件,少一个都不行,还要挨个的去改 include 想想都可怕,那么可不可以把这个jsoncpp打成库呢?那么我们就要考虑如下:
- 必须使用CMake,不使用编写mk的方式;
- 在任何系统上都可以,不可在编译库的时候切换到其他系统;
好吧,基于以上两点,百度搜了一波,发现…GG,没有符合的哎,用CMake就得去 Linux 下面,且需要自己构建 工具 链,要不然就是…mk…。再去Google搜一搜,发现还是这样的,难道,不存在?再去GitHub搜,发现没有相关的,无可奈何,去Google提供的sample中找一找吧,哈!还真有发现,链接: hello-libs
编译so动态库
-
修改cpp目录为:
-
修改../cpp/jsoncpp/目录中的CMakeLists.txt如下:
cmake_minimum_required(VERSION 3.4.1) set(CMAKE_VERBOSE_MAKEFILE on) add_library( # 库名字 jsoncpp # 库类型 SHARED # 库包含的资源 src/json_tool.h src/json_reader.cpp src/json_valueiterator.inl src/json_value.cpp src/json_writer.cpp src/version.h.in) # 导出目录 此处的设置 导出主目录在 Project/export文件夹内。 set(export_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../export) set_target_properties( # 库名字 jsoncpp # 设置输出.so动态库的路径 PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${export_dir}/libsojsoncpp/lib/${ANDROID_ABI}") add_custom_command( # POST_BUILD 处 有三个值可选 # 分别是: # PRE_BUILD:在 hello 运行其他规则前执行 # PRE_LINK:在编译源文件之后但在 链接其他二进制文件 或 运行静态库的库管理器 或 归档工具 之前执行 # POST_BUILD:最后执行 TARGET jsoncpp POST_BUILD # 拷贝命令 将 ${CMAKE_CURRENT_SOURCE_DIR}/src/json/allocator.h 文件拷贝到 ${export_dir}/libsojsoncpp/include/json/ 文件夹内 且名字和之前的相同 COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/allocator.h" "${export_dir}/libsojsoncpp/include/json/allocator.h" COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/config.h" "${export_dir}/libsojsoncpp/include/json/config.h" COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/forwards.h" "${export_dir}/libsojsoncpp/include/json/forwards.h" COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/features.h" "${export_dir}/libsojsoncpp/include/json/features.h" COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/value.h" "${export_dir}/libsojsoncpp/include/json/value.h" COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/reader.h" "${export_dir}/libsojsoncpp/include/json/reader.h" COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/writer.h" "${export_dir}/libsojsoncpp/include/json/writer.h" COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/assertions.h" "${export_dir}/libsojsoncpp/include/json/assertions.h" COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/autolink.h" "${export_dir}/libsojsoncpp/include/json/autolink.h" COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/json.h" "${export_dir}/libsojsoncpp/include/json/json.h" COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/version.h" "${export_dir}/libsojsoncpp/include/json/version.h" ) 复制代码
-
修改 ../cpp/CMakeLists.txt如下:
cmake_minimum_required(VERSION 3.4.1) set(CMAKE_VERBOSE_MAKEFILE on) # 设置资源主目录 CMAKE_CURRENT_SOURCE_DIR 代表当前CMakeLists.txt 所在的目录 set(lib_src_DIR ${CMAKE_CURRENT_SOURCE_DIR}) # 设置CMake编译后文件的存放的临时目录 set(lib_build_DIR $ENV{HOME}/tmp) # 得到 lib_build_DIR 文件夹内文件 file(MAKE_DIRECTORY ${lib_build_DIR}) # 添加子目录 add_subdirectory(${lib_src_DIR}/jsoncpp ${lib_build_DIR}/jsoncpp) 复制代码
-
修改 ../app/build.gradle如下:
apply plugin: 'com.android.application' android { ... defaultConfig { ... externalNativeBuild { cmake { // 这里的名字最好和 ../cpp/jsoncpp/CMakeLists.txt 中设置的名字相同 targets 'jsoncpp' } ... } } ... externalNativeBuild { cmake { path 'src/main/cpp/CMakeLists.txt' } } } 复制代码
说明:点击Build/Make Project(或者 Make Module 'app') 会在 项目根目录下 新建 export 文件夹 在里面会存放 库所需的头文件和so动态库。编译后如下:
so和头文件都生成了,但是我们在写../cpp/jsoncpp/CMakeLists.txt 文件时,也发现了,将所需的头文件导出到指定目录时有点儿费劲,只是名字换了下,若是用代码来写的话,一个for循环就可以了,那么在CMakeLists.txt中,可不可以实现类似的呢?哈哈,那当然是肯定的了,最终修改如下:
cmake_minimum_required(VERSION 3.4.1) set(CMAKE_VERBOSE_MAKEFILE on) add_library( jsoncpp SHARED src/json_tool.h src/json_reader.cpp src/json_valueiterator.inl src/json_value.cpp src/json_writer.cpp src/version.h.in) set(export_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../export) set_target_properties( jsoncpp PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${export_dir}/libsojsoncpp/lib/${ANDROID_ABI}") add_custom_command( TARGET jsoncpp POST_BUILD # 将 ${CMAKE_CURRENT_SOURCE_DIR}/src/json 文件夹下的文件 导出到 ${export_dir}/libajsoncpp/include/json/ 文件夹内 COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/src/json" "${export_dir}/libsojsoncpp/include/json/") 复制代码
将之前生成的export文件夹删除,重新build发现是可以的。
OK,动态库可以编译成功,那么讲道理,静态库也是一样的,来尝试下编译静态库库。
编译a静态库
在以上编译so动态库的前提下,修改../cpp/jsoncpp/CMakeLists.txt如下:
cmake_minimum_required(VERSION 3.4.1) set(CMAKE_VERBOSE_MAKEFILE on) add_library( jsoncpp # 将 库 类型 由 SHARED 修改为 STATIC STATIC src/json_tool.h src/json_reader.cpp src/json_valueiterator.inl src/json_value.cpp src/json_writer.cpp src/version.h.in) set(export_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../export) set_target_properties( jsoncpp # 将 LIBRARY_OUTPUT_DIRECTORY 修改为 ARCHIVE_OUTPUT_DIRECTORY # 方便查看 生成的a文件目录修改一下 即 将 libsojsoncpp 修改为 libajsoncpp PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${export_dir}/libajsoncpp/lib/${ANDROID_ABI}") add_custom_command( TARGET jsoncpp POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/src/json" "${export_dir}/libajsoncpp/include/json/" ) 复制代码
修改完成后,Build/Make Project(或者 Make Module 'app') 会在 Project/export目录下生成:
这样编译.a静态库和.so动态库就完成了。
下篇我们讲如何链接 生成的so动态库和a静态库,以及动态库和静态库的区别;点击调转到下一篇:
Demo链接: UseCmakeBuildLib
END
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 关于内存你需要了解的(二)
- 你需要了解的 nginx 基础配置
- 关于 CPU 你需要了解的(二)
- 前端也需要了解的 JSONP 安全
- UMI.js需要了解的知识
- 关于 Android 编译,你需要了解什么
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。