TECH
BLOG

Oculus Platform APIをコールバックからTaskへ変換する

2020
6

はじめに

Oculus Storeからアプリを配布する時はOculus Platform APIが必須になっています。
そのOculus Platform APIは結果をコールバックで返すので処理が冗長になってしまいますが簡単にTask化できたので紹介します。

開発環境

  • System.Threading.Tasksを扱える設定およびバージョンのUnity
  • Unity2017 + Experimental (.NET 4.6 Equivalent)
  • Unity2018 + .NET 4.x Equivalent
  • Unity2019以上
  • Oculus Integration v1.41.0以上

コールバックの場合

以下はエンタイトルメントチェックのベストプラクティスのサンプルコードです。Oculus Platform APIはIsUserEntitledToApplication()のようにOnComplete()で結果が返ってくるので同様の呼び出しが続くとコールバック地獄になって処理の流れが分かりにくくなります。

using UnityEngine;
using Oculus.Platform;
public class AppEntitlementCheck: MonoBehaviour {
 void Awake ()
 {
   try
   {
     Core.AsyncInitialize();
     Entitlements.IsUserEntitledToApplication().OnComplete(EntitlementCallback); // ここがコールバック
   }
   catch(UnityException e)
   {
     Debug.LogError("Platform failed to initialize due to exception.");
     Debug.LogException(e);
     // Immediately quit the application.
     UnityEngine.Application.Quit();
   }
 }
 void EntitlementCallback (Message msg)
 {
   if (msg.IsError)
   {
     Debug.LogError("You are NOT entitled to use this app.");
     UnityEngine.Application.Quit();
   }
   else
   {
     Debug.Log("You are entitled to use this app.");
   }
 }
}

Taskへ変換する

スクリプティング定義シンボルにOVR_PLATFORM_ASYNC_MESSAGESを追加します。

image.png

するとTaskを返すGen()メソッドがOculus.Platform.Requestクラスで使えるようになるので以下のように書く事ができます。

private async void Awake()
{
   try
   {
       if (!Core.Initialized())
       {
           var initialized = await Core.AsyncInitialize().Gen(); // ここをTask化
           if (initialized.IsError)
           {
               Debug.Log($"failed initialize: {initialized.GetError().Message}");
               return;
           }
       }
       var entitlements = await Entitlements.IsUserEntitledToApplication().Gen(); // ここをTask化
       if (entitlements.IsError)
       {
           Debug.Log($"failed entitlement: {entitlements.GetError().Message}");
           return;
       }
       var user = await Users.GetLoggedInUser().Gen(); // ここをTask化
       if (user.IsError)
       {
           Debug.Log($"failed get user: {user.GetError().Message}");
           return;
       }
       Debug.Log($"{user.Data.ID}, {user.Data.OculusID}");
   }
   catch (UnityException e)
   {
       Debug.LogException(e);
       Application.Quit();
   }
}

更にUniTaskと組み合わせるとタイムアウトも簡単に扱えます。

var initialized = await Core.AsyncInitialize().Gen().AsUniTask().Timeout(TimeSpan.FromSeconds(10));

1つ残念なのはGen()が返すTaskはTaskCompletionSourceで作られてprivateフィールドにあるのですがTrySetCanceled()を呼ぶメソッドが用意されていないのでCancellationTokenでキャンセルできない事です。どうしてもキャンセルしたい場合はSDKに多少の変更が必要です。

RELATED PROJECT

No items found.