用NDK生成cURL和OpenSSL库
最近在用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库的更多相关文章
- Android NDK生成及连接静态库与动态库
对于Android应用开发,大部分情况下我们使用Java就能完整地实现一个应用.但是在某些情况下,我们需要借助C/C++来写JNI本地代码.比如,在使用跨平台的第三方库的时候:为了提升密集计算性能的时 ...
- C++调用openssl库生成RSA加密秘钥对
直接上代码.默认生成的是pkcs#1格式 // ---- rsa非对称加解密 ---- // #define KEY_LENGTH 1024 // 密钥长度 #define PUB_KEY_FILE ...
- Android NDK生成共享库和静态库
Date: 2014-03-14 Title: Compile Android Native Binary And Library Published: true Type: post Tags: A ...
- NDK jni 加载静态库
加载静态库到android,静态库的提供方式有2种, a. 通过源文件来编译静态库 b. 加载已经编译好的静态库 首先我们来看,通过源文件来编译静态库,工程目录如下 第一步:我们来看我们的jni目录, ...
- android开发 NDK 编译和使用静态库、动态库 (转)
在eclipse工程目录下建立一个jni的文件夹 在jni文件夹中建立Android.mk和Application.mk文件 Android.mk文件: Android提供的一种makefile文件, ...
- 使用openssl库实现RSA、AES数据加密
openssl是可以很方便加密解密的库,可以使用它来对需要在网络中传输的数据加密.可以使用非对称加密:公钥加密,私钥解密.openssl提供了对RSA的支持,但RSA存在计算效率低的问题,所 ...
- vs2010编译curl为static库及测试
1,编译curl为static库 用vs2010打开: curl-7.32.0\vs\vc6\vc6curl.dsw 选择LIB Release生成libcurl静态库: curl-7.32.0\vs ...
- php开启curl和openssl
php开启curl和openssl 开启php curl函数库的步骤 1).去掉windows/php.ini 文件里;extension=php_curl.dll前面的; /*用 echo phpi ...
- [转]使用openssl库实现RSA、AES数据加密
openssl是可以很方便加密解密的库,可以使用它来对需要在网络中传输的数据加密.可以使用非对称加密:公钥加密,私钥解密.openssl提供了对RSA的支持,但RSA存在计算效率低的问题,所以一般的做 ...
随机推荐
- MongoDB 部署复制集(副本集)
部署MongoDB复制集(副本集) 环境 操作系统:Ubuntu 18.04 MongoDB: 4.0.3 服务器 首先部署3台服务器,1台主节点 + 2台从节点 3台服务器的内容ip分别是: 1 ...
- bzoj4605: 崂山白花蛇草水 权值线段树套KDtree
bzoj4605: 崂山白花蛇草水 链接 bzoj loj 思路 强制在线,那就权值线段树套KDtree好了,没啥好讲的. KDtree要加平衡因子来重构.另外,那水真难喝. 错误 树套树一边写过了, ...
- 安全测试基础-SQL注入详解
1:什么是SQL注入 SQL注入是一种将SQL代码插入或添加到应用(用户)的输入参数中的攻击,之后再将这些参数传递给后台的SQL服务器加以解析并执行. www.xx.com/news.php?id=1 ...
- Mac版最详细的Flutter开发环境搭建
上周任务不多,闲来无事想学习一下flutter耍一耍,发现flutter的环境搭建步骤还是很繁琐的,官网的搭建教程只是按步骤让你进行操作,中间出现的问题完全没有提及,对我这种没搞过原生开发的小白来说超 ...
- [Beta]Scrum Meeting#10
github 本次会议项目由PM召开,时间为5月15日晚上10点30分 时长15分钟 任务表格 人员 昨日工作 下一步工作 木鬼 撰写博客整理文档 撰写博客整理文档 swoip 为适应新功能调整布局前 ...
- Elasticsearch Java Rest Client简述
ESJavaClient的历史 JavaAPI Client 优势:基于transport进行数据访问,能够使用ES集群内部的性能特性,性能相对好 劣势:client版本需要和es集群版本一致,数据序 ...
- @Autowired和@Resource的区别和联系
背景: 今天下班路上看到一个大货车,于是想到了装配,然后脑海里跳出了一个注解@Autowired(自动装配),于是又想到最近工作项目用的都是@Resource注解来进行装配.于是本着学什么东西都要一钻 ...
- Curator框架实现ZooKeeper分布式锁
排他锁(X) 这里主要讲讲分布式锁中的排他锁.排他锁(Exclusive Locks,简称X锁),又称为写锁或独占锁,是一种基本的锁类型.如果事务T1对数据对象O1加上了排他锁,那么在整个加锁期间,只 ...
- hive函数 get_json_object
pandas和SQL数据分析实战 https://study.163.com/course/courseMain.htm?courseId=1006383008&share=2&sha ...
- 【嵌入式开发】裸机引导操作系统和ARM 内存操作 ( DRAM SRAM 类型 简介 | Logical Bank | 内存地址空间介绍 | 内存芯片连接方式 | 内存初始化 | 汇编代码示例 )
[嵌入式开发]ARM 内存操作 ( DRAM SRAM 类型 简介 | Logical Bank | 内存地址空间介绍 | 内存芯片连接方式 | 内存初始化 | 汇编代码示例 ) 一. 内存 ...