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