Unity(ver:2019.4.28f1)で、UnityWebRequest を使って HTTP(POST) 通信します。今回作成するHTTP通信スクリプト「ApiHttpTest.cs」の仕様を次に示します。
- UnityWebRequest で HTTP(POST)通信
- リクエスト、レスポンスは JSON 形式
- 基底クラスを使った複数の通信 API の作成
スクリプトテンプレートの作成
プロジェクト「HttpTest」を作成し、Unityのスクリプトテンプレートを次のように作成します。
作成したスクリプト・クラスのフォルダ構成を次に示します。
HTTP通信スクリプトの作成
つぎのようにHTTP通信スクリプト「ApiHttpTest.cs」を作成します。作成したHTTP通信スクリプト「ApiHttpTest.cs」は、HierarchyのMainCameraにドラッグ&ドロップします。
- 14-15行目で SoldierとWeaponを生成します。
- 25行目の「sendApiSoldier」では Soldier、58行目の「sendApiWeapon」ではWeaponと通信します。それぞれのSendメソッド 内で JSON 形式にシリアライズされ、UnityWebRequest で HTTP(POST) 通信されます。通信完了をコールバックで受け取り、レスポンス構造体へデシリアライズします。
- 25行目の「sendApiSoldier」では、「userId = “usersoldier”」「password = “abc123″」をjson形式で送信し、サーバから「’name’=>’tomosoft’」「 ‘age’=>2」をjson形式で受信します。
- 58行目の「sendApiWeapon」では、「userId = “userweapon”」「valuesreq = { 1, 10, 100, 1000 }」をjson形式で送信し、サーバから「’count’=>5 」「‘valuesres’=> [1,2,3,4,5]」をjson形式で受信します。
ApiHttpTest.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ApiHttpTest : MonoBehaviour
{
private Api.Soldier soldier;
private Api.Weapon weapon;
private Web.ApiBase.Result result;
private void Start()
{
// 通信用クラス生成
soldier = new Api.Soldier();
weapon = new Api.Weapon();
// API 通信
sendApiSoldier();
sendApiWeapon();
}
/// <summary>
/// API Soldier 通信
/// </summary>
private void sendApiSoldier()
{
// エンドポイントの設定
soldier.EndPoint = Api.Soldier.Name;
// リクエストパラメータを設定
soldier.request.userId = "usersoldier";
soldier.request.password = "abc123";
// 通信
soldier.Send<Api.Soldier.Request>(ref soldier.request, result => {
// リザルト
if(result.isSucceeded) // 成功
{
// レスポンスを展開
soldier.response = soldier.Response<Api.Soldier.Response>();
// 内容確認
Debug.Log("Soldier Succeed!!");
Debug.Log(" name : " + soldier.response.name);
Debug.Log(" age : " + soldier.response.age);
}
else // 失敗
{
Debug.Log("Soldier Failed : " + result.error);
}
});
}
/// <summary>
/// API Weapon 通信
/// </summary>
private void sendApiWeapon()
{
// エンドポイントの設定
weapon.EndPoint = Api.Weapon.Name;
// リクエストパラメータを設定
weapon.request.userId = "userweapon";
weapon.request.valuesreq = new List<int>() { 1, 10, 100, 1000 };
// 通信
weapon.Send<Api.Weapon.Request>(ref weapon.request, result => {
// リザルト
if (result.isSucceeded) // 成功
{
// レスポンスを展開
weapon.response = weapon.Response<Api.Weapon.Response>();
// 内容確認
Debug.Log("Weapon Succeed!!");
Debug.Log(" count : " + weapon.response.count);
foreach(var v in weapon.response.valuesres)
{
Debug.Log(" val : " + v);
}
}
else // 失敗
{
Debug.Log("Weapon Failed : " + result.error);
}
});
}
}
soldierクラスの作成
HTTP 通信クラス「ApiBase.cs」を基底クラスとして、各API のリクエストとレスポンスを定義した soldierクラス「soldier.cs」を作成します。
- 10行目で、通信時の URL は共通部分をHTTP 通信クラス「ApiBase.cs」側で定義するので、末尾の API 名を定義します。
- 15行目,26行目で、リクエストとレスポンス用の構造体を Serializable 属性で作成し、パラメータを定義します。
Api/soldier.cs
using System;
namespace Api
{
/// <summary>
/// API Soldier
/// </summary>
public class Soldier : Web.ApiBase
{
public const string Name = "soldier.php";
/// <summary>
/// リクエストパラメータ
/// </summary>
[Serializable]
public struct Request
{
public string userId;
public string password;
}
public Request request;
/// <summary>
/// レスポンスパラメータ
/// </summary>
[Serializable]
public struct Response
{
public string name;
public int age;
}
public Response response;
}
}
HTTP 通信クラスの作成
HTTP 通信クラス「ApiBase.cs」を次のように作成します。
- 77行目でUnityWebRequest を POST形式で生成し、リクエストパラメータをjson形式で設定します。詳細については「UnityWebRequest」を参照
- 58-59行目でパラメータは string のままでは渡せないため、byte配列に変換します。詳細については「JSON Serialization」を参照
- 64行目で、コルーチンを使ってHTTP(POST)通信を開始します。
- 87-89行目で、通信結果は isNetworkError と isHttpError がともに false であることで成功と判定します。
- 96行目でレスポンスはdownloadHandler に Json形式(text)で格納されます。
Utility/ApiBase.cs
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
namespace Web
{
/// <summary>
/// HTTP 通信クラス
/// </summary>
public class ApiBase
{
/// <summary>
/// HTTP 通信の結果
/// </summary>
public struct Result
{
public bool isSucceeded; // true で成功
public string error; // 失敗時のエラー内容
/// <summary>
/// 成功
/// </summary>
public void Suceeded()
{
isSucceeded = true;
error = "";
}
/// <summary>
/// 失敗
/// </summary>
/// <param name="error"></param>
public void Failed(string error)
{
isSucceeded = false;
this.error = error;
}
}
// ベースURL
private const string BaseUrl = "http://localhost/httptest/"; // 適切なパスを設定してください
// レスポンス(JSON)
private string resJson;
// エンドポイント
public string EndPoint { get; set; }
/// <summary>
/// リクエスト(オブジェクト)を JSON に変換して HTTP(POST)通信を行う
/// </summary>
/// <typeparam name="T">リクエスト型</typeparam>
/// <param name="request">リクエストのオブジェクト</param>
/// <param name="cb">コールバック</param>
public void Send<T>(ref T request, Action<Result> cb)
{
// リクエストオブジェクトを JSON に変換(byte配列)
string reqJson = JsonUtility.ToJson(request);
byte[] postData = System.Text.Encoding.UTF8.GetBytes(reqJson);
// HTTP(POST)通信
var url = BaseUrl + EndPoint;
Debug.Log("Send URL : " + url);
CoroutineHandler.StartStaticCoroutine(onSend(url, postData, cb));
}
/// <summary>
/// HTTP(POST)通信の実行
/// </summary>
/// <param name="url">接続する URL</param>
/// <param name="postData">POST するデータ</param>
/// <param name="cb">コールバック</param>
/// <returns>コルーチン</returns>
private IEnumerator onSend(string url, byte[] postData, Action<Result> cb)
{
// HTTP(POST)の情報を設定
var req = new UnityWebRequest(url, "POST");
req.uploadHandler = (UploadHandler)new UploadHandlerRaw(postData);
req.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
req.SetRequestHeader("Content-Type", "application/json");
// API 通信(完了待ち)
yield return req.SendWebRequest();
// 通信結果
Result result = new Result();
if (req.isNetworkError ||
req.isHttpError) // 失敗
{
Debug.Log("Network error:" + req.error);
result.Failed(req.error);
}
else // 成功
{
Debug.Log("Succeeded:" + req.downloadHandler.text);
resJson = req.downloadHandler.text;
result.Suceeded();
}
cb(result);
}
/// <summary>
/// レスポンス(JSON)からオブジェクトを生成して返す
/// </summary>
/// <typeparam name="T">レスポンス型</typeparam>
/// <returns>レスポンスのオブジェクト</returns>
public T Response<T>()
{
return JsonUtility.FromJson<T>(resJson);
}
}
}
コルーチンクラスの作成
HTTP 通信クラス「ApiBase.cs」は MonoBehaviour を継承していないので、次のようにコルーチンクラス「CoroutineHandler.cs」を作成します。
Utility/CoroutineHandler.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// MonoBehaviour を継承せずにコルーチンを使うためのクラス
/// 参考:https://qiita.com/Teach/items/2fa2b4fa4334a0a3e34d
/// </summary>
public class CoroutineHandler : MonoBehaviour
{
// インスタンス
static protected CoroutineHandler Instance;
// インスタンス取得(DontDestroy な Object)
static public CoroutineHandler instance
{
get
{
if (Instance == null)
{
GameObject obj = new GameObject("CoroutineHandler");
DontDestroyOnLoad(obj);
Instance = obj.AddComponent<CoroutineHandler>();
}
return Instance;
}
}
/// <summary>
/// オブジェクトが非アクティブまたは削除される際の処理(解放)
/// </summary>
public void OnDisable()
{
if(Instance)
{
Destroy(Instance.gameObject);
Instance = null;
}
}
/// <summary>
/// コルーチンの起動
/// </summary>
/// <param name="coroutine">起動させるコルーチン</param>
/// <returns>コルーチン</returns>
static public Coroutine StartStaticCoroutine(IEnumerator coroutine)
{
return instance.StartCoroutine(coroutine);
}
}
サーバ側スクリプトの作成
xampp環境下で次のphpアプリ「soldier.php」「weapon.php」を動作させ、UnityからのアクセスでJson形式で受け取ったデータにデータを追加して転送します。
- 2行目で追加するデータ「’name’=>’tomosoft’, ‘age’=>2」を定義します。
httptest/soldier.php
<?php
$value_array = ['name'=>'tomosoft', 'age'=>2, 'value3'=>3, 'value4'=>4, 'value5'=>5];
try {
//print_r(getallheaders() );
//echo "body".file_get_contents('php://input');
$post_body = file_get_contents('php://input');
$obj = json_decode($post_body,true);
if ($obj === NULL) return;
//配列をJSON形式に変換
$jsonstr = json_encode($obj + $value_array);
echo $jsonstr;
} catch (PDOException $e){
var_dump($e->getMessage());
}
?>
- 2行目で追加するデータ「’count’=>5, ‘valuesres’=> [1,2,3,4,5]」を定義します。
httptest/weapon.php
<?php
$value_array = ['count'=>5, 'valuesres'=> [1,2,3,4,5], 'value3'=>3, 'value4'=>4, 'value5'=>5];
try {
//print_r(getallheaders() );
//echo "body".file_get_contents('php://input');
$post_body = file_get_contents('php://input');
$obj = json_decode($post_body, true);
if ($obj === NULL) return;
//配列をJSON形式に変換
$jsonstr = json_encode($obj + $value_array);
echo $jsonstr;
} catch (PDOException $e){
var_dump($e->getMessage());
}
?>
HTTP通信スクリプトの実行
ゲームをプレーすると、Consoleにサーバから転送された次のデータが表示されます。


