こんにちは、VR事業部の石井です。
今回はUnityからGoogle Driveのファイルを読み書きする方法を紹介します。
はじめに
UnityからGoogle Driveのファイルを読み書きする方法を検索するとUnityGoogleDriveというOSSがよくヒットします。
UnityGoogleDriveはOAuthで認証するアカウントを指定できますが、認証するにはブラウザを開く必要があります。
UnityGoogleDriveは他の認証方法をサポートしていないのでブラウザを開くのは避けられません。
例えばサーバーPCからGoogle Driveにアクセスしたい場合など、ウェブブラウザを経由せずに認証を通す必要があります。
そこで本記事ではサービスアカウントを使用できるGoogle Drive Api v3を使います。
バージョン情報など
各種バージョン情報は以下の通りです。
- Unity 2021.3.24f1
- Nuget for Unity 3.1.0(MIT license)
- Google APIs client Library for .NET(Apache-2.0 license)
- Google.Apis.Drive.v3 1.60.0.3034
- Google.Apis 1.60.0
- Google.Apis.Auth 1.60.0
- Google.Apis.Core 1.60.0
- Newtonsoft.Json 13.0.2(MIT license)
手順
Google Cloud Platformのセットアップ
Google Cloud Platformのコンソールにログインします。
cloud.google.com
まずは新しいプロジェクトを作成します。
上部にあるリストボックスをクリックします。
右上の[新しいプロジェクト]をクリックします。
プロジェクト名を入力します。
ここでは「google-drive-sample」とします。
適当な組織を選択し、[作成]ボタンをクリックします。
プロジェクトができました。
次に左上のハンバーガーメニューのアイコンをクリックして、APIとサービス>認証情報をクリックします。
上部の[+認証情報を作成]をクリックし、サービスアカウントをクリックします。
サービスアカウント名を入力します。
ここでは「service-account-sample」とします。
なお、このタイミングで自動的にそのサービスアカウントのメールアドレスが決定します。
[完了]ボタンをクリックします。
サービスアカウントの欄で、作成したサービスアカウントのメールアドレスをクリックします。
[キー]タブをクリックします。
鍵を追加>新しい鍵をクリックします。
JSON形式を選択し、[作成]ボタンをクリックします。
これでキーがダウンロードできたので、Cドライブ直下にsampleフォルダを作成してそこに保存しておきます。
このキーは下記スクリプトの「キーのJSONファイル」で使用します。
次にGoogle Drive APIを有効化します。
APIとサービス>有効なAPIとサービスで[+APIとサービスの有効化]をクリックします。
検索欄でdriveと入力して検索します。
検索結果にある「Google Drive API」をクリックします。
[有効にする]ボタンをクリックします。
これでGoogle Cloud Platformのセットアップが完了しました。
Google Driveのセットアップ
Google Driveに読み書きしたいフォルダを作成します。
ここではマイドライブに「Sample」というフォルダを作成しました。
作成したフォルダに移動し、フォルダ名をクリックするとメニューが表示されるので、[共有]ボタンをクリックします。
入力欄に先程作成したサービスアカウントのメールアドレスを入力します。
右のリストで「編集者」を選択し、[共有]ボタンをクリックします。
Sampleフォルダに適当なファイルを置いておきます。
ここでは「DriveFile.txt」とします。
SampleフォルダのURLの末尾のIDをメモしておきます。
このIDは下記スクリプトの「Google DriveのフォルダーID」で使用します。
Unityプロジェクトのセットアップ
新規プロジェクトを作成し、Package Managerを開きます。
左上の[+]ボタンをクリックし、「Add package from git URL...」を選択します。
以下のURLを貼り付けて、[Add]ボタンをクリックします。
https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity
これでNuget for Unityをインポートできました。
Nuget for Unityを開きます。
Search欄に「google.apis.drive」と入力して、[Search]ボタンをクリックします。
「Google.Apis.Drive.v3」の[Install]ボタンをクリックします。
Google.Apis.Drive.v3以外にも依存関係のあるライブラリが自動的にインポートされます。
Unityスクリプト
今回はボタンクリックでファイル一覧表示、アップロード、ダウンロードをします。
まずは空のC#スクリプトを作成します。
ここでは「GoogleDriveSample.cs」とします。
そして、以下のように実装します。
using System; using System.Collections.Generic; using System.IO; using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Services; using Google.Apis.Upload; using TMPro; using UnityEngine; public class GoogleDriveSample : MonoBehaviour { /// <summary> /// キーのJSONファイル /// </summary> private const string JSON_FILE = @"C:\sample\[サービスアカウントのJSON].json"; /// <summary> /// Google DriveのフォルダーID /// </summary> private const string GOOGLE_DRIVE_FOLDER_ID = "[Google DriveのフォルダーID]"; /// <summary> /// アップロードするファイルパス /// </summary> private const string FILE_PATH = @"C:\sample\LocalFile.txt"; /// <summary> /// ダウンロードするファイルID /// </summary> private const string DOWNLOAD_FILE_ID = "[ダウンロードするファイルID]"; /// <summary> /// ダウンロードファイル保存パス /// </summary> private const string SAVE_PATH = @"C:\sample"; /// <summary> /// キャンバステキスト /// </summary> [SerializeField] private TextMeshProUGUI _canvasText; /// <summary> /// Google Driveのサービス /// </summary> private DriveService _driveService; private void Start() { // 認証情報を取得 GoogleCredential credential; using (var stream = new FileStream(JSON_FILE, FileMode.Open, FileAccess.Read)) { credential = GoogleCredential.FromStream(stream).CreateScoped(DriveService.ScopeConstants.Drive); } // Drive APIのサービスを作成 _driveService = new DriveService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = "Google Drive Sample", }); OutputCanvasText("Service:" + _driveService.Name); } /// <summary> /// ファイルの一覧表示 /// </summary> public void List() { try { List(_driveService); } catch (Exception e) { OutputCanvasText(e.Message); } } /// <summary> /// ファイルの一覧表示 /// </summary> /// <param name="service">Google Driveのサービス</param> private void List(DriveService service) { OutputCanvasText("List start"); // フォルダ内を検索する var request = service.Files.List(); request.Q = "'" + GOOGLE_DRIVE_FOLDER_ID + "' in parents"; // files(*) だとすべての情報が取得できる request.Fields = "nextPageToken, files(id, name, size, createdTime)"; var files = new List<Google.Apis.Drive.v3.Data.File>(); do { var result = request.Execute(); files.AddRange(result.Files); request.PageToken = result.NextPageToken; } while (!string.IsNullOrEmpty(request.PageToken)); // 結果を出力する foreach (var file in files) { OutputCanvasText("Name: " + file.Name + " ID: " + file.Id + " Size: " + file.Size + "byte CreatedTime: " + file.CreatedTime); } OutputCanvasText("List end"); } /// <summary> /// ファイルのダウンロード /// </summary> public void Download() { try { Download(_driveService); } catch (Exception e) { OutputCanvasText(e.Message); } } /// <summary> /// ファイルのダウンロード /// </summary> /// <param name="service">Google Driveのサービス</param> private void Download(DriveService service) { OutputCanvasText("Download start"); // メタデータを取得 var file = service.Files.Get(DOWNLOAD_FILE_ID).Execute(); if (file == null) { OutputCanvasText("fileがnull"); return; } OutputCanvasText("Name: " + file.Name + " ID: " + file.Id); // ダウンロード var request = service.Files.Get(DOWNLOAD_FILE_ID); var fileStream = new FileStream(Path.Combine(SAVE_PATH, file.Name), FileMode.Create, FileAccess.Write); request.Download(fileStream); fileStream.Close(); OutputCanvasText("Download end"); } /// <summary> /// ファイルのアップロード /// </summary> public void Upload() { try { // アップロードするファイルのメタデータを作成 var fileMetadata = new Google.Apis.Drive.v3.Data.File() { Name = Path.GetFileName(FILE_PATH), Parents = new[] {GOOGLE_DRIVE_FOLDER_ID}, }; Upload(_driveService, fileMetadata); } catch (Exception e) { OutputCanvasText(e.Message); } } /// <summary> /// ファイルのアップロード /// </summary> /// <param name="service">Google Driveのサービス</param> /// <param name="fileMetadata">メタデータ</param> /// <exception cref="Exception"></exception> private void Upload(DriveService service, Google.Apis.Drive.v3.Data.File fileMetadata) { OutputCanvasText("Upload start"); var request = service.Files.Create(fileMetadata, new FileStream(FILE_PATH, FileMode.Open), "text/plain"); request.Fields = "name, id"; var uploadProgress = request.Upload(); if (uploadProgress.Status != UploadStatus.Completed) { OutputCanvasText("Upload failed:" + uploadProgress.Status); return; } // アップロードされたファイルの名前とIDを取得 var file = request.ResponseBody; OutputCanvasText("Name:" + file.Name + " ID:" + file.Id); OutputCanvasText("Upload end"); } /// <summary> /// キャンバスにあるテキストに追記する /// </summary> /// <param name="text">テキスト</param> private void OutputCanvasText(string text) { _canvasText.text += text + "\n"; } }
上記スクリプトのJSON_FILE (キーのJSONファイル)、GOOGLE_DRIVE_FOLDER_ID (Google DriveのフォルダーID)は前記Google Cloud Platformのセットアップ、Google Driveのセットアップで取得した値を入力してください。
また、このサンプルでは通信に同期処理をしているため、大きなファイルを処理するとUIが固まります。
実際に利用するときはasync/awaitとExecuteAsyncメソッド、UploadAsyncメソッドを使うと良いでしょう。
シーンに空のGameObjectを作成し、「GoogleDriveSample」とします。
そのオブジェクトに上記のGoogleDriveSample.csをアタッチします。
空のCanvasを作成します。
そこにボタンを3つ並べ、「List Button」、「Download Button」、「Upload Button」とします。
さらにTextを追加し、「Canvas Text」とします。
List ButtonオブジェクトのButtonコンポーネントでOn Clickリストを1つ追加し、GoogleDriveSampleオブジェクトを参照します。
発生させるイベントでGoogleDriveSample.Listを選択します。
Download ButtonはGoogleDriveSample.Download、Upload ButtonはGoogleDriveSample.Uploadになるように同様に設定します。
GoogleDriveSampleオブジェクトのCanvas TextにCanvas TextオブジェクトのTextMeshProを参照します。
SkyBoxのままだと文字が見にくいので、Main CameraのClear Flagsを「Solid Color」、Backgroundを黒に近い色にします。
最後にC:\sampleフォルダに適当なファイルを置いておきます。
ここでは「LocalFile.txt」とします。
これで準備が整いました。
実行
実行します。
ゲームビューで[List]ボタンをクリックします。
Google Driveに保存したファイルの情報が表示されました。
このファイルをダウンロードしたいので、IDをメモしておきます。
一度Unityの実行を停止し、上記スクリプトのDOWNLOAD_FILE_ID (ダウンロードするファイルID)にそのIDを入力します。
再度実行します。
[Download]ボタンをクリックします。
C:\sampleフォルダを見ると「DriveFile.txt」が保存されています。
[Upload]ボタンをクリックします。
Google DriveのSampleフォルダを見ると「LocalFile.txt」が保存されています。
まとめ
UnityGoogleDriveを使わずにUnity上でGoogle Driveのファイルを読み書きできました。
OAuthを使用せずサービスアカウントを使うという選択肢もあることを知っておくと、要件に合わせて使い分けができます。
cloud.google.com
cloud.google.com
それぞれの特性を理解した上でお試しください!