
マイケル
みなさんこんにちは!
マイケルです!
マイケルです!

エレキベア
こんにちクマ〜〜〜

マイケル
今日は UnityWebRequest の使い方について見ていくよ!

エレキベア
UnityWebRequestとは何クマ??

マイケル
UnityからWebサーバと通信するために使われる機能だよ!
今回はこれを使って下記のような
CRUD機能(作成、検索、更新、削除)を作ってみます!
今回はこれを使って下記のような
CRUD機能(作成、検索、更新、削除)を作ってみます!


エレキベア
WEBアプリとかで最初に作ったりするやつクマね

マイケル
コードはUnity側だけになるけどGitHubにあげているので
参考にお使いください!
参考にお使いください!
GitHub(masarito617) – unity-web-request-sample

マイケル
それではやっていこう!

エレキベア
楽しみクマ〜〜〜〜
参考書籍

マイケル
今回は特に書籍は使わずに、
下記の公式リファレンスを参考にしています!
下記の公式リファレンスを参考にしています!
UnityWebRequest – Unityスクリプトリファレンス

マイケル
WEBAPIについては下記書籍がおすすめです!
少し古いけどWebの歴史から知ることができるので読み物としても面白いですね。
少し古いけどWebの歴史から知ることができるので読み物としても面白いですね。
Webを支える技術 ―― HTTP,URI,HTML,そしてREST WEB+DB PRESS plus

エレキベア
これは定番クマ〜〜〜
UnityWebRequestの使い方

マイケル
まずは簡単な使い方についてみていこう!
基本的には下記のようにリクエストを作成してレスポンスを受け取ります。
SendWebRequest は非同期のためコルーチン内で実行する必要があります。
基本的には下記のようにリクエストを作成してレスポンスを受け取ります。
SendWebRequest は非同期のためコルーチン内で実行する必要があります。
//リクエスト作成
UnityWebRequest request = UnityWebRequest.Get(【URL】);
// リクエスト送信
yield return request.SendWebRequest();
// レスポンスを受け取る
request.downloadHandler.text
↑基本的な使い方
エレキベア
シンプルクマね

マイケル
リクエストに関しては GET/POST/PUT/DELETE
それぞれ作成することができます。
この時、POSTに関してはWWWFormを使用して値を送ることができます。
それぞれ作成することができます。
この時、POSTに関してはWWWFormを使用して値を送ることができます。
UnityWebRequest.Get(【URL】);
UnityWebRequest.Post(【URL】, 【データ】);
UnityWebRequest.Put(【URL】, 【データ】);
UnityWebRequest.Delete(【URL】);
↑リクエストの作成// formデータの作成
WWWForm form = new WWWForm();
form.AddField("name1", "value1");
form.AddField("name2", "value2");
// リクエスト作成
UnityWebRequest request = UnityWebRequest.Post(【URL】, form);
↑WWWFormを使用したリクエスト作成
エレキベア
値を送るのもこれなら簡単クマね

マイケル
最後にContent-Typeについてですが、
UnityWebRequestはデフォルトでapplication/x-www-form-urlencodedで送信されます。
application/jsonで送信したい場合には、下記のようにUploadHandlerRaw、DownloadHandlerBufferを自身でnewして送る必要があるようです。
UnityWebRequestはデフォルトでapplication/x-www-form-urlencodedで送信されます。
application/jsonで送信したい場合には、下記のようにUploadHandlerRaw、DownloadHandlerBufferを自身でnewして送る必要があるようです。
// byte配列に変換
var bodyRaw = Encoding.UTF8.GetBytes(【JSON】);
// リクエスト作成
var request = new UnityWebRequest(【URL】, "POST");
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
↑application/jsonでの送信
エレキベア
JSON形式で送りたい場合もよくありそうクマね

マイケル
それじゃ使い方はこの辺にしておいて、さっそく使っていこう!
CRUD機能の実装
APIサーバの作成

マイケル
送信先が必要なので、簡単なAPIサーバを準備します。
ここではRuby on Railsを使って、下記のBookテーブルを操作するだけの機能を実装しました。
ここではRuby on Railsを使って、下記のBookテーブルを操作するだけの機能を実装しました。
Bookテーブル構成
本ID | 名前 | 価格 |
id : integer | name : string | price : integer |

エレキベア
かなりシンプルなテーブルクマね

マイケル
APIサーバの作成について詳細は省きますが、
参考までにコマンドを載せておきます!
参考までにコマンドを載せておきます!
# api_testプロジェクト作成
rails new api_test --api --skip-action-mailer --skip-action-mailbox --skip-action-text --skip-action-cable --skip-action-mailer --skip-action-mailbox --skip-action-text --skip-action-cable
cd api_test
# Bookリソースの作成
bin/rails g resource book name:string price:integer
# テーブル作成
bin/rails db:migrate
↑APIサーバの作成
マイケル
この状態で起動してhttp://127.0.0.1:3000にアクセスすると、
お馴染みのWelcome画面が表示されます!
お馴染みのWelcome画面が表示されます!
# サーバ起動
bin/rails server


エレキベア
これだけでサーバ立てられるのは便利クマね〜〜〜

マイケル
resourceコマンドで作成したため、ルーティングは下記のように設定されています。
これらの処理をcontrollerクラスに記述しましょう!
これらの処理をcontrollerクラスに記述しましょう!
GET /books books#index
POST /books books#create
PUT /books/:id books#update
DELETE /books/:id books#destroy
↑routes情報class BooksController < ApplicationController
# 全てのBook情報を返す
def index
@books = Book.all()
render json: {
books: @books
}
end
# Bookレコードを作成する
def create
@book = Book.new()
@book.name = params[:name]
@book.price = params[:price]
if @book.save
render json: @book
end
end
# 指定IDのBookを更新する
def update
@book = Book.find(params[:id])
@book.name = params[:name]
@book.price = params[:price]
if @book.save
render json: @book
end
end
# 指定IDのBookを破棄する
def destroy
@book = Book.find(params[:id])
@book.destroy
end
end
↑各処理の記述
マイケル
これでサーバ側の最低限の準備はできました!
あとは、http://127.0.0.1:3000/books にUnity側からリクエストするようにしていきましょう。
あとは、http://127.0.0.1:3000/books にUnity側からリクエストするようにしていきましょう。

エレキベア
楽しみクマ〜〜〜〜
Unity側の実装
UI構成

マイケル
UIの構成についてですが、
今回は下記のような本アイテムのプレハブをScrollViewの中に生成する
といった構成にしました。
今回は下記のような本アイテムのプレハブをScrollViewの中に生成する
といった構成にしました。



マイケル
プレハブには下記のようなスクリプトをアタッチしておきます。
事前に各UIを割り当てて置くことでGetComponentする数を減らすことができます。
事前に各UIを割り当てて置くことでGetComponentする数を減らすことができます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 本アイテムクラス
/// </summary>
public class BookItemContent : MonoBehaviour
{
public Text idText;
public InputField nameInput;
public InputField priceInput;
public Button updateButton;
public Button deleteButton;
}
↑本アイテムスクリプトの作成
エレキベア
いちいち各フィールドをGetComponentしていたら効率が悪いクマね
本リストの表示

マイケル
まずは本リストの表示機能から!
下記のように、起動時とリロードボタン押下時に取得して表示するようにします。
下記のように、起動時とリロードボタン押下時に取得して表示するようにします。


エレキベア
GETリクエストを送信して
レスポンスから本アイテムを生成するクマね
レスポンスから本アイテムを生成するクマね

マイケル
まず本リスト全体を管理するスクリプトを作成し、共通で使用する送信処理を用意しました。
下記のように
リクエストとコールバックを渡して、レスポンスが返ってきたらコールバックを実行する
といった処理にします。
下記のように
リクエストとコールバックを渡して、レスポンスが返ってきたらコールバックを実行する
といった処理にします。
/// <summary>
/// リクエストを送る
/// </summary>
/// <param name="request"></param>
/// <param name="callback"></param>
private IEnumerator SendRequest(UnityWebRequest request, Action<string> callback = null)
{
// リクエストを送る
yield return request.SendWebRequest();
// レスポンスを出力
if (request.result == UnityWebRequest.Result.ConnectionError
|| request.result == UnityWebRequest.Result.ProtocolError)
{
Debug.Log(request.error);
}
else
{
// コールバックを実行
if (callback != null)
{
callback(request.downloadHandler?.text);
}
}
}
↑送信処理の作成
マイケル
そしてこの送信処理をGetBookList()内から呼び出します!
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
/// <summary>
/// 本リスト管理クラス
/// </summary>
public class BookListManager : MonoBehaviour
{
[SerializeField] private GameObject bookScrollRect; // 本リストスクロールエリア
[SerializeField] private GameObject bookItemPrefab; // 本アイテムPrefab
/// <summary>
/// 開始処理
/// </summary>
private void Start()
{
// 本情報を取得
GetBookList();
}
/// <summary>
/// 全ての本アイテムを取得する
/// READ
/// </summary>
private void GetBookList()
{
// リクエストを送る
var url = "http://127.0.0.1:3000/books";
var request = UnityWebRequest.Get(url);
StartCoroutine(SendRequest(request, response =>
{
var schema = JsonUtility.FromJson<BookSchemaArray>(response);
foreach (var bookSchema in schema.books)
{
// 取得した本アイテムをリストに追加
var obj = Instantiate(bookItemPrefab, bookScrollRect.transform);
var bookItemContent = obj.GetComponent<BookItemContent>();
bookItemContent.idText.text = bookSchema.id.ToString();
bookItemContent.nameInput.text = bookSchema.name;
bookItemContent.priceInput.text = bookSchema.price.ToString();
bookItemContent.updateButton.onClick.AddListener(() => { PushUpdateButton(bookItemContent); });
bookItemContent.deleteButton.onClick.AddListener(() => { PushDeleteButton(bookSchema.id); });
}
}));
}
・・・略・・・
/// <summary>
/// 本リストをクリアする
/// </summary>
private void ClearBookList()
{
foreach (Transform child in bookScrollRect.gameObject.transform)
{
Destroy(child.transform.gameObject);
}
}
/// <summary>
/// JSON型定義
/// </summary>
[Serializable]
private class BookSchema
{
public int id;
public string name;
public int price;
}
[Serializable]
private class BookSchemaArray
{
public BookSchema[] books;
}
// ---------- 各ボタン押下処理 ----------
public void PushReloadButton()
{
ClearBookList();
GetBookList();
}
・・・略・・・
}
↑取得処理の実装
マイケル
コールバック内で返ってきたJSONをclassに変換してUIに設定しています。
JsonUtility.FromJsonを使って変換することができますが、classには[Serializable]を付ける必要があることには注意です。
JsonUtility.FromJsonを使って変換することができますが、classには[Serializable]を付ける必要があることには注意です。

エレキベア
これで表示機能はできたクマね
本アイテムの追加

マイケル
次にアイテムの追加について!
入力された内容をPOSTリクエストで送信しますが、
ここではapplication/jsonを使用した送信処理を実装してみました。
入力された内容をPOSTリクエストで送信しますが、
ここではapplication/jsonを使用した送信処理を実装してみました。

/// <summary>
/// 本アイテムを追加する
/// CREATE
/// </summary>
/// <param name="bookItemContent">追加する本情報</param>
private void AddBookItem(BookItemContent bookItemContent)
{
// jsonデータの作成
var schema = new BookSchema
{
name = bookItemContent.nameInput.text,
price = int.Parse(bookItemContent.priceInput.text)
};
var json = JsonUtility.ToJson(schema);
// byte配列に変換
var bodyRaw = Encoding.UTF8.GetBytes(json);
// リクエストを送る
var url = "http://127.0.0.1:3000/books/";
var request = new UnityWebRequest(url, "POST");
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
StartCoroutine(SendRequest(request, response =>
{
// 本情報を再取得
ClearBookList();
GetBookList();
}));
}
・・・略・・・
public void PushAddButton(BookItemContent bookItemContent)
{
AddBookItem(bookItemContent);
}
↑追加処理の実装
マイケル
最小限のため、入力チェック処理が入っていないことには注意です!

エレキベア
(手抜きクマ・・・。)
本アイテムの更新

マイケル
次に本アイテムの更新処理について!
これもapplication/jsonでPUTリクエストを送信します。
これもapplication/jsonでPUTリクエストを送信します。

/// <summary>
/// 本アイテムを更新する
/// UPDATE
/// </summary>
/// <param name="bookItemContent">更新する本情報</param>
private void UpdateBookItem(BookItemContent bookItemContent)
{
// jsonデータの作成
var schema = new BookSchema
{
name = bookItemContent.nameInput.text,
price = int.Parse(bookItemContent.priceInput.text)
};
var json = JsonUtility.ToJson(schema);
// byte配列に変換
var bodyRaw = Encoding.UTF8.GetBytes(json);
// リクエストを送る
var url = "http://127.0.0.1:3000/books/" + bookItemContent.idText.text;
var request = new UnityWebRequest(url, "PUT");
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
StartCoroutine(SendRequest(request, response =>
{
// 本情報を再取得
ClearBookList();
GetBookList();
}));
}
・・・略・・・
private void PushUpdateButton(BookItemContent bookItemContent)
{
UpdateBookItem(bookItemContent);
}
↑更新処理の実装
エレキベア
追加処理とほぼ同じクマね
本アイテムの削除

マイケル
そして最後に削除処理について!
これはシンプルでidを付与したURLをDELETE送信するだけになります。
これはシンプルでidを付与したURLをDELETE送信するだけになります。

/// <summary>
/// 本アイテムを削除する
/// DELETE
/// </summary>
/// <param name="id">削除する本ID</param>
private void DeleteBookItem(int id)
{
// リクエストを送る
var url = "http://127.0.0.1:3000/books/" + id;
var request = UnityWebRequest.Delete(url);
StartCoroutine(SendRequest(request, response =>
{
// 本情報を再取得
ClearBookList();
GetBookList();
}));
}
・・・略・・・
private void PushDeleteButton(int id)
{
DeleteBookItem(id);
}
↑削除処理の実装
マイケル
以上で最低限のCRUD機能の実装完了です!!

エレキベア
楽勝だったクマね
WWWFormを使用する場合

マイケル
ちなみにWWWFormでPOST、PUTリクエストを送る場合には
下記のようにリクエストを作成します!
PUTメソッドではWWWFormを使用できないため、
POSTリクエスト作成後にrequest.methodにPUTを指定するようにします!
下記のようにリクエストを作成します!
PUTメソッドではWWWFormを使用できないため、
POSTリクエスト作成後にrequest.methodにPUTを指定するようにします!
/// <summary>
/// 本アイテムを追加する(WWWForm使用)
/// CREATE
/// </summary>
/// <param name="bookItemContent">追加する本情報</param>
private void AddBookItemForm(BookItemContent bookItemContent)
{
// formデータの作成
var form = new WWWForm();
form.AddField("name", bookItemContent.nameInput.text);
form.AddField("price", int.Parse(bookItemContent.priceInput.text));
// リクエストを送る
var url = "http://127.0.0.1:3000/books";
var request = UnityWebRequest.Post(url, form);
StartCoroutine(SendRequest(request, response =>
{
// 本情報を再取得
ClearBookList();
GetBookList();
}));
}
/// <summary>
/// 本アイテムを更新する(WWWForm使用)
/// UPDATE
/// </summary>
/// <param name="bookItemContent">更新する本情報</param>
private void UpdateBookItemForm(BookItemContent bookItemContent)
{
// formデータの作成
var form = new WWWForm();
form.AddField("name", bookItemContent.nameInput.text);
form.AddField("price", int.Parse(bookItemContent.priceInput.text));
// リクエストを送る
var url = "http://127.0.0.1:3000/books/" + bookItemContent.idText.text;
var request = UnityWebRequest.Post(url, form);
request.method = "PUT"; // PUTを指定
StartCoroutine(SendRequest(request, response =>
{
// 本情報を再取得
ClearBookList();
GetBookList();
}));
}
↑WWWFormを使用した送信
マイケル
というのも、htmlのformでもPUT、DELETE送信がサポートされていないためだと思われます。
htmlから送る場合にもhiddenパラメータとして_methodを指定して送るのが定番となっているため、同じようなイメージで使用するといいと思います。
htmlから送る場合にもhiddenパラメータとして_methodを指定して送るのが定番となっているため、同じようなイメージで使用するといいと思います。

エレキベア
とりあえずWWWFormを使う時にはPOST送信クマね
おわりに

マイケル
というわけで今回はUnityでCRUD機能を実装してみました!
どうだったかな?
どうだったかな?

エレキベア
クライアントサーバ連携がめんどくさそうだったクマが、
やってみたら思っていたよりも簡単に出来てびっくりしたクマ
やってみたら思っていたよりも簡単に出来てびっくりしたクマ

マイケル
通信処理はソシャゲを作る際には避けて通れないので
どんどん触って慣れていこう!
どんどん触って慣れていこう!

マイケル
それでは今日はこの辺で!
アデュー!!!
アデュー!!!

エレキベア
クマ〜〜〜〜〜
【Unity】UnityWebRequestを使ってCRUD機能を実装する【Ruby on Rails】〜完〜
コメント