如果不知道在CMake中依赖第三方库,请看我以前的文章:
需求
我们在安卓中使用网络请求并解析json很容易,有很多很方便的框架,如:okhttp,retrofit,android-async-http,volley。
但是如果我们的需求是:不能把请求网络的协议url暴露出去,并且把直接返回的JSON阉割部分字段再抛出去,例如做SDK开发。
虽然我们可以使用java的混淆,但是如果多用点心,混淆过的jar还是可以反编译出来的。(使用抓包工具Fidder请忽略,o(╯□╰)o)
此时,在JNI中使用C/C++请求网络是很不错的选择。
第三方库
curl:C中请求网络很好的库,项目地址:
jsoncpp:c++中解析json很方便的库,项目地址:
工程结构
- cpp:与C有关的代码
- cpp/include:第三方库依赖的头文件
- JniUtils.cpp/JniUtils.h:我封装的常用JNI工具类
- native-lib.cpp:与java交互的类
- web_task.cpp/web_task.h:对curl库第二次封装
curl请求网络
身边的一个大神把libcurl封装下,封装源码太长了,放在github上,封装后请求网络就变得非常容易,几行代码搞定,返回的json数据在jsonResult中。
GET请求
//GET请求
string url = "http://www.weather.com.cn/data/sk/101280601.html";
WebTask task;
task.SetUrl(url.c_str());
task.SetConnectTimeout(5);
task.DoGetString();
if (task.WaitTaskDone() == 0) {
//请求服务器成功
string jsonResult = task.GetResultString();
}
POST请求
//POST请求,url随便举例的
string url = "http://www.weather.com.cn/user/add";
WebTask task;
task.SetUrl(url.c_str());
task.SetConnectTimeout(5);
task.AddPostString("username", username);
task.AddPostString("password", password);
task.AddPostString("email", email);
if (task.WaitTaskDone() == 0) {
//请求服务器成功
string jsonResult = task.GetResultString();
}
几行代码搞定网络请求,是不是有种使用安卓框架的感觉。
jsoncpp解析json
接下来该使用jsoncpp解析json数据,请求天气网址返回的json如下:
{
"weatherinfo": {
"city": "深圳",
"cityid": "101280601",
"temp": "21",
"WD": "南风",
"WS": "1级",
"SD": "31%",
"WSE": "1",
"time": "17:05",
"isRadar": "1",
"Radar": "JC_RADAR_AZ9755_JB",
"njd": "暂无实况",
"qy": "1014",
"rain": "0"
}
}
- 如果是json根节点,如下:
//根节点
Json::Value weatherinfo = root["weatherinfo"];
string js1 = weatherinfo["city"].asString();
LOGI("根节点解析: %s\n", js1.c_str());
- 如果字段是string,如下:
string city = root["weatherinfo"]["city"].asString(); - 如果字段是int,如下:
int year= root["year"].asInt();
回到上面的例子,附上解析的代码:
Json::Reader reader;
Json::Value root;
//从字符串中读取数据
if (reader.parse(jsonResult, root)) {
/*//根节点
Json::Value weatherinfo = root["weatherinfo"];
string js1 = weatherinfo["city"].asString();
LOGI("根节点解析: %s\n", js1.c_str());*/
//读取子节点信息
string city = root["weatherinfo"]["city"].asString();
string temp = root["weatherinfo"]["temp"].asString();
string WD = root["weatherinfo"]["WD"].asString();
string WS = root["weatherinfo"]["WS"].asString();
string time = root["weatherinfo"]["time"].asString();
string result = "城市:" + city + "\n温度:"+ temp+ "\n风向:" + WD + "\n风力:"+ WS + "\n时间:" + time;
结束
如果你不想自己生成libcurl.a和libjsoncpp.a文件,可以直接使用我工程的。
此外对网络库libcurl封装的代码也放在github上。
工程中的JniUtils.h和JniUtils.cpp是我封装的,功能如下:
- 在JNI中打印Android的log
- 将java的string转化成c的字符串
- 将C字符串转java字符串
才是开始做NDK开发,也才开始写blog,请赏我个star,感激不尽!
更多jsoncpp使用
Json文件的生成和解析
C++ 解析Json——jsoncpp
C++的Json解析库:jsoncpp和boost
C++ JSON文件的读取和生成