android - 在Android上使用TidHTTP时出现 "Could not load SSL library"错误

标签 android delphi ssl indy

我正在尝试使用TIdHTTP下载文件。在Delphi Seattle中获取。这是一个适用于Android的应用程序,我所有的尝试都失败了。我所得到的都是相同的错误“无法加载SSL库”。步骤如下:

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;

最佳答案

如果您未使用Android 6棉花糖,则OpenSSL在Android上应该可以正常工作。当您收到“无法加载”错误时,可以在WhichFailedToLoad()单元中调用Indy的IdSSLOpenSSLHeaders函数,以找出无法加载OpenSSL的原因。如果您的设备未预装OpenSSL,则可以在应用程序中部署OpenSSL二进制文件,并使用Indy的IdOpenSSLSetLibPath()函数告诉Indy从何处加载它们。

就是说,从Android 6 Marshmallow开始,Android上为Google no longer supports OpenSSL。它已被一个名为BoringSSL的自定义派生类替换为Indy does not fully support yet(尽管在Seattle发布后对Indy进行了一些与BoringSSL相关的更改)。因此,如果您在Android 6上使用Indy SSL/TLS遇到麻烦,则可以尝试升级到最新的SVN snapshot以查看是否有帮助(在撰写本文时,当前的SVN修订版为5359)。

BoringSSL对OpenSSL API接口(interface)进行了一些重大更改(删除函数,更改数据类型等),因此它与现有的OpenSSL代码不向后兼容。但更糟糕的是,BoringSSL使用与OpenSSL相同的库文件名,并在设备启动时预加载,因此无法在您的Android应用程序中部署自定义的OpenSSL库二进制文件。当应用尝试在运行时加载OpenSSL库文件名时,Android将仅使用预加载的BoringSSL二进制文件(无论您是否调用Indy的IdOpenSSLSetLibPath()函数)。

Indy在Android的NDK级别(而不是Java级别)上运行,因此要使Indy避免使用BoringSSL,将需要用户执行以下任一操作:

  • 用与BoringSSL不冲突的新文件名重新编译OpenSSL库(AFAIK没有可用的已知版本),然后更新Indy以使用这些文件名。
  • 将OpenSSL源代码直接编译到其Android应用中。 Indy当前未设置为在iOS以外的任何平台上都不支持OpenSSL的静态链接,但是如果有人可以在Android上为OpenSSL生成可行的IdSSLOpenSSLHeaders_static文件,则这应该是对Indy的.a单元进行相关定义的微小更改。我确实知道至少有一个用户尝试此路由,但是该用户尚未成功(获取源代码以正确完全链接时出错)。
  • 切换到Android的基于Java的更高级别的加密API。这是Google的首选解决方案。但是Indy目前不支持它。这样做将需要使用JNI调用来访问Java API,从而为Android套接字I/O和SSL/TLS编写一套全新的TIdStackTIdIOHandler类。但这存在性能和线程问题,需要解决。

  • 因此,目前尚没有已知可行的解决方法来使Indy SSL/TLS在Android 6+上运行。

    更新:Embarcadero论坛中的用户能够找到与Indy兼容并可以在Android 6上使用的OpenSSL .so文件:

    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 Android.zip

    OpenSSL 1.0.2g iOS Simulator.zip

    更新:现在可在Embarcadero附件论坛中获得适用于OpenSSL 1.0.2g的Android二进制文件:

    https://forums.embarcadero.com/thread.jspa?threadID=211147

    然后,要加载OpenSSL而不是BoringSSL,请按照以下步骤操作:
  • 将2个.so文件添加到您的项目部署中,并将它们设置为部署到.\assets\internal\文件夹
  • System.StartupCopy单元添加为DPR的uses子句中的第一个单元。
  • 在应用启动时调用IdOpenSSLSetLibPath(TPath.GetDocumentsPath)


  • 更新:Embarcadero附件论坛中现已提供OpenSSL 1.0.1t和1.0.2h二进制文件:

    https://forums.embarcadero.com/thread.jspa?threadID=211147

    更新:这些二进制文件现已发布在Indy的Fulgan镜子上:

    http://indy.fulgan.com/SSL/

    关于android - 在Android上使用TidHTTP时出现 "Could not load SSL library"错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37105600/

    相关文章:

    android - android 中 oauth 后的 Twitter 用户屏幕名称

    android - 没有网络连接

    java - Android 检查服务器是否响应 "is"JSON

    .htaccess - 将域重定向到另一个域,包括文件夹结构(如果可能,使用 SSL)

    android - 可以在 XML 布局中访问首选项吗?

    delphi - 保存 VirtualStringTree 节点数据

    delphi - "Access Denied"在 Windows 服务程序中的 Mailslot 上写入

    delphi - 如何在放置组件时显示“"Edit Component' s Name”窗口?

    android - 在 Android 中使用 TLS 并禁用 SSL

    javascript - 谷歌标签管理器给出混合内容错误