Unreal Engine HTTP リクエスト / レスポンス処理 (JSON デシリアライズ)
Unreal Engine で HTTP リクエストする方法
モジュールを追加
- プロジェクトに HTTP , Json モジュールを追加する
- /Games/<プロジェクト名>/Source/<プロジェクト名>/<プロジェクト名>.Build.cs
- PublicDependencyModuleNames.AddRange()
- “HTTP” , “Json” を追加
HTTP リクエストするクラスを作成
クラスを追加する
- Content Browser > C++ Classes > 右クリック
- New C++ Class…
- None 選択 > Next 押下
- Name を HttpRequest に設定 > Create Class 押下
HttpRequest を実装する
// HttpRequest.h // Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "http.h" class HTTPREQUESTSAMPLE_API HttpRequest { public: HttpRequest(); ~HttpRequest(); void OnRequest(const FString Url, const FString Verb); private: static void OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool ConnectionSuccessfully); };
// Fill out your copyright notice in the Description page of Project Settings. #include "HttpRequest.h" HttpRequest::HttpRequest() { } HttpRequest::~HttpRequest() { } void HttpRequest::OnRequest(const FString Url, const FString Verb) { // HTTP リクエストオブジェクト作成 const FHttpRequestRef Request = FHttpModule::Get().CreateRequest(); // HTTP リクエスト完了時に実行する関数ポインタをリセット Request->OnProcessRequestComplete().BindStatic(&HttpRequest::OnResponseReceived); // HTTP リクエストの URL を設定 Request->SetURL(Url); // HTTP リクエストのメソッドを設定 Request->SetVerb(Verb); // HTTP リクエスト Request->ProcessRequest(); } void HttpRequest::OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool ConnectionSuccessfully) { // レスポンスコードのチェック if (EHttpResponseCodes::IsOk(Response->GetResponseCode())) { // JSON オブジェクト格納用変数の初期化 TSharedPtr<FJsonObject> ResponseObj = MakeShareable(new FJsonObject()); // 文字列から JSON を読み込むための Reader 初期化 TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString()); // 文字列から JSON オブジェクト if (FJsonSerializer::Deserialize(Reader, ResponseObj)) { // UE でログ出力 (API から受け取った文字列そのまま) UE_LOG(LogTemp, Display, TEXT("Response %s"), *Response->GetContentAsString()); // UE でログ出力 (JSON から title キーの文字列のみ出力) UE_LOG(LogTemp, Display, TEXT("Title %s"), *ResponseObj->GetObjectField("slideshow")->GetStringField("title")); } } else { UE_LOG(LogTemp, Error, TEXT("Reponse Code : %d"), Response->GetResponseCode()); } }
- http リクエストするアクターを作成
- ヘッダファイル
- HttpRequest を include する
- SendRequest メンバ関数を定義する
- Blueprint から呼び出すため UFUNCTION マクロを指定する
- BlueprintCallable
- Category = ”Http”
- Blueprint から呼び出すため UFUNCTION マクロを指定する
// ApiTest.h // Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "HttpRequest.h" // <= include #include "GameFramework/Actor.h" #include "ApiTest.generated.h" UCLASS() class HTTPREQUESTSAMPLE_API AApiTest : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties AApiTest(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; public: // Called every frame virtual void Tick(float DeltaTime) override; UFUNCTION(BlueprintCallable, Category = "Http") // <= メンバ関数定義 void SendRequest(); };
// ApiTest.cpp // Fill out your copyright notice in the Description page of Project Settings. #include "ApiTest.h" // Sets default values AApiTest::AApiTest() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; } // Called when the game starts or when spawned void AApiTest::BeginPlay() { Super::BeginPlay(); } // Called every frame void AApiTest::Tick(float DeltaTime) { Super::Tick(DeltaTime); } void AApiTest::SendRequest() // <= メンバ関数の実装 { HttpRequest Request; Request.OnRequest("https://httpbin.org/json", "GET"); }
- Blueprint クラスを作成する
- C++ Classes > <プロジェクト名> > ApiTest > MRB (マウス右クリック)
- Create Blueprint Class Based on ApiTest
- 作成した Blueprint クラスを任意のレベルに配置
HTTP リクエストを行う
画面のボタンを押下すると HTTP リクエストを行うようにする
Widget Blueprint を追加する
- Content Browser > Widget Blueprint
- 適当な名前に変更 > (ex) WBP_ApiRequest
- Widget Blueprint を編集する (Designer) (画面のボタン追加のため)
- Widget Blueprint を編集する (Graph)
(ボタン押下イベントに、API リクエスト処理を割り当てるため)
- My Blueprint > VARIABLES > Navigation > Button_0 > 選択
- Details > Events > On Cliecked > + ボタン押下 > On Clicked Event を追加
- Get Actor Of Class Blueprint を追加
- Actor Class > BP_ApiTest を指定
- Return Value > BP_ApiTest クラスを取得する
- Send Request を実行する
- Level Blueprint を編集する
- Play
- Send Request ボタン押下 > Output Log にレスポンス結果表示
クラスの関連の概観 (PlantUML)
@startuml class diagram ' ---------- ' definition ' ---------- skinparam BackgroundColor #WhiteSmoke skinparam PackageStyle rectangle ' ---------- ' definition ' ---------- package /Engine/Source/Runtime/Online/HTTP/Public { class FHttpModule { {static} + Get() : FHttpModule& + CreateRequest() : TSharedRef<IHttpRequest, ESPMode::ThreadSafe> } package Interfaces { class IHttpBase class IHttpResponse { + GetContentAsString(): FString } class IHttpRequest { + SetVerb(const FString& Verb) : void + SetURL(const FString& URL) : void + ProcessRequest() : bool + OnProcessRequestComplete() : FHttpRequestCompleteDelegate& } note right of IHttpRequest::OnProcessRequestComplete * マクロを利用して Delegate の宣言 ** DECLARE_DELEGATE_ThreeParams( FHttpRequestCompleteDelegate, FHttpRequestPtr /*Request*/, FHttpResponsePtr /*Response*/, bool /*bConnectedSuccessfully*/) end note } } package /Engine/Source/Runtime/Json/Public { package Dom { class FJsonObject } package Serialization { class TJsonReader{} class TJsonReaderFactory { {static} + Create(FString&& JsonString) : TSharedRef<TJsonReader<TCHAR>> } class FJsonSerializer { {static} +Deserialize(const TSharedRef<TJsonReader<CharType>>& Reader, TSharedPtr<FJsonObject>& OutObject, EFlags InOptions = EFlags::None) : bool } } } package C++ { class HttpRequest { + OnRequest(const FString Url, const FString Verb) : void {static} - OnResponseRecieved(FHttpRequestPtr Request, FHttpResponsePtr Response, bool ConnectionSuccessfully) : void } note right of HttpRequest::OnRequest * OnRequest の処理内容 ** FHttpModule::Get で FHttpModule のインスタンスを取得 (Singleton ライクな実装) ** FHttpModule.CreateRequest で IHttpRequet インタフェースを取得 (プラットフォームに合わせたインタフェース。SharedReference かつ スレッドセーフ) ** IHttpRequest->OnProcessRequestComplete デリゲートに、OnResponseRecieved 関数をバインド ** IHttpRequest->SetURL に、問い合わせ URL を設定 ** IHttpRequest->SetVerb に、HTTP メソッドを設定 ** IHttpRequest->ProcessRequest でリクエスト実行 end note note right of HttpRequest::OnResponseRecieved * OnResponseRecieved の処理内容 (IHttpRequest の OnProcessRequestComplete デリゲートに登録) ** FJsonObject (SharedPointer) を作成 ** TJsonReader (SharedReference) を TJsonReaderFactory::Create で作成 ** FJsonSerializer::Desirialize で、FJsonObject と TJsonReader を受け取りデシリアライズ ** デシリアライズしたレスポンスをログに表示する end note class ApiTest { + SendRequest() : void } } package Blueprint { class BP_ApiTest class WBP_ApiRequest note right of WBP_ApiRequest * Widget Blueprint Class ** Button の Onclicked イベントに BP_ApiTest の SendRequest を紐づけ end note } ' ---------- ' relation ' ---------- TJsonReader <-- TJsonReaderFactory : use IHttpBase <|-- IHttpRequest : extends IHttpBase <|-- IHttpResponse : extends FHttpModule <---- HttpRequest : use IHttpRequest <---- HttpRequest : use IHttpResponse <---- HttpRequest : use TJsonReaderFactory <---- HttpRequest : use FJsonObject <---- HttpRequest : use FJsonSerializer <---- HttpRequest : use HttpRequest <-- ApiTest : use ApiTest <|-- BP_ApiTest : extends BP_ApiTest <-- WBP_ApiRequest : use @enduml
参考
#UnrealEngine5 でHTTPリクエスト機能を実装してAPIコールしてみた | DevelopersIO
https://www.youtube.com/watch?v=c6gad7tXfTM
[UE4] HTTP通信 その1 ~基本編~|株式会社ヒストリア