内容简介: 这个在写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 编译,你需要了解什么
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Beginning Apache Struts
Arnold Doray / Apress / 2006-02-20 / USD 44.99
Beginning Apache Struts will provide you a working knowledge of Apache Struts 1.2. This book is ideal for you Java programmers who have some JSP familiarity, but little or no prior experience with Ser......一起来看看 《Beginning Apache Struts》 这本书的介绍吧!