最近在用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. linux MySQL5.7 rpm安装(转)

    删除旧包: # rpm -qa | grep -i mysql # rpm -ev mysql-libs-* --nodeps 安装rpm包: # rpm -ivh mysql-community-c ...

  2. 用户管理命令——useradd、paaswd、who、w

    1.useradd和passwd命令: 其中:useradd用来添加用户,passwd用来添加用的的密码: 用户创建后可以用用户名和密码进行登录. 2.passwd:密码的更改: (1)普通用户: 只 ...

  3. pmm docker-compose 运行试用

    pmm 是一个很不错的mysql.mongo.postgresql 数据库监控平台,基于prometheus.grafana.exporter 算是一个比较完整 的数据库分析平台 参考架构图 环境准备 ...

  4. 7.学习springmvc的异常处理

    一.页面的异常处理流程 二.建立项目springmvc04_exception 1.编写index.jsp页面: <%@ page contentType="text/html;cha ...

  5. The real universe

  6. P3350 [ZJOI2016]旅行者

    题目描述 小Y来到了一个新的城市旅行.她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n*m个路口 (i,j)(1<=i<=n,1&l ...

  7. centos服务器升级nodejs, pm2

    突然抽风想升级服务器的nodejs版本,原服务器版本运行的8.x,而目前(2019年5月30日)nodejs官方最新版本已经更新到了12.x了,稳定版本也更新到了10.x. 然后就折腾了一把去升级服务 ...

  8. GSEA 基因集富集分析

    http://software.broadinstitute.org/gsea/index.jsp GSEA(Gene Set Enrichment Analysis)是一种生物信息学的计算方法,用于 ...

  9. 经典算法(一) top k

    问题:1亿数据中,找出最大的k个数,要求使用内存不超过1m (延伸问题:1亿数据中,找出重复出现次数最多的k个,要求使用内存不超过1m 等) 分析: 1亿数字(int)占内存:100000000 * ...

  10. ImportError: DLL load failed while importing win32api: 找不到指定的模块。

    这个是用pip install pywin32安装报的一个错误 据说直接使用pip install pypiwin32安装就不会有报错 但是遇到错误还是要尝试解决一下的 pip install pyw ...