雖然本篇和上篇沒很大的關係,但…仍是建議先去看下上篇----初次使用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