Unity2018.3以降でObservableWWWの代替手段

# ObservableWWW

`ObservableWWW`とはUniRxで`UnityEngine.WWW`を`Observable`として扱える便利な機構でした。
ですがこの`UnityEngine.WWW`自体がかなり古く、2019年現在では非推奨となってしまいました。
（代わりに`UnityWebRequest`を使う必要がある）

それに伴い、Unity2018.3以降では`ObservableWWW`が`Obsolete`になってしまいました。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47146/da3d6cb9-5ba3-a423-3a2b-e55ef4877ca0.jpeg)



そこで今回は、Unity2018.3以降で`ObservableWWW`の代替手段を紹介します。

# そもそもUnity2018.3以降でObservableWWW使わなくない？

そもそも論として、**Unity2018.3だとUniTaskが使える**ため積極的に`Observable`を利用する必要がありません。
このような単発の非同期処理であれば`async/await`で十分だからです。

# 結論: UniTaskを使おう

ということで、結論としては「UniTaskを使う」となります。

## GitHubからUniTaskを導入

UniTaskはAssetStoreでは公開されていないため、GitHubから導入する必要があります。

 * [UniTask Release Page](https://github.com/Cysharp/UniTask/releases)

上記の場所から最新のUniTaskのunitypackageをダウンロードして、Unityプロジェクトに導入してください。
UniTaskというプロジェクト名ですけど、歴史的経緯でパッケージ名は「**UniRx.Async**」になっています。

## UniTaskを使ったコードを書く

`using UniRx.Async;`をした上で。`WWW`の代わりに`UnityWebRequest`を`async/await`で待受けるようにしてください。

```cs
using System;
using UnityEngine;
using UniRx.Async;
using UnityEngine.Networking;

public class UnityWebRequestSample : MonoBehaviour
{
    async void Start()
    {
        var uri = "https://unity.com/";
        try
        {
            var result = await GetTextAsync(uri);
            Debug.Log(result);
        }
        catch (Exception e)
        {
            Debug.LogException(e);
        }
    }


    /// <summary>
    /// UnityWebRequestをasync/awaitで待ち受ける
    /// </summary>
    private async UniTask<string> GetTextAsync(string uri)
    {
        var uwr = UnityWebRequest.Get(uri);

        // SendWebRequestが終わるまでawait 
        await uwr.SendWebRequest();

        if (uwr.isHttpError || uwr.isNetworkError)
        {
            // 失敗していたらそのまま例外をthrow
            throw new Exception(uwr.error);
        }

        return uwr.downloadHandler.text;
    }
}
```

これでOKです。

# でもやっぱObservableがいい

諸々の諸事情により、`UniTask<T>`ではなく`IObservable<T>`に変換したい場合があります。
その場合は`ToObservable()`を用いて変換するとよいでしょう。

## Hotのままでいいなら

`GetTextureObservable()`を実行した時点で`GetTextAsync()`が実行開始してもよいならこの方法でOKです。

```cs
/// <summary>
/// UnityWebRequestを内部で利用したObservable
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
private IObservable<string> GetTextureObservable(string uri)
{
    return GetTextAsync(uri).ToObservable();
}

/// <summary>
/// UnityWebRequestをasync/awaitで待ち受ける
/// </summary>
private async UniTask<string> GetTextAsync(string uri)
{
    var uwr = UnityWebRequest.Get(uri);

    // SendWebRequestが終わるまでawait 
    await uwr.SendWebRequest();

    if (uwr.isHttpError || uwr.isNetworkError)
    {
        // 失敗していたらそのまま例外をthrow
        throw new Exception(uwr.error);
    }

    return uwr.downloadHandler.text;
}
```

## Coldにしたいなら

`GetTextureObservable()`を`Subscribe()`したタイミングで、`GetTextAsync()`が実行開始して欲しいならこの方法で。
`Observable.Defer()`を使ってください。

```cs
/// <summary>
/// UnityWebRequestを内部で利用したObservable
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
private IObservable<string> GetTextureObservable(string uri)
{
    return Observable.Defer(() => GetTextAsync(uri).ToObservable());
}

/// <summary>
/// UnityWebRequestをasync/awaitで待ち受ける
/// </summary>
private async UniTask<string> GetTextAsync(string uri)
{
    var uwr = UnityWebRequest.Get(uri);

    // SendWebRequestが終わるまでawait 
    await uwr.SendWebRequest();

    if (uwr.isHttpError || uwr.isNetworkError)
    {
        // 失敗していたらそのまま例外をthrow
        throw new Exception(uwr.error);
    }

    return uwr.downloadHandler.text;
}
```

# まとめ

 * UnityWebRequestを使うならUniTaskとasync/awaitで
 * ObservableにしたいならUniTaskから変換する


なお、このままでは`CancellationToken`を引数にしていた場合`ToObservable`ができない。
なのでこちらを記事をどうぞ。

* [UniTaskをCancellationTokenを指定しながらToObservableするメモ](https://qiita.com/toRisouP/items/8ec18d73d9e8c5169587)