You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在FireMonkey移动应用运行时捕获可读异常堆栈跟踪?

FireMonkey移动应用(Android/iOS)捕获可读异常堆栈的方案

针对Delphi 11.3(Alexandria)和12.1(Athens)的FireMonkey移动应用,以下是几种捕获可读异常堆栈的实用方案,替代Windows平台的jclDebug、madEcept等工具:

一、用Delphi内置能力直接获取

从Delphi 10.3开始,FireMonkey移动平台已经支持直接读取异常的堆栈信息,关键是要正确设置编译选项:

  • 开启调试信息:在项目选项的「Compiler」→「Linking」里,勾选「Include debug information」;Android额外开启「Generate stack frames」,iOS在「iOS Build」中开启「Debug information」。
  • 直接调用Exception.StackTrace属性:捕获异常时,直接读取这个属性就能拿到Delphi层面的堆栈。注意Release版本会因编译器优化丢失部分信息,建议要么开调试信息的Release包,要么用Debug版本排查问题。
  • 线程堆栈补充:如果需要获取当前线程的堆栈(非异常场景),可以用TThread.CurrentThread.StackTrace。

二、第三方成熟工具(开箱即用)

这些工具和Windows平台的体验一致,配置简单:

  • EurekaLog:支持Android/iOS,安装对应Delphi版本的插件后,在项目选项里启用它,就能自动捕获全局异常,生成带详细堆栈、线程信息、系统环境的报告,还能把报告存本地或传服务器。
  • madExcept:同样支持移动平台,配置后会自动生成符号解析后的堆栈,还能自定义报告格式和输出方式,适合需要深度定制的场景。

三、手动实现跨平台堆栈捕获(无依赖)

如果不想用第三方工具,可以自己写代码获取原生平台的堆栈:

Android平台

利用JNI获取Java层的堆栈:

uses Androidapi.JNI.JavaTypes, Androidapi.Helpers;

function GetAndroidNativeStackTrace(E: Exception): string;
var
  JEx: JThrowable;
  StackElements: TJavaObjectArray<JStackTraceElement>;
  I: Integer;
begin
  Result := '';
  if E is EJNIException then
  begin
    JEx := EJNIException(E).JNIException;
    StackElements := JEx.getStackTrace;
    for I := 0 to StackElements.Length - 1 do
      Result := Result + StackElements.Items[I].toString + sLineBreak;
  end;
end;

iOS平台

通过ObjC的backtrace函数获取原生堆栈:

uses Objcapi, Macapi.ObjectiveC, Macapi.Foundation;

function GetiOSNativeStackTrace: string;
var
  FrameCount: Integer;
  CallStack: Pointer;
  StackSymbols: PPAnsiChar;
  I: Integer;
begin
  Result := '';
  FrameCount := backtrace(nil, 0);
  CallStack := malloc(FrameCount * SizeOf(Pointer));
  try
    FrameCount := backtrace(CallStack, FrameCount);
    StackSymbols := backtrace_symbols(CallStack, FrameCount);
    if Assigned(StackSymbols) then
    begin
      for I := 0 to FrameCount - 1 do
        Result := Result + StackSymbols[I] + sLineBreak;
      free(StackSymbols);
    end;
  finally
    free(CallStack);
  end;
end;

符号解析(Release版本必备)

Release版本的堆栈是内存地址,需要用Delphi自带工具解析:

  • iOS:用dsymutil工具结合编译生成的.dSYM文件,把地址转换成代码行。
  • Android:用addr2line工具(Android NDK自带),配合.map文件解析地址。

四、全局异常捕获配置

不管用哪种方案,建议注册全局异常处理,避免应用直接崩溃并保存日志:

procedure GlobalExceptionHandler(Sender: TObject; E: Exception);
var
  FullStackTrace: string;
begin
  // 先获取Delphi层面的堆栈
  FullStackTrace := E.StackTrace;
  // 补充原生平台堆栈
  {$IFDEF ANDROID}
  FullStackTrace := FullStackTrace + sLineBreak + 'Android Native Stack:' + sLineBreak + GetAndroidNativeStackTrace(E);
  {$ENDIF}
  {$IFDEF IOS}
  FullStackTrace := FullStackTrace + sLineBreak + 'iOS Native Stack:' + sLineBreak + GetiOSNativeStackTrace;
  {$ENDIF}
  // 保存到本地文件或上传服务器
  // 示例:SaveLogToFile是自定义的日志保存函数
  SaveLogToFile('CrashLog_' + FormatDateTime('yyyyMMdd_hhmmss', Now) + '.txt', 
    Format('Exception: %s'#13#10'Message: %s'#13#10'Stack Trace:'#13#10'%s', 
    [E.ClassName, E.Message, FullStackTrace]));
end;

initialization
  Application.OnException := GlobalExceptionHandler;

内容的提问来源于stack exchange,提问作者AlexLL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 00:27:13