需求:在unreal中实现下载功能,输入相关url网址,本地文件夹存入相应文件。
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HTTP" });
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "Interfaces/IHttpRequest.h"
#include "RuntimeFilesDownloaderLibrary.generated.h"
UENUM(BlueprintType, Category = "Runtime Files Downloader")
enum DownloadResult
{
SuccessDownloading UMETA(DisplayName = "Success"),
DownloadFailed UMETA(DisplayName = "Download failed"),
SaveFailed UMETA(DisplayName = "Save failed"),
DirectoryCreationFailed UMETA(DisplayName = "Directory creation failed")
};
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnFilesDownloaderProgress, const int32, BytesSent, const int32, BytesReceived, const int32, ContentLength);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnFilesDownloaderResult, TEnumAsByte < DownloadResult >, Result);
UCLASS()
class DOWNLOAD_API URuntimeFilesDownloaderLibrary : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable, Category = "Runtime Files Downloader")
FOnFilesDownloaderProgress OnProgress;
UPROPERTY(BlueprintAssignable, Category = "Runtime Files Downloader")
FOnFilesDownloaderResult OnResult;
UPROPERTY(BlueprintReadOnly, Category = "Runtime Files Downloader")
FString FileURL;
UPROPERTY(BlueprintReadOnly, Category = "Runtime Files Downloader")
FString FileSavePath;
UFUNCTION(BlueprintCallable, Category = "Runtime Files Downloader")
static URuntimeFilesDownloaderLibrary* CreateDownloader();
UFUNCTION(BlueprintCallable, Category = "Runtime Files Downloader")
bool DownloadFile(const FString& URL, const FString& SavePath, float TimeOut = 5);
private:
void OnProgress_Internal(FHttpRequestPtr Request, int32 BytesSent, int32 BytesReceived);
void OnReady_Internal(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
};
#include "RuntimeFilesDownloaderLibrary.h"
#include "HttpModule.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
//创建了一个URuntimeFilesDownloaderLibrary对象,并将其添加到根对象,防止系统自动回收
URuntimeFilesDownloaderLibrary* URuntimeFilesDownloaderLibrary::CreateDownloader()
{
URuntimeFilesDownloaderLibrary* Downloader = NewObject<URuntimeFilesDownloaderLibrary>();
Downloader->AddToRoot();
return Downloader;
}
bool URuntimeFilesDownloaderLibrary::DownloadFile(const FString& URL, const FString& SavePath, float TimeOut)
{
if (URL.IsEmpty() || SavePath.IsEmpty() || TimeOut <= 0)
{
return false;
}
FileURL = URL;
FileSavePath = SavePath;
/*ue4.27旧版本弃用下列方法*/
/*TSharedRef HttpRequest = FHttpModule::Get().CreateRequest();*/
//4.27及以后使用如下方法
TSharedPtr<IHttpRequest, ESPMode::ThreadSafe> HttpRequest = FHttpModule::Get().CreateRequest();
HttpRequest->SetVerb("GET");
HttpRequest->SetURL(FileURL);
//HttpRequest->SetTimeout(TimeOut);
//监听事件OnProcessRequestComplete绑定OnReady_Internal,OnRequestProgress绑定OnProgress_Internal
HttpRequest->OnProcessRequestComplete().BindUObject(this, &URuntimeFilesDownloaderLibrary::OnReady_Internal);
HttpRequest->OnRequestProgress().BindUObject(this, &URuntimeFilesDownloaderLibrary::OnProgress_Internal);
// Process the request
HttpRequest->ProcessRequest();
return true;
}
//监听事件
void URuntimeFilesDownloaderLibrary::OnProgress_Internal(FHttpRequestPtr Request, int32 BytesSent, int32 BytesReceived)
{
const FHttpResponsePtr Response = Request->GetResponse();
if (Response.IsValid())
{
const int32 FullSize = Response->GetContentLength();
OnProgress.Broadcast(BytesSent, BytesReceived, FullSize);
}
}
void URuntimeFilesDownloaderLibrary::OnReady_Internal(FHttpRequestPtr Request, FHttpResponsePtr Response,
bool bWasSuccessful)
{
RemoveFromRoot();
Request->OnProcessRequestComplete().Unbind();
if (Response.IsValid() && EHttpResponseCodes::IsOk(Response->GetResponseCode()) && bWasSuccessful)
{
//
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
//
FString Path, Filename, Extension;
FPaths::Split(FileSavePath, Path, Filename, Extension);
//查看文件夹,没有则创建文件
if (!PlatformFile.DirectoryExists(*Path))
{
if (!PlatformFile.CreateDirectoryTree(*Path))
{
OnResult.Broadcast(DirectoryCreationFailed);
return;
}
}
// 开启文件写入
//通过PlatformFile.OpenWrite()函数打开文件句柄,以便将下载的数据写入文件中。函数的参数是一个TCHAR类型的字符串,表示文件的路径和文件名。
//然后,检查句柄是否成功打开。如果句柄成功打开,就将HTTP请求响应中的数据通过FileHandle->Write()函数写入到文件中。
IFileHandle* FileHandle = PlatformFile.OpenWrite(*FileSavePath);
if (FileHandle)
{
//
FileHandle->Write(Response->GetContent().GetData(), Response->GetContentLength());
//
delete FileHandle;
OnResult.Broadcast(SuccessDownloading);
}
else
{
OnResult.Broadcast(SaveFailed);
}
}
else
{
OnResult.Broadcast(DownloadFailed);
}
}
该蓝图在关卡中调用,通过Event Begin Play事件监听行为,当按下
按钮,创建DOWNLOADER对象,并执行下载功能,下载时对下载行为进行监听,包括RESULT(Success,Download failed,Save failed,Directory creation failed四种下载结果)和以下三个数据信息:
· BytesSent 表示已发送的字节数,指示已经发送到服务器的字节数。
· BytesReceived 表示已接收的字节数,指示已从服务器接收到的字节数。
· FullSize 表示完整内容的长度,指示需要下载的文件的总字节数。
最后通过BytesReceived/FullSize计算出百分号数据,实现下载进度实时追踪,下载完成后RESULT枚举信息输出。