最近在用Qt开发Android应用时需要获取https页面内容,但Qt内置的QNetworkAccessManager类只支持下面这些协议(调用其supportedSchemes成员函数获取):

("ftp", "file", "qrc", "http", "data")

而网上我找到的支持https的介绍是使用QSslConfiguration类,然后把OpenSSL的两个DLL(libeay32.dll和ssleay32.dll)复制到Qt库目录中,但我始终没成功,也就懒得在手机上折腾了。

这个思路不行,还有两个方案:一是通过QAndroidJniEnvironment和QAndroidJniObject调用Android SDK中封装的Https访问代码,还有就是通过cURL库,可以复用以前的代码,而且性能也不错,所以选择这个方案。

首先是准备工作:

  • Windows(Win10 x64)

    • 下载并安装msys2(http://repo.msys2.org/distrib/x86_64/),启动msys2_shell.cmd脚本,运行“pacman -Syuu”升级后关闭控制台窗口,重新启动后再运行一遍。这一步是可选的,如果不更新应该也可以,但我是更新后开始下一步的。
    • 下载Windows版NDK并安装
    • 设置ANDROID_NDK_HOME环境变量:exprot ANDROID_NDK_HOME=/d/android-ndk-r20
    • 更新PATH环境变量:export PATH="/d/android-ndk-r20/toolchains/llvm/prebuilt/windows-x86_64/bin/":$PATH
  • Linux(CentOS 8)
    • 下载Linux版NDK并安装
    • 设置ANDROID_NDK_HOME环境变量:exprot ANDROID_NDK_HOME=/home/user/android-ndk-r20
    • 更新PATH环境变量:export PATH="/home/user/android-ndk-r20/toolchains/llvm/prebuilt/linux-x86_64/bin":$PATH
  • 下载OpenSSL源码包,版本必须是1.1.x,开始我没注意,用的是之前下载的1.0.x,折腾了很长时间也没搞定,郁闷!
  • 下载cURL源码包,我用的版本是7.66.0

然后就可以开工,下面列出的命令都是Linux平台,Windows里面msys2的命令大同小异。

生成OpenSSL

  • cd openssl-1.1.1d
  • ./Configure shared android-arm -D__ANDROID_API__=23 no-asm no-ssl2 no-ssl3 no-comp no-hw no-engine --prefix=/usr/local/ssl
  • make -j && make install

上面第二行命令中的android-arm参数要注意,脚本提示可选的系统/编译器有很多:

android-arm android-arm64 android-armeabi android-mips android-mips64 android-x86 android-x86_64 android64 android64-aarch64 android64-mips64 android64-x86_64

但要选择哪个取决于你所用NDK根目录下“platforms/android-xx”里面的子目录能对应上才行,例如android-ndk-r20中的android-16里面只有arch-arm和arch-x86,所以如果命令行设置__ANDROID_API__=16的话,是不能生成android-arm64版库文件的。

接下来是cURL

  • cd curl-7.66.0
  • CC=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi23-clang ./configure --prefix=/usr/local/curl --host=arm-linux-androideabi --with-ssl=/usr/local/ssl/
  • make -j && make install

在用到Qt项目之前,先写个控制台程序测试一下:

 #include <iostream>
#include <map>
#include <string>
#include <curl/curl.h> using namespace std; #define URL u8R"(https://raw.githubusercontent.com/LCTT/LFS-BOOK/9.0-translating/README.md)" typedef std::map<std::string, std::string> HeaderFields;
typedef struct {
int code;
std::string body;
HeaderFields headers;
} Response; size_t write_callback( void *data, size_t size, size_t nmemb, void *userdata )
{
Response *r = reinterpret_cast< Response * >( userdata );
r->body.append( reinterpret_cast< char * >( data ), size * nmemb );
return size * nmemb;
} int _cURL()
{
if( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK )
{
cout << "Call curl_global_init failed! \n";
return ;
}// if CURL *curlHandle = curl_easy_init();
CURLcode res = CURLE_OK;
curl_slist *headerList = nullptr;
Response ret = {};
curl_easy_setopt( curlHandle, CURLOPT_URL, URL );
curl_easy_setopt( curlHandle, CURLOPT_WRITEFUNCTION, write_callback );
curl_easy_setopt( curlHandle, CURLOPT_WRITEDATA, &ret );
curl_easy_setopt( curlHandle, CURLOPT_SSL_VERIFYPEER, );
curl_easy_setopt( curlHandle, CURLOPT_SSL_VERIFYHOST, );
res = curl_easy_perform( curlHandle );
if( res != CURLE_OK )
cout << "The result code is: " << ( int )res << "\n";
if( false == ret.body.empty() )
cout << ret.body << "\n";
curl_easy_cleanup( curlHandle );
curl_global_cleanup(); return ;
} int main()
{
return _cURL();
}

保存为test.cc,然后生成Android控制台程序:

$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi23-clang++ test.cc -I/usr/local/curl/include -Wl,-Bstatic -lcurl -lssl -lcrypto -Wl,-Bdynamic -o test

注意curl、ssl和crypto三个库用-Wl,-Bstatic方式指定链接静态库(顺序不能错),否则默认会链接动态库,但非root手机没有复制动态库到系统目录的权限,所以需要静态链接得到test,然后开启Android手机的调试模式并连接主机USB,最后在命令行切换到Android SDK的platform-tools目录:

  • 把文件复制到手机存储器:adb push test /data/local/tmp
  • 启动adb Shell:adb shell
  • 文件添加可执行权限:chmod +x /data/local/tmp/test
  • 启动:/data/local/tmp/test

顺利的话就可以正确获取并显示页面中的文本,然后就可以导入Qt项目,首先把cURL的头文件都复制到项目的目录中,然后把libcurl.a、libssl.a和libcrypto.a三个库文件复制到项目路径的android/lib中,修改*.pro文件,添加下面一行:

LIBS += -L$$PWD/android/lib -lcurl -lssl -lcrypto

如果已经有LIBS就在后面加上-lcurl -lssl -lcrypto三个库的引用,最后即可生成APK。

注意:

  • 如果系统没有GNU binutils,运行cURL的configure脚本前需要把NDK的路径添加到PATH,而且是添加对应生成目标的路径,例如要生成64位arm指令集:
PATH=“$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/aarch64-linux-android/bin/”:$PATH

然后在生成不同目标平台库的时候先切换,例如通用arm指令集:

PATH=“$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/arm-linux-androideabi/bin/”:$PATH
  • Qt应用项目的Android系统版本号要大于等于生成cURL和OpenSSL设置的__ANDROID_API__版本号,否则链接时可能会出现找不到stdin、stdout和stderr外部符号的错误,一般生成库都是选个低点的系统版本兼容性更好。

用NDK生成cURL和OpenSSL库的更多相关文章

  1. Android NDK生成及连接静态库与动态库

    对于Android应用开发,大部分情况下我们使用Java就能完整地实现一个应用.但是在某些情况下,我们需要借助C/C++来写JNI本地代码.比如,在使用跨平台的第三方库的时候:为了提升密集计算性能的时 ...

  2. C++调用openssl库生成RSA加密秘钥对

    直接上代码.默认生成的是pkcs#1格式 // ---- rsa非对称加解密 ---- // #define KEY_LENGTH 1024 // 密钥长度 #define PUB_KEY_FILE ...

  3. Android NDK生成共享库和静态库

    Date: 2014-03-14 Title: Compile Android Native Binary And Library Published: true Type: post Tags: A ...

  4. NDK jni 加载静态库

    加载静态库到android,静态库的提供方式有2种, a. 通过源文件来编译静态库 b. 加载已经编译好的静态库 首先我们来看,通过源文件来编译静态库,工程目录如下 第一步:我们来看我们的jni目录, ...

  5. android开发 NDK 编译和使用静态库、动态库 (转)

    在eclipse工程目录下建立一个jni的文件夹 在jni文件夹中建立Android.mk和Application.mk文件 Android.mk文件: Android提供的一种makefile文件, ...

  6. 使用openssl库实现RSA、AES数据加密

         openssl是可以很方便加密解密的库,可以使用它来对需要在网络中传输的数据加密.可以使用非对称加密:公钥加密,私钥解密.openssl提供了对RSA的支持,但RSA存在计算效率低的问题,所 ...

  7. vs2010编译curl为static库及测试

    1,编译curl为static库 用vs2010打开: curl-7.32.0\vs\vc6\vc6curl.dsw 选择LIB Release生成libcurl静态库: curl-7.32.0\vs ...

  8. php开启curl和openssl

    php开启curl和openssl 开启php curl函数库的步骤 1).去掉windows/php.ini 文件里;extension=php_curl.dll前面的; /*用 echo phpi ...

  9. [转]使用openssl库实现RSA、AES数据加密

    openssl是可以很方便加密解密的库,可以使用它来对需要在网络中传输的数据加密.可以使用非对称加密:公钥加密,私钥解密.openssl提供了对RSA的支持,但RSA存在计算效率低的问题,所以一般的做 ...

随机推荐

  1. Math小记

    20161231 黄金分割比:短/长=长/(短+长)=((根号5)-1)/2 ≍ 0.618 斐波那契数列前后两项的比值存在极限.设其中三个数为a.b.(a+b),则当项数趋于无穷时有a/b=b/(a ...

  2. xms西软预定列表-房类市场

    select b.descript,sum(a.quan) as quan,case WHEN c.descript is null THEN '团队预留' ELSE c.descript end a ...

  3. 使用Lua脚本通过原子减防止超卖

    需求 双十二要搞一个一分钱门票抢购的活动. 分析 性能分析,抢购时会发生高并发,如果仅仅依靠Mysql数据库,有可能因为大量的请求频繁访问数据库造成服务器雪崩,所以考虑通过Redis减库存,最终的数据 ...

  4. 市值TOP10,人类进化及中美坐标

    题记:观察人类进化,以及各国.各民族在这个进化中所起的作用.所处的位置,市值 TOP 10 的变迁,会是一个再好不过的指标! 2008年,经历了全球金融危机后,原油期货一路飙升,创出了147.27美元 ...

  5. 经典算法(三) 单链表 反转 & 是否相交/成环 & 求交点 等

    参考文章: 判断链表是否相交:http://treemanfm.iteye.com/blog/2044196 一.单链表反转 链表节点 public class Node { private int ...

  6. [Beta]Scrum Meeting#10

    github 本次会议项目由PM召开,时间为5月15日晚上10点30分 时长15分钟 任务表格 人员 昨日工作 下一步工作 木鬼 撰写博客整理文档 撰写博客整理文档 swoip 为适应新功能调整布局前 ...

  7. odoo开发笔记 -- 当前时间&时间运算相关

    当前日期/时间: from datetime import datetime, timedelta now_time = datetime.now() today_date_format = now_ ...

  8. 一行命令搞定/usr/bin/perl^M: bad interpreter

    https://www.cnblogs.com/albertYe/p/8819143.html **************************************************** ...

  9. Visual-Based Autonomous Driving Deployment from a Stochastic and Uncertainty-Aware Perspective

    张宁 Visual-Based Autonomous Driving Deployment from a Stochastic and Uncertainty-Aware Perspective Le ...

  10. Srping的IOC

    XML方式: IOC:控制反转的底层原理就是:工厂模式+反射+配置文件DI:依赖注入就是通过配置文件设置属性值 BeanFactory 是老版本的工厂类:调用getBean的时候,才会生成类的实例Ap ...