Table of Contents

TMS FNC App Update — Guides

Control file and remote version

The component reads a remote control file referenced by URL. The file contains the new version string and a list of files to download. AppInfo exposes the parsed metadata (what's new text, EULA, update message, and the informational URL) after a successful check.

Checking and applying updates

Call NewVersionAvailable to download the control file and compare it against the local installation, then call StartUpdate to download and apply the payload. DoUpdate combines the two and shows the configured confirmation message first.

What the check found

An update can be detected in three independent ways — a newer version string, a newer file version, or a differing checksum — and PendingNewVersion, PendingNewFileVersion, and PendingNewChecksum report which one fired. They are filled in by NewVersionAvailable, so read them only after that call returned True; the two string properties stay empty and PendingNewChecksum stays -1 for a comparison that did not detect anything. That makes them the right values to show the user, and to record in a log, before starting the update.

uses
  FMX.TMSFNCAppUpdate;

procedure TForm1.CheckForUpdateButtonClick(Sender: TObject);
begin
  AppUpdate1.URL := 'https://downloads.example.com/myapp/update.inf';

  if not AppUpdate1.NewVersionAvailable then
  begin
    ShowMessage('You are running the latest version.');
    Exit;
  end;

  // The three Pending properties report which comparison detected the update
  // during the most recent NewVersionAvailable call, so read them only after
  // that call returned True. Each stays at its empty value when the update was
  // not found through that particular comparison.
  if AppUpdate1.PendingNewVersion <> '' then
    Memo1.Lines.Add('New application version: ' + AppUpdate1.PendingNewVersion);

  if AppUpdate1.PendingNewFileVersion <> '' then
    Memo1.Lines.Add('New file version: ' + AppUpdate1.PendingNewFileVersion);

  // PendingNewChecksum is -1 when no checksum difference was detected.
  if AppUpdate1.PendingNewChecksum <> -1 then
    Memo1.Lines.Add('New checksum: ' + IntToStr(AppUpdate1.PendingNewChecksum));

  AppUpdate1.StartUpdate;
end;

Elevation for system-level installs

Elevate controls whether the update runs with administrative rights when the files have to be written to a protected location; it defaults to True. On Windows the component spawns an elevated helper process automatically.

Custom version comparison

Handle OnVersionComparison to override the default version-string comparison with your own logic. The handler receives the local version and the remote one and decides, through AIsNewVersion, whether the remote version counts as an update.

uses
  FMX.TMSFNCAppUpdate;

procedure TForm1.FormCreate(Sender: TObject);
begin
  AppUpdate1.OnVersionComparison := AppUpdate1VersionComparison;
end;

procedure TForm1.AppUpdate1VersionComparison(Sender: TObject;
  AOldVersion: string; ANewVersion: string; var AIsNewVersion: Boolean);
begin
  // AOldVersion is the locally installed version, ANewVersion the one read
  // from the control file. Set AIsNewVersion to decide whether the remote
  // version counts as an update.
  AIsNewVersion := CompareSemanticVersions(ANewVersion, AOldVersion) > 0;
end;

Logging

Set Logging.Enabled and Logging.Filename to have the component write a detailed update log. Log writes your own message into that same file, so application context — who started the check, what was decided, why a restart was postponed — lands in the same chronological record as the component's own entries. Enable logging first: Log has no file to write to otherwise.

uses
  FMX.TMSFNCAppUpdate;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Log appends to the file the component itself writes to, so enable logging
  // and point it at a file first - without that there is nothing to write to.
  AppUpdate1.Logging.Enabled := True;
  AppUpdate1.Logging.Filename := ChangeFileExt(ParamStr(0), '.update.log');

  AppUpdate1.OnFileDownloaded := AppUpdate1FileDownloaded;
  AppUpdate1.OnAppRestart := AppUpdate1AppRestart;
end;

procedure TForm1.CheckForUpdateButtonClick(Sender: TObject);
begin
  AppUpdate1.Log('Update check started');
  if AppUpdate1.NewVersionAvailable then
    AppUpdate1.Log('Update found: ' + AppUpdate1.PendingNewVersion)
  else
    AppUpdate1.Log('No update available');
end;

procedure TForm1.AppUpdate1FileDownloaded(Sender: TObject;
  FileItem: TTMSFNCAppUpdateFile; StatusCode: Integer);
begin
  // Interleaving your own entries with the component's own lines keeps the
  // sequence readable when a failed update has to be diagnosed after the fact.
  AppUpdate1.Log(Format('Downloaded %s (status %d)', [FileItem.URL, StatusCode]));
end;

procedure TForm1.AppUpdate1AppRestart(Sender: TObject; var Allow: Boolean);
begin
  { FHasUnsavedWork is your own flag for pending user changes. }
  Allow := not FHasUnsavedWork;
  if not Allow then
    AppUpdate1.Log('Restart postponed: unsaved changes');
end;

See also