最近在用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. WinDbg常用命令系列---!uniqstack

    简介 这个!uniqstack扩展扩展显示的所有线程的堆栈的所有当前进程,不包括显示为具有重复项的堆栈中. 使用形式 !uniqstack [ -b | -v | -p ] [ -n ] 参数 -b将 ...

  2. Install Python3.6 on Amazon Linux/EC2 在Amazon Linux实例中安装使用Python3.6

    本文转载自 https://gist.github.com/niranjv/f80fc1f488afc49845e2ff3d5df7f83b 由于Amazon Linux中预装的Python版本为2. ...

  3. mysql课外积累

    where 与 on 的区别 : ON:针对关联表进行条件筛选,不会影响结果集的数量和主表数据. WHERE:针对结果集进行条件筛选,会影响结果集的数量. LIKE声明中的%和_是什么意思? --%对 ...

  4. Zookeeper请求处理原理分析

    Zookeeper是可以存储数据的,所以我们可以把它理解一个数据库,实际上它的底层原理本身也和数据库是类似的. 一.数据库的原理 我们知道,数据库是用来存储数据的,只是数据可以存储在内存中或磁盘中.而 ...

  5. WDM驱动改可手动加卸载的NT驱动

    WDM驱动改可手动加卸载的NT驱动 测试工具:osrloader 把一个WDM类型的驱动改成可动态加载/卸载,需要做以下2个修改: 1. 把SOURCES文件夹中的DRIVERTYPE=WDM去掉 2 ...

  6. [技术博客] 自制 apt deb Repository

    [技术博客] 自制 apt deb Repository (termux) 在修改整合遵循GPLv3的Android terminal app and Linux environment:termux ...

  7. Ubuntu 17.10安装VirtualBox 5.2.2 及相关问题解决

    link:https://www.linuxidc.com/Linux/2017-11/148870.htm sudo apt update && sudo apt upgrade s ...

  8. Spring的注解收集

    @Scope("prototype")spring 默认scope 是单例模式scope="prototype" 可以保证 当有请求的时候 都创建一个Actio ...

  9. Cross-channel Communication Networks

    Cross-channel Communication Networks 2019-12-13 14:17:18 Paper: https://papers.nips.cc/paper/8411-cr ...

  10. epool与select有什么区别

    select在一个进程中打开的最大fd是有限制的,由FD_SETSIZE设置,默认值是2048.不过 epoll则没有这个限制,它所支持的fd上限是最大可以打开文件的数目,这个数字一般远大于2048, ...