XE6发布文件
在Deployment Manager中添加待发布的文件,Remote Path写入assets\internal\或
assets\就可以
其中assets\internal\会把文件发布到
TPath.GetDocumentsPath(也就是/data/data/.../files)目录下assets\会把文件发布到
TPath.GetSharedDocumentsPath(也就是/mnt/sdcard/Android/data/.../files)目录下
另外修改了System.StartUpCopy单元,支持设置assets\sdcard\xxx 会把文件发布到/mnt/sdcard/xxx目录下
{ ******************************************************* }
{ }
{ CodeGear Delphi Runtime Library }
{ Copyright(c) 2013-2014 Embarcadero Technologies, Inc. }
{ }
{ ******************************************************* }
///使用说明
///在Deployment Manager中,设置assets\internal\,文件将会发布到TPath.GetDocumentsPath(也就是/data/data/.../files)
///设置assets\会把文件发布到TPath.GetSharedDocumentsPath(也就是/mnt/sdcard/Android/data/.../files)目录下
///设置assets\sdcard\xxx 会把文件发布到/mnt/sdcard/xxx目录下
{$HPPEMIT LINKUNIT}
unit System.StartUpCopy;
interface
uses
System.SysUtils;
type
EStartUpCopyException = class(Exception);
implementation
uses
{$IFDEF ANDROID}
Androidapi.AssetManager,
Androidapi.NativeActivity,
Androidapi.IOUtils,
Posix.Unistd,
System.RTLConsts,
Androidapi.ExternalSDCardPath,
{$ENDIF ANDROID}
{$IFDEF IOS}
iOSapi.Foundation,
{$ENDIF}
System.IOUtils;
{$IFDEF ANDROID}
type
TASSETS_TYPE = (atExternal, atInternal, atSDCard);
const
MAX_BUFF_LEN = 65536;
ASSETS_ROOT = ‘assets‘;
ASSETS_ROOT_D = ‘assets‘ + PathDelim;
ASSETS_ROOT_D_LENGTH = Length(ASSETS_ROOT_D);
ASSETS_INTERNAL = ‘internal‘;
ASSETS_INTERNAL_D = ‘internal‘ + PathDelim;
ASSETS_DEPLOY_DIR = ‘deployinfo‘;
ASSETS_FILENAME = ‘deployedassets.txt‘;
ASSETS_FILENAME_PATH = ASSETS_DEPLOY_DIR + PathDelim + ASSETS_FILENAME;
ASSETS_SDCard = ‘sdcard‘;
ASSETS_SDCard_D = ‘sdcard‘ + PathDelim;
ASSETS_SDCard_D_LENGTH = Length(ASSETS_SDCard_D);
{$ENDIF ANDROID}
{$IFDEF ANDROID}
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);
if LAssetFile <> nil then
begin
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;
end
else
raise EStartUpCopyException.CreateFmt(SAssetFileNotFound, [OrigFileName]);
finally
if (LAssetFile <> nil) then
AAsset_close(LAssetFile);
SetLength(Buffer, 0);
end;
end;
end;
function ReadAssetsDeployFile(AssetManager: PAAssetManager;
var FileContent: string): Boolean;
var
Buffer: array [0 .. MAX_BUFF_LEN - 1] of char;
LAssetFile: PAAsset;
ReadCount: Integer;
M: TMarshaller;
begin
Result := False;
LAssetFile := AAssetManager_open(AssetManager, M.AsUtf8(ASSETS_FILENAME_PATH).ToPointer,
AASSET_MODE_BUFFER);
if Assigned(LAssetFile) then
begin
try
repeat
ReadCount := AAsset_read(LAssetFile, @Buffer, MAX_BUFF_LEN);
if ReadCount > 0 then
FileContent := FileContent + UTF8Tostring(@Buffer);
until (ReadCount <= 0);
Result := True;
finally
AAsset_close(LAssetFile);
end;
end;
end;
procedure CopyAssetsToFiles;
var
AssetManager: PAAssetManager;
RootDir: string;
InternalPath: string;
ExternalPath: string;
SDCardPath: String;
{$REGION ‘CopyAssetFolder‘}
procedure CopyAssetFolder(const LAssetManager: PAAssetManager;
const FromFolder, ToFolder: string; IsInternal: TASSETS_TYPE = atExternal);
var
LAssetDir: PAAssetDir;
LFile: MarshaledAString;
FileName: string;
M: TMarshaller;
begin
// Listing the files on root directory
LAssetDir := AAssetManager_openDir(LAssetManager, M.AsUtf8(FromFolder).ToPointer);
if LAssetDir <> nil then
begin
try
LFile := AAssetDir_getNextFileName(LAssetDir);
while LFile <> nil do
begin
FileName := UTF8Tostring(LFile);
case IsInternal of
atInternal:
begin
CopyAssetToFile(LAssetManager, FromFolder, FileName, InternalPath,
ToFolder, FileName);
end;
atSDCard:
begin
if SDCardPath = ‘‘ then
raise EStartUpCopyException.Create(SExternalExtorageNotAvailable);
CopyAssetToFile(LAssetManager, FromFolder, FileName, SDCardPath, ToFolder,
FileName);
end;
else
begin
if ExternalPath = ‘‘ then
raise EStartUpCopyException.Create(SExternalExtorageNotAvailable);
CopyAssetToFile(LAssetManager, FromFolder, FileName, ExternalPath, ToFolder,
FileName);
end;
end;
LFile := AAssetDir_getNextFileName(LAssetDir);
end;
finally
AAssetDir_close(LAssetDir);
end;
end;
end;
{$ENDREGION}
{$REGION ‘CopyAssetFile‘}
procedure CopyAssetFile(const LAssetManager: PAAssetManager;
const FromFile, ToFile: string; IsInternal: TASSETS_TYPE = atExternal);
var
FileName: string;
FromFolder: string;
ToFolder: string;
begin
FromFolder := ExtractFilePath(FromFile);
ToFolder := ExtractFilePath(ToFile);
FileName := ExtractFilename(FromFile);
case IsInternal of
atInternal:
begin
CopyAssetToFile(LAssetManager, FromFolder, FileName, InternalPath,
ToFolder, FileName)
end;
atSDCard:
begin
if SDCardPath = ‘‘ then
raise EStartUpCopyException.Create(SExternalExtorageNotAvailable);
CopyAssetToFile(LAssetManager, FromFolder, FileName, SDCardPath, ToFolder,
FileName);
end;
else
begin
if ExternalPath = ‘‘ then
raise EStartUpCopyException.Create(SExternalExtorageNotAvailable);
CopyAssetToFile(LAssetManager, FromFolder, FileName, ExternalPath, ToFolder,
FileName);
end;
end;
end;
{$ENDREGION}
{$REGION ‘ProcessDeployedFiles‘}
procedure ProcessDeployedFiles(const LAssetManager: PAAssetManager; LFilesStr: string);
var
I: Integer;
FileName: string;
AFiles: TArray<string>;
begin
AFiles := LFilesStr.Split([string(#13#10)], ExcludeEmpty);
for I := Low(AFiles) to High(AFiles) do
begin
FileName := AFiles[I].Replace(‘\‘, ‘/‘).Replace(‘./‘, ‘‘);
if FileName.StartsWith(ASSETS_ROOT_D) then
begin
FileName := FileName.Substring(ASSETS_ROOT_D_LENGTH);
if FileName.StartsWith(ASSETS_INTERNAL_D) then
begin
CopyAssetFile(AssetManager, FileName,
FileName.Substring(Length(ASSETS_INTERNAL_D)), atInternal);
end
else if FileName.StartsWith(ASSETS_SDCard) then
begin
CopyAssetFile(AssetManager, FileName,
FileName.Substring(ASSETS_SDCard_D_LENGTH), atSDCard);
end
else
begin
CopyAssetFile(AssetManager, FileName, FileName, atExternal);
end;
end;
end;
end;
{$ENDREGION}
var
DeployedFiles: string;
begin
InternalPath := GetFilesDir;
ExternalPath := GetExternalFilesDir;
SDCardPath := GetExternalSDCardPath();
AssetManager := ANativeActivity(System.DelphiActivity^).AssetManager;
if (AssetManager <> nil) then
begin
if ReadAssetsDeployFile(AssetManager, DeployedFiles) then
ProcessDeployedFiles(AssetManager, DeployedFiles)
else
begin
RootDir := ‘‘;
CopyAssetFolder(AssetManager, RootDir, RootDir, atExternal);
RootDir := ASSETS_INTERNAL;
CopyAssetFolder(AssetManager, RootDir, ‘‘, atInternal);
RootDir := ‘StartUp‘;
CopyAssetFolder(AssetManager, RootDir, RootDir, atExternal);
RootDir := ASSETS_SDCard;
CopyAssetFolder(AssetManager, RootDir, RootDir, atSDCard);
end;
end;
end;
procedure CopyStartUpFiles;
begin
CopyAssetsToFiles;
end;
{$ELSE !ANDROID}
procedure CopyStartUpFiles;
var
Source, Destination: string;
procedure DoCopyFiles(const Src: string; const Dst: string);
var
SearchRec: TSearchRec;
Res: Integer;
begin
Res := FindFirst(Src + ‘*‘, faAnyFile, SearchRec);
while Res = 0 do
begin
if (SearchRec.Attr and faDirectory) = faDirectory then
begin
if (SearchRec.Name <> ‘.‘) and (SearchRec.Name <> ‘..‘) then
begin
if ForceDirectories(Dst + SearchRec.Name) then
// Do the recurse thing...
DoCopyFiles(Src + SearchRec.Name + PathDelim,
Dst + SearchRec.Name + PathDelim);
end;
end
else
begin
if not FileExists(Dst + SearchRec.Name) then
begin
TFile.Copy(Src + SearchRec.Name, Dst + SearchRec.Name, False);
// copy without overwriting.
end
end;
Res := FindNext(SearchRec);
end;
end;
{$IFDEF IOS}
var
Bundle: NSBundle;
{$ENDIF}
begin
{$IFDEF IOS}
Bundle := TNSBundle.Wrap(TNSBundle.OCClass.mainBundle);
Source := UTF8Tostring(Bundle.bundlePath.UTF8String) + PathDelim + ‘StartUp‘ +
PathDelim;
{$ELSE}
Source := ExtractFilePath(ParamStr(0)) + ‘StartUp‘ + PathDelim;
{$ENDIF}
if DirectoryExists(Source) then
begin
Destination := GetHomePath + PathDelim;
DoCopyFiles(Source, Destination);
end;
end;
{$ENDIF ANDROID}
initialization
begin
CopyStartUpFiles;
end;
end.