虽然本篇和上篇没很大的关系,但…仍是建议先去看下上篇----初次使用CMake构建native项目java
这个在写JNI的时候就很常见了,好比json库,C++本身是没有提供json库的,而后咱们在写JNI的时候,一般须要和上层交互数据,较简单的就是json了,那么就拿json来作讲解吧。首先来找一个json库啦!android
jsoncpp本篇就用这个json库来作讲解吧,首先把代码clone下来。c++
将include里的json文件夹拷贝到../app/src/main/cpp目录下;git
将src/lib_json里面的文件除去 CMakeLists.txt拷贝到../app/src/main/cpp目录下;github
最终以下:json
修改../app/src/main/cpp/CMakeLists.txt以下:app
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一下ide
What Are you!!!出错了,告诉在json_tool.h的第10行出错了,那行吧,点进去瞅一眼,以下:工具
哦,include错了,应该改成 #include “json/config.h” 那就改吧!cv过来的全部文件都得去查看一下(试想一下,如果cv过来的文件有1W个,咋办…,改完这个,未来别的地方在引用,又忘了那个曾经是改过的了,停!stop,我眼疼!)。post
打开../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打成库呢?那么咱们就要考虑以下:
好吧,基于以上两点,百度搜了一波,发现…GG,没有符合的哎,用CMake就得去Linux下面,且须要本身构建工具链,要否则就是…mk…。再去Google搜一搜,发现仍是这样的,难道,不存在?再去GitHub搜,发现没有相关的,迫不得已,去Google提供的sample中找一找吧,哈!还真有发现,连接:hello-libs
修改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,动态库能够编译成功,那么讲道理,静态库也是同样的,来尝试下编译静态库库。
在以上编译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