TidHTTP 在 Android 上出现错误 "Could not load SSL library"
Error "Could not load SSL library" on Android with TidHTTP
我正在尝试在 Delphi 西雅图下载 TIdHTTP.Get 的文件。这是 android 的应用程序,我的所有尝试都失败了。我得到的都是同样的错误 "Could not load SSL library"。这是程序:
procedure TfrmMain.DownloadPicture(const AURL: string);
var
MeS: TMemoryStream;
cidSSL: TIdSSLIOHandlerSocketOpenSSL;
cidHTTP: TIdHTTP;
begin
cidHTTP:= TIdHTTP.Create(nil);
cidSSL:= TIdSSLIOHandlerSocketOpenSSL.Create(nil);
Mes := TMemoryStream.Create;
try
cidHTTP.ReadTimeout := 30000;
cidHTTP.IOHandler := IdSSL;
cidSSL.SSLOptions.Method := sslvSSLv3;
cidSSL.SSLOptions.Mode := sslmUnassigned;
cidSSL.StartSSL;
cidHTTP.Get(AURL, Mes);
except
on E : Exception do
begin showmessage('Error: '+E.Message);
end;
end;
Mes.Position := 0;
frmImage.Image.Bitmap.LoadFromStream(Mes);
end;
可能您有一个新的 OpenSSL 库和一个旧的 Indy 版本。检查这个:
Indy 10 - IdSMTP.Connect raising "Could not load SSL library."
有 32/64 位版本。
确保您拥有正确版本的文件。
请参阅 this FTP 了解正确的版本。
用于下载二进制文件的其他镜像 here。
如果您不是 使用 Android 6 Marshmallow,OpenSSL 应该可以在 Android 上正常工作。当您遇到“无法加载”错误时,您可以在 IdSSLOpenSSLHeaders
单元中调用 Indy 的 WhichFailedToLoad()
函数来找出无法加载 OpenSSL 的原因。如果您的设备没有预装 OpenSSL,您可以使用您的应用程序部署 OpenSSL 二进制文件,并使用 Indy 的 IdOpenSSLSetLibPath()
函数告诉 Indy 从哪里加载它们。
也就是说,从 Android 6 Marshmallow 开始,Google no longer supports OpenSSL on Android. It has been replaced with a custom fork named BoringSSL, which Indy does not fully support yet (although some BoringSSL-related changes have been made to Indy after Seattle's release). So, if you are having trouble with using Indy SSL/TLS on Android 6, you can try upgrading to the latest Github snapshot 看看是否有帮助。
BoringSSL 对 OpenSSL API 接口进行了一些主要 更改(删除函数、更改数据类型等),因此它不向后兼容现有的 OpenSSL代码。但更糟糕的是,BoringSSL 使用与 OpenSSL 相同的库文件名,并在设备启动时预加载,因此无法使用您的 Android 应用程序部署自定义构建的 OpenSSL 库二进制文件。当应用程序试图在运行时加载 OpenSSL 库文件名时,Android 将仅使用预加载的 BoringSSL 二进制文件(无论您是否调用 Indy 的 IdOpenSSLSetLibPath()
函数)。
Indy 在 Android 的 NDK 级别运行,而不是 Java 级别,因此要使 Indy 避免 BoringSSL 将要求用户:
使用与 BoringSSL 不冲突的新文件名重新编译 OpenSSL 库(据我所知,没有可用的已知版本),然后更新 Indy 以使用这些文件名。
将 OpenSSL 源代码直接编译到他们的 Android 应用程序中。 Indy 当前未设置为在 iOS 以外的任何平台上支持 OpenSSL 的静态 linking,但这应该是一个小改动,以更新 Indy 的 IdSSLOpenSSLHeaders_static
单元,如果有人可以在 Android 上为 OpenSSL 生成可行的 .a
文件。我知道至少有一个用户尝试过这条路线,但该用户尚未成功(错误地使源代码完全 link 正确)。
切换到 Android 更高级别的基于 Java 的加密 API。这是 Google 的首选解决方案。但 Indy 目前不支持它。这样做需要为 Android 套接字 I/O 和 SSL/TLS 编写一整套新的 TIdStack
和 TIdIOHandler
类,使用 JNI 调用来访问Java APIs。但这有需要处理的性能和线程问题。
因此,目前没有已知可行的解决方法可以使 Indy SSL/TLS 在 Android 6+ 上运行。
更新:Embarcadero 论坛中的用户能够找到与 Indy 兼容并在 Android 上工作的 OpenSSL .so
文件 6:
https://forums.embarcadero.com/thread.jspa?threadID=211089
After many reports of my apps crashing if installed in Android 6 devices I've searched the net for some tips and the couple of needed .so compiled files, 1.02 version, added the two files to the play store deployment of my apps (assets\internal) and changed the Indy's path calling
IdOpenSSLSetLibPath(TPath.GetDocumentsPath)
in the OnCreate of my datamodule.
After those modifications of my code my Apps run perfectly on my brand new S7 with Android 6.0.1, and on all the other recent Android devices (tested using the Play Store deployment).
And now the Google warning pops up telling me that the OpsnSSL files deployed with my apps are not of the minimum required 1.02f version (or 1.01r).... and so my post in this forum.
...
Anyway you can download here the latest .so files, the ones that I deploy at this moment:
https://drive.google.com/file/d/0B7AxqW32K0oXWW9nUk9qaFpHT0k/view?usp=sharing
同一讨论中的另一位用户似乎也取得了一些成功:
Ive been running on android 6 loading the .so libraries just fine for months. The new problem is we need to compile new versions of the openssl libraries. Cygwin is not working correctly to compile for me so im switching to a linux install to create them (if possible) https://wiki.openssl.org/index.php/Android#Build_the_OpenSSL_Library_2
heres a repository you can grab some current prebuilt ones https://github.com/emileb/OpenSSL-for-Android-Prebuilt.git
更新:以下(德语)论坛讨论为注册用户提供 Android(和 iOS 模拟器)的 OpenSSL 1.0.2g 二进制文件。他们不会在 Google Play 商店中显示安全警告:
http://www.delphipraxis.net/188736-kompilierte-openssl-bibliotheken-fuer-android.html
OpenSSL 1.0.2g iOS Simulator.zip
更新:OpenSSL 1.0.2g 的 Android 二进制文件现已在 Embarcadero 附件论坛中可用:
https://forums.embarcadero.com/thread.jspa?threadID=211147
然后,要加载 OpenSSL 而不是 BoringSSL,请按照以下步骤操作:
将 2 个 .so
文件添加到项目部署并将它们设置为部署到 .\assets\internal\
文件夹
将 System.StartupCopy
单元添加为 DPR 的 uses
子句中的第一个单元。
在应用程序启动时调用 IdOpenSSLSetLibPath(TPath.GetDocumentsPath)
。
更新:OpenSSL 1.0.1t 和 1.0.2h 二进制文件现在位于 Embarcadero 附件论坛中:
https://forums.embarcadero.com/thread.jspa?threadID=211147
更新:二进制文件现已发布在 Indy 的 Fulgan 镜像上:
更新:Indy 不再使用 Fulgan 镜像来托管 OpenSSL 二进制文件。他们现在在自己的 GitHub 仓库中:
https://www.indyproject.org/2020/06/16/openssl-binaries-moved-to-github/
只需将 TidHTTP 组件换成 TNetHTTPClient
我使用这段代码并且有效:
procedure TfPrecos.GetImageByUrl(URL: string);
var
Strm: TMemoryStream;
vIdHTTP: TIdHTTP;
cidSSL: TIdSSLIOHandlerSocketOpenSSL;
begin
IdOpenSSLSetLibPath(TPath.GetDocumentsPath); //libcrypto.so and libssl.so in ./assets/internal
vIdHTTP.IOHandler := cidSSL;
cidSSL.SSLOptions.Method := sslvSSLv23; // version 2.3
cidSSL.SSLOptions.Mode := sslmUnassigned;
cidSSL.StartSSL;
try
vIdHTTP.Get(URL, Strm);
if (Strm.Size > 0) then
begin
Strm.Position := 0;
try
Image1.Bitmap.LoadFromStream(Strm);
finally
end;
end;
finally
Strm.DisposeOf;
vIdHTTP.DisposeOf;
end;
end;
我正在尝试在 Delphi 西雅图下载 TIdHTTP.Get 的文件。这是 android 的应用程序,我的所有尝试都失败了。我得到的都是同样的错误 "Could not load SSL library"。这是程序:
procedure TfrmMain.DownloadPicture(const AURL: string);
var
MeS: TMemoryStream;
cidSSL: TIdSSLIOHandlerSocketOpenSSL;
cidHTTP: TIdHTTP;
begin
cidHTTP:= TIdHTTP.Create(nil);
cidSSL:= TIdSSLIOHandlerSocketOpenSSL.Create(nil);
Mes := TMemoryStream.Create;
try
cidHTTP.ReadTimeout := 30000;
cidHTTP.IOHandler := IdSSL;
cidSSL.SSLOptions.Method := sslvSSLv3;
cidSSL.SSLOptions.Mode := sslmUnassigned;
cidSSL.StartSSL;
cidHTTP.Get(AURL, Mes);
except
on E : Exception do
begin showmessage('Error: '+E.Message);
end;
end;
Mes.Position := 0;
frmImage.Image.Bitmap.LoadFromStream(Mes);
end;
可能您有一个新的 OpenSSL 库和一个旧的 Indy 版本。检查这个: Indy 10 - IdSMTP.Connect raising "Could not load SSL library."
有 32/64 位版本。 确保您拥有正确版本的文件。
请参阅 this FTP 了解正确的版本。
用于下载二进制文件的其他镜像 here。
如果您不是 使用 Android 6 Marshmallow,OpenSSL 应该可以在 Android 上正常工作。当您遇到“无法加载”错误时,您可以在 IdSSLOpenSSLHeaders
单元中调用 Indy 的 WhichFailedToLoad()
函数来找出无法加载 OpenSSL 的原因。如果您的设备没有预装 OpenSSL,您可以使用您的应用程序部署 OpenSSL 二进制文件,并使用 Indy 的 IdOpenSSLSetLibPath()
函数告诉 Indy 从哪里加载它们。
也就是说,从 Android 6 Marshmallow 开始,Google no longer supports OpenSSL on Android. It has been replaced with a custom fork named BoringSSL, which Indy does not fully support yet (although some BoringSSL-related changes have been made to Indy after Seattle's release). So, if you are having trouble with using Indy SSL/TLS on Android 6, you can try upgrading to the latest Github snapshot 看看是否有帮助。
BoringSSL 对 OpenSSL API 接口进行了一些主要 更改(删除函数、更改数据类型等),因此它不向后兼容现有的 OpenSSL代码。但更糟糕的是,BoringSSL 使用与 OpenSSL 相同的库文件名,并在设备启动时预加载,因此无法使用您的 Android 应用程序部署自定义构建的 OpenSSL 库二进制文件。当应用程序试图在运行时加载 OpenSSL 库文件名时,Android 将仅使用预加载的 BoringSSL 二进制文件(无论您是否调用 Indy 的 IdOpenSSLSetLibPath()
函数)。
Indy 在 Android 的 NDK 级别运行,而不是 Java 级别,因此要使 Indy 避免 BoringSSL 将要求用户:
使用与 BoringSSL 不冲突的新文件名重新编译 OpenSSL 库(据我所知,没有可用的已知版本),然后更新 Indy 以使用这些文件名。
将 OpenSSL 源代码直接编译到他们的 Android 应用程序中。 Indy 当前未设置为在 iOS 以外的任何平台上支持 OpenSSL 的静态 linking,但这应该是一个小改动,以更新 Indy 的
IdSSLOpenSSLHeaders_static
单元,如果有人可以在 Android 上为 OpenSSL 生成可行的.a
文件。我知道至少有一个用户尝试过这条路线,但该用户尚未成功(错误地使源代码完全 link 正确)。切换到 Android 更高级别的基于 Java 的加密 API。这是 Google 的首选解决方案。但 Indy 目前不支持它。这样做需要为 Android 套接字 I/O 和 SSL/TLS 编写一整套新的
TIdStack
和TIdIOHandler
类,使用 JNI 调用来访问Java APIs。但这有需要处理的性能和线程问题。
因此,目前没有已知可行的解决方法可以使 Indy SSL/TLS 在 Android 6+ 上运行。
更新:Embarcadero 论坛中的用户能够找到与 Indy 兼容并在 Android 上工作的 OpenSSL .so
文件 6:
https://forums.embarcadero.com/thread.jspa?threadID=211089
After many reports of my apps crashing if installed in Android 6 devices I've searched the net for some tips and the couple of needed .so compiled files, 1.02 version, added the two files to the play store deployment of my apps (assets\internal) and changed the Indy's path calling
IdOpenSSLSetLibPath(TPath.GetDocumentsPath)
in the OnCreate of my datamodule.
After those modifications of my code my Apps run perfectly on my brand new S7 with Android 6.0.1, and on all the other recent Android devices (tested using the Play Store deployment).
And now the Google warning pops up telling me that the OpsnSSL files deployed with my apps are not of the minimum required 1.02f version (or 1.01r).... and so my post in this forum.
...
Anyway you can download here the latest .so files, the ones that I deploy at this moment: https://drive.google.com/file/d/0B7AxqW32K0oXWW9nUk9qaFpHT0k/view?usp=sharing
同一讨论中的另一位用户似乎也取得了一些成功:
Ive been running on android 6 loading the .so libraries just fine for months. The new problem is we need to compile new versions of the openssl libraries. Cygwin is not working correctly to compile for me so im switching to a linux install to create them (if possible) https://wiki.openssl.org/index.php/Android#Build_the_OpenSSL_Library_2
heres a repository you can grab some current prebuilt ones https://github.com/emileb/OpenSSL-for-Android-Prebuilt.git
更新:以下(德语)论坛讨论为注册用户提供 Android(和 iOS 模拟器)的 OpenSSL 1.0.2g 二进制文件。他们不会在 Google Play 商店中显示安全警告:
http://www.delphipraxis.net/188736-kompilierte-openssl-bibliotheken-fuer-android.html
OpenSSL 1.0.2g iOS Simulator.zip
更新:OpenSSL 1.0.2g 的 Android 二进制文件现已在 Embarcadero 附件论坛中可用:
https://forums.embarcadero.com/thread.jspa?threadID=211147
然后,要加载 OpenSSL 而不是 BoringSSL,请按照以下步骤操作:
将 2 个
.so
文件添加到项目部署并将它们设置为部署到.\assets\internal\
文件夹将
System.StartupCopy
单元添加为 DPR 的uses
子句中的第一个单元。在应用程序启动时调用
IdOpenSSLSetLibPath(TPath.GetDocumentsPath)
。
更新:OpenSSL 1.0.1t 和 1.0.2h 二进制文件现在位于 Embarcadero 附件论坛中:
https://forums.embarcadero.com/thread.jspa?threadID=211147
更新:二进制文件现已发布在 Indy 的 Fulgan 镜像上:
更新:Indy 不再使用 Fulgan 镜像来托管 OpenSSL 二进制文件。他们现在在自己的 GitHub 仓库中:
https://www.indyproject.org/2020/06/16/openssl-binaries-moved-to-github/
只需将 TidHTTP 组件换成 TNetHTTPClient
我使用这段代码并且有效:
procedure TfPrecos.GetImageByUrl(URL: string);
var
Strm: TMemoryStream;
vIdHTTP: TIdHTTP;
cidSSL: TIdSSLIOHandlerSocketOpenSSL;
begin
IdOpenSSLSetLibPath(TPath.GetDocumentsPath); //libcrypto.so and libssl.so in ./assets/internal
vIdHTTP.IOHandler := cidSSL;
cidSSL.SSLOptions.Method := sslvSSLv23; // version 2.3
cidSSL.SSLOptions.Mode := sslmUnassigned;
cidSSL.StartSSL;
try
vIdHTTP.Get(URL, Strm);
if (Strm.Size > 0) then
begin
Strm.Position := 0;
try
Image1.Bitmap.LoadFromStream(Strm);
finally
end;
end;
finally
Strm.DisposeOf;
vIdHTTP.DisposeOf;
end;
end;