Posted at

PlayFabのUnitySDKのコールバック地獄の対応

PlayFabのUnitySDKは古いUnityにも対応するため、async/awaitではなくコールバックで結果を受け取ります。

C#SDKはasync/awaitなのですが、こちらはAndroid実機などでHttpClientを使おうとしてアプリがクラッシュします。

手っ取り早く解決するために、PlayFabClientAPIを解析して内部でUniTaskCompletionSourceを使ってUniTaskを返すWrapperメソッドの集まりを作りました。

// こんな感じでメソッド名を洗い出す

var validMethods = new List<(string methodName, string requestType, string resultType)>();
using (var stream = File.OpenText("PlayFabClientAPI.cs")))
{
while (!stream.EndOfStream)
{
var row = stream.ReadLine();
// public static void ***(***Request...)を探す
if (row.Contains("public static void") && row.Contains("request") && row.Contains("resultCallback"))
{
var temp = row.Split(new[] { "void ", "(" }, StringSplitOptions.RemoveEmptyEntries);
var methodName = temp[1];
temp = temp[2].Split("request", StringSplitOptions.RemoveEmptyEntries);
var requestType = temp[0];
temp = temp[1].Split(new[] { " Action<", ">" }, StringSplitOptions.RemoveEmptyEntries);
var resultType = temp[1];
validMethods.Add((methodName, requestType, resultType));
}
}
}

// こんな感じでラッピングしたメソッドを書き出す

foreach (var (methodName, requestType, resultType) in validMethods)
{
if (methodName.Contains("<"))
{
var temp = methodName.Split(new[] { "<", ">" }, StringSplitOptions.RemoveEmptyEntries);
stringBuilder.AppendLine($"\t\tpublic static UniTask<{resultType}> {temp[0]}Async<{temp[1]}>({requestType} request, object customData = null, Dictionary<string, string> extraHeaders = null)");
}
else
{
stringBuilder.AppendLine($"\t\tpublic static UniTask<{resultType}> {methodName}Async({requestType} request, object customData = null, Dictionary<string, string> extraHeaders = null)");
}
stringBuilder.AppendLine("\t\t{");
stringBuilder.AppendLine($"\t\t\treturn ToUniTask<{requestType}, {resultType}>({methodName}, request, customData, extraHeaders);");
stringBuilder.AppendLine("\t\t}");
}

完成品

https://gist.github.com/yKimisaki/5a3d331a0c1db909d8e10c9ce079b25d

これで

var result = await PlayFabClientAPIAsync.LoginWithCustomIDAsync(new LoginWithCustomIDRequest()

{
CustomId = "0",
CreateAccount = true,
});

のような感じで結果を受け取ることができます。