Вопрос или проблема
Надеюсь, название уже достаточно ясное, но чтобы объяснить лучше: у меня есть большой выбор опций на странице Выбор компонентов
(около 1.4 ГБ файлов .png), и моя цель – уменьшить размер сборки для установщика, заставив его загружать файлы в {tmp}
и устанавливать их после распаковки. К сожалению, у меня возникли некоторые проблемы при попытке следовать ответам на другие вопросы.
- Ссылка на скачивание моих файлов видна на странице загрузки, что меня невероятно беспокоит в отношении проблем с безопасностью.
- Все файлы загружаются независимо от того, какие компоненты выбрал пользователь, что приводит к большому количеству времени, потраченного на извлечение, к тому же, к сожалению, нет индикатора прогресса, чтобы дать обратную связь пользователю.
- Попытка отменить загрузку полностью замораживает установщик, требуя от пользователя использовать Диспетчер задач для выхода из установки.
———————————————————————————————————————————
В настоящее время весь [Code]
для моего установщика (извините, это много)
[Files]
// Тест
Source: "{tmp}\packs\Sapphic_icons\Dead by Daylight\DeadByDaylight\Content\UI\Icons\README.txt"; DestDir: "{app}"; Components: sapphic; Flags: ignoreversion recursesubdirs createallsubdirs external; Check: ExtractedFileNeedsInstallation
[Types]
Name: "sapphic"; Description: "Sapphic Pack";
Name: "custom"; Description: "Индивидуализированный"; Flags: iscustom;
[Components]
Name: "sapphic"; Description: "Sapphic Pack - В процессе*"; Types: custom sapphic;
[Code]
{ —————————— Логирование извлечения ———————————————————————————————————————— }
const
NO_PROGRESS_BOX = 4;
RESPOND_YES_TO_ALL = 16;
procedure UnZip(ZipPath, FileName, TargetPath: string);
var
Shell: Variant;
ZipFile: Variant;
Item: Variant;
TargetFolder: Variant;
begin
Shell := CreateOleObject('Shell.Application');
ZipFile := Shell.NameSpace(ZipPath);
if VarIsClear(ZipFile) then
RaiseException(Format('Не удается открыть ZIP-файл "%s" или он не существует', [ZipPath]));
Item := ZipFile.ParseName(FileName);
if VarIsClear(Item) then
RaiseException(Format('Не удается найти "%s" в ZIP-файле "%s"', [FileName, ZipPath]));
TargetFolder := Shell.NameSpace(TargetPath);
if VarIsClear(TargetFolder) then
RaiseException(Format('Целевой путь "%s" не существует', [TargetPath]));
TargetFolder.CopyHere(Item, NO_PROGRESS_BOX or RESPOND_YES_TO_ALL);
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Обработка извлечения ———————————————————————————————————————— }
function ExtractedFileNeedsInstallation: Boolean;
var
TargetPath: String;
begin
TargetPath := ExpandConstant('{userappdata}')+'\App\packs';
Result := not FileExists(TargetPath);
Log(Format('ExtractedFileNeedsInstallation: %d', [Result]));
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Прогресс загрузки ———————————————————————————————————————— }
var
DownloadPage: TDownloadWizardPage;
function OnDownloadProgress(const Url, FileName: String; const Progress, ProgressMax: Int64): Boolean;
begin
if Progress = ProgressMax then
Log(Format('Файл успешно загружен в {tmp}: %s', [FileName]));
Result := True;
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Мастер установки ———————————————————————————————————————— }
procedure InitializeWizard();
begin
{ Страница загрузки }
DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), @OnDownloadProgress);
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
{ —————————— Обработка загрузки ———————————————————————————————————————— }
function NextButtonClick(CurPageID: Integer): Boolean;
var
Temp: String;
begin
if CurPageID = wpReady then begin
if (not ExtractedFileNeedsInstallation) then
begin
Result := True;
end
else
begin
DownloadPage.Clear;
DownloadPage.Add('https://www.dropbox.com/scl/fi/fautmpacdsl22h6y41jrv/packs.zip?rlkey=ul3kl1f9o3258yguitprisx6c&st=wwry4esv&dl=1', 'packs.zip', '');
DownloadPage.Show;
try
try
DownloadPage.Download;
Temp := ExpandConstant('{tmp}');
UnZip(Temp+'\packs.zip', 'packs', Temp);
Result := True;
except
SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbCriticalError, MB_OK, IDOK);
Result := False;
end;
finally
DownloadPage.Hide;
end;
end;
end else
Result := True;
end; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
———————————————————————————————————————————
Ответ или решение
Для решения проблемы скачивания и извлечения специфических файлов, выбранных пользователем на странице выбора компонентов, необходимо внести ряд изменений и улучшений в предоставленный код вашего установщика. Это обеспечит безопасность, оптимизирует процесс скачивания и предоставит пользователю необходимую обратную связь. Рассмотрим ключевые шаги более детально.
1. Повышение уровня безопасности
Для устранения проблемы с видимостью ссылок на скачивание желательно использовать подход, при котором ссылка будет недоступна напрямую. Можно реализовать механизм генерации временных ссылок на сервере или использовать API для получения файла. В качестве альтернативы можно рассмотреть использование хеширования для проверки подлинности файлов.
2. Фильтрация скачиваемых файлов
Текущая реализация загружает все файлы, игнорируя выбор пользователя. Чтобы это исправить, необходимо создать логику, которая будет проверять выбранные компоненты и скачивать только соответствующие файлы.
Примерно это может выглядеть следующим образом:
function ComponentsToDownload: TStringList;
var
Components: TStringList;
begin
Components := TStringList.Create;
try
if IsComponentSelected('sapphic') then
Components.Add('sapphic_files.zip'); // Добавьте соответствующие файлы для скачивания
// Добавьте проверки для дополнительных компонентов
Result := Components;
finally
Components.Free;
end;
end;
// В функции NextButtonClick
var
FilesToDownload: TStringList;
begin
FilesToDownload := ComponentsToDownload;
try
for FileName in FilesToDownload do
begin
DownloadPage.Add('http://yourserver.com/' + FileName, FileName, '');
end;
...
finally
FilesToDownload.Free;
end;
3. Отображение прогресса загрузки
Для улучшения взаимодействия с пользователем добавьте прогресс-бар при загрузке файлов. Это можно реализовать через обновление пользовательского интерфейса на этапе загрузки.
4. Обработка отмены загрузки
Для предотвращения зависания установщика при попытке отмены загрузки следует реализовать специальный метод обработки прерывания загрузки. Например, добавьте кнопку "Отмена", которая прекращает выполнение потока загрузки и возвращает пользователя к предыдущему экрану.
5. Извлечение только нужных файлов
Для извлечения конкретных файлов из ZIP-архива в соответствии с выбором пользователя обновите процедуру UnZip
.
procedure UnZipSelective(ZipPath: string; TargetPath: string; FileNames: TStringList);
var
Shell: Variant;
ZipFile: Variant;
TargetFolder: Variant;
I: Integer;
begin
Shell := CreateOleObject('Shell.Application');
ZipFile := Shell.NameSpace(ZipPath);
if VarIsClear(ZipFile) then
RaiseException(Format('Cannot open ZIP file "%s"', [ZipPath]));
TargetFolder := Shell.NameSpace(TargetPath);
if VarIsClear(TargetFolder) then
RaiseException(Format('Target path "%s" does not exist', [TargetPath]));
for I := 0 to FileNames.Count - 1 do
begin
var Item := ZipFile.ParseName(FileNames[I]);
if not VarIsClear(Item) then
TargetFolder.CopyHere(Item, NO_PROGRESS_BOX or RESPOND_YES_TO_ALL);
end;
end;
Заключение
Следуя вышеизложенным рекомендациям, вы сможете улучшить функциональность вашего установщика, сделать процесс скачивания более безопасным и эффективным, обеспечивая пользователю лучший опыт. Не забывайте выполнять тестирование на каждом этапе, чтобы выявить возможные проблемы и улучшить взаимодействие с конечным пользователем.