準備
-
Unity本体
ただし、Script Runtime Version
で.NET4.x系のものが使えるバージョン
(Unity2018など) -
以下の2つのレポジトリをCloneしておく
gRPC : https://github.com/grpc/grpc
protobuf : https://github.com/google/protobuf
前提
Unity + gRPCでは、MagicOnionというライブラリが有名ですが、ここではそれを使いません。
ただし、MagicOnionの修正内容は参考にしました...
以下をUnityプロジェクトに入れる
- gRPCのC#のソースコード
grpc/src/csharp/Grpc.Core
- protobufのC#のソースコード
protobuf/csharp/src/Google.Protobuf
エラーを粛々と取り除く
IAsyncEnumeratorが無いと怒られる
Assets/Grpc.Core/IAsyncStreamReader.cs(53,46): error CS0246: The type or namespace name `IAsyncEnumerator' could not be found. Are you missing an assembly reference?
IAsyncEnumeratorというインターフェースが無く、コンパイルエラーが出ますので、以下のような定義を追加します。
public interface IAsyncEnumerator<T> : IDisposable
{
T Current { get; }
Task<bool> MoveNext(CancellationToken token);
}
MoveNextの引数がないと言われる
Assets/Grpc.Core/Internal/ServerCallHandler.cs(69,69): error CS1501: No overload for method `MoveNext' takes `0' arguments
これは、Grpc.CoreがRx.NETに依存しているためこのようなエラーが表示されます。
なので、さらに以下のコードを追加します(namespaceやファイルの配置場所はそれぞれの事情に合わせてやってね)
public static class AsyncEnumerator
{
public static Task<bool> MoveNext<T>(this IAsyncEnumerator<T> enumerator)
{
if (enumerator == null)
throw new ArgumentNullException(nameof(enumerator));
return enumerator.MoveNext(CancellationToken.None);
}
}
これは、Rx.NETのコードの中身そのままです。
Rx.NETまでUnityに入れようか悩みましたが、UniRxの競合とかとも考えられるためこの程度にしています。
この時点でコンパイルが通る
エラーが出なくなりました。では、次に実行してみましょう。
デバッグ実行用のSSLの証明書がないと言われる
実行するとこのエラーが出ました
IOException: Error loading the embedded resource "Grpc.Core.roots.pem"
SSLの証明書がない場合のエラーと考察し、どうしようかと考えていましたがここで、MagicOnion
の修正方法を参考にさせていただきました。DefaultSslRootsOverride.cs
を以下のように書き換えます。まあ、中身はまるっとその処理を無視するような内容です。
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
namespace Grpc.Core.Internal
{
/// <summary>
/// Overrides the content of default SSL roots.
/// </summary>
internal static class DefaultSslRootsOverride
{
//const string RootsPemResourceName = "Grpc.Core.roots.pem";
static object staticLock = new object();
/// <summary>
/// Overrides C core's default roots with roots.pem loaded as embedded resource.
/// </summary>
public static void Override(NativeMethods native)
{
lock (staticLock)
{
//var stream = typeof(DefaultSslRootsOverride).GetTypeInfo().Assembly.GetManifestResourceStream(RootsPemResourceName);
//if (stream == null)
//{
// throw new IOException(string.Format("Error loading the embedded resource \"{0}\"", RootsPemResourceName));
//}
//using (var streamReader = new StreamReader(stream))
//{
// var pemRootCerts = streamReader.ReadToEnd();
// native.grpcsharp_override_default_ssl_roots(pemRootCerts);
//}
}
}
}
}
これはMagicOnionのソースコードそのままです。
これで、この実行時のエラーは出なくなります。
DllNotFoundException: grpc_csharp_ext
grpc_charp_exが無いとエラーが表示されます。
DllNotFoundException: grpc_csharp_ext
Grpc.Core.Internal.NativeLogRedirector.Redirect (Grpc.Core.Internal.NativeMethods native) (at Assets/Grpc.Core/Internal/NativeLogRedirector.cs:49)
なので、それを入手してDLLをAssets配下に置く必要があるのですが、ここで自分は手間取りました。
Ubuntsu on Windowsを使っていたせいなのかはわからないですが、grpc本家のREADMEを読みつつビルドを試しましたが、うまくいかず、結局サンプルコードをVisual Studioでビルドし、NuGetパッケージの中かからdllを抜き出すということをしました
参考
- https://github.com/grpc/grpc/blob/master/README.md
- https://github.com/grpc/grpc/tree/master/src/csharp
なんだかんだあって、grpc_csharp_ext.dllをUnityプロジェクトに入れる
ここで、grpcのレポジトリ内にあるサンプルプロジェクトをビルドし、サーバーを立ち上げます。
https://github.com/grpc/grpc/tree/master/examples/csharp/helloworld
この中身をVisual Studioでビルドするだけでサーバー側のプログラムまでビルドされるので、ビルドしたサーバー側のexeファイルを立ち上げます。Windows以外の環境であれば、READMEの手順の通りに .NET Core
インストールしつつビルドすることで実行できるかと思います。
クライアント側のサンプルコードを参考にしつつUnity側のプログラムを書く
まず、gRPC自体のサンプルプロジェクトには .proto
と言われるサーバー側との通信規約をもとにしたコードもあるので、それをUnityプロジェクトに入れます。
ここにある HelloWorld.cs/HelloWorldGRPC.cs
がそれです。
これは、gRPCのコード生成プログラムによって吐かれるコードですがサンプルプロジェクトには含まれています。
UnityからCallする処理を入れる
以下のようなコードを書きます
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Grpc.Core;
using Helloworld;
public class TestGrpc : MonoBehaviour
{
void Start ()
{
Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
var client = new Greeter.GreeterClient(channel);
String user = "Test UserName";
var reply = client.SayHello(new HelloRequest { Name = user });
Debug.Log("Greeting: " + reply.Message);
}
}
これは、gRPCのC#サンプルプロジェクトの中身をそのままUnityのStartに入れ込んだだけです。
適当なGameObjectにこれをアタッチして実行します。
サーバー側のプログラムを立ち上げた上で実行すると、以下のようにちゃんとレスポンスを受け取れました!
その他
Android/iOSで動かすには、grpc_csharp_ext.dll
をそれぞれのプラットフォームごとコンパイルするという苦行が待ってます。
https://github.com/grpc/grpc/blob/master/src/csharp/experimental/README.md
こちらにそのやり方は書かれてますが、まだiOSはTBD扱いです。。。
UniRxの作者の方が、いろいろやり取りされているので、できるんだと思います。
(grpc_csharp_extの中身はCのコードなのでXCodeでゴニョゴニョするとできるはず)
次は各プラットフォームの対応 + リアルタイムチャットなどをgRPCで出来たらなと思います。