4

I am playing with an application for IOS and Android using Delphi XE5 and Firemonkey. While on IOS the application works fine it fails to start on Android. The reason is that on the startup phase it fails in the System.StartUpCopy.pas unit.

I have some files I deploy with the application (multimedia content and XML). While all of them are copied ok on IOS, some of them fail on Android. The deploy configuration is done with deployment manager in Delphi.

  • The following is ok: assets/internal/profiles/default.xml
  • But this one fails: assets/internal/media/images/concert/object4.png

It fails inside "System.StartUpCopy" on the line 97 where this code is running

ReadCount := AAsset_read(LAssetFile, @Buffer[0], MAX_BUFF_LEN);

But the problem is a little bit higher where it gets the "LAssetFile"

LAssetFile := AAssetManager_open(LAssetManager, M.AsUtf8(OrigFileName).ToPointer, AASSET_MODE_BUFFER);

"AAssetManager_open" returns nil. Why I do not know, as I do not know how to get some error code from the API. The whole block of code looks like this

function CopyAssetToFile(LAssetManager: PAAssetManager; const AssetFolder, AssetName: string;
              const DestinationRoot, DestFolder, FileName: string): Boolean;
var
  OrigFileName,
  DestFileName,
  DestinationPath: string;
  ReadCount, WriteCount: Integer;
  LAssetFile: PAAsset;
  FileHandle: THandle;
  Buffer: TBytes;
  M: TMarshaller;
begin
  Result := True;

  if AssetFolder = '' then
    OrigFileName := AssetName
  else
    OrigFileName := IncludeTrailingPathDelimiter(AssetFolder) +  AssetName;

  if DestFolder <> '' then
  begin
    DestinationPath := IncludeTrailingPathDelimiter(DestinationRoot) + DestFolder;
    DestFileName := IncludeTrailingPathDelimiter(DestinationRoot) + IncludeTrailingPathDelimiter(DestFolder) + FileName;
  end
  else
  begin
    DestinationPath := DestinationRoot;
    DestFileName := IncludeTrailingPathDelimiter(DestinationRoot) + FileName
  end;

  if not FileExists(DestFileName) then //do not overwrite files
  begin
    // Second Create an intermediate buffer.
    SetLength(Buffer, MAX_BUFF_LEN);
    LAssetFile := nil;
    try
      if not DirectoryExists(DestinationPath) then
      begin
        if not ForceDirectories(DestinationPath) then
        begin
          Exit(False);
        end;
      end;
      // We have a valid AssetManager. Start
      LAssetFile := AAssetManager_open(LAssetManager, M.AsUtf8(OrigFileName).ToPointer, AASSET_MODE_BUFFER);
      FileHandle := FileCreate(DestFileName);
      try
        if FileHandle = THandle(-1) then
        begin
          Exit(False);
        end;
        repeat
          ReadCount := AAsset_read(LAssetFile, @Buffer[0], MAX_BUFF_LEN);
          WriteCount := FileWrite(FileHandle, Buffer, 0, ReadCount);
        until (ReadCount <= 0) or (ReadCount <> WriteCount);

      finally
        FileClose(FileHandle);
      end;
    finally
      if (LAssetFile <> nil) then
        AAsset_close(LAssetFile);
      SetLength(Buffer, 0);
    end;
  end;
end;

This is original XE5 code. Now the only difference I see between the file that is ok and the file that failed is the directory depth. The first has only one level depth eg. one dir and the other has 3 levels of depth. I have some other files that also copy OK and all have only one level of directory depth.

Anyone knows what could be wrong here. I can't debug further as I already went as deep as I could.

If it helps I am testing on actual device, Samsung Galaxy Nexus.

EDIT:

Found out that if I change:

assets/internal/media/images/concert/object4.png

to

assets/internal/media/images/concert/object.png

Then it works. WTF. Any explanations? I looked and numbers are supposed to be valid characters for android and assets file names

Runner
  • 6,073
  • 26
  • 38

0 Answers0