GoogleDrive内に置いてあるマスターデータJsonファイルをUnityにインポートしたい。
手動でGoogleDriveからダウンロードしてUnityエディタに入れても良いんだけど、更新するたびに手動でやるのは面倒なので、できれば自動化したい。
ということで、やってみました。
元々の意図はJsonファイルのインポートですが、この記事ではJsonファイルに限りません。
タイトル通り、MacでUnityからGoogleDrive内のファイルをインポートする方法を、超丁寧に解説します。
GoogleApisをダウンロードする
まずはGoogleApisのDLLファイルをダウンロードします。
Windowsなら簡単にできそうなのですが、MacでGoogleApisをダウンロードする場合は一手間必要です。
(ここの上手い方法が分からなかったので、もしもっと簡単な方法があったら教えて欲しいです)
まず、Visual Studio for Macが入っていない場合は、こちらからインストールしてください。
Visual Studio Code(VSCode)は別物なので注意。
GoogleApisはVisualStudioを通してダウンロードします。
VisualStudioをインストールできたら、起動して「ファイル」 > 「新しいソリューション」から新規プロジェクトを作成します。
「Web and Console」の「アプリ」を選択し、「コンソール アプリケーション」を選択した上で次へ。
対象のフレームワークはデフォルトのままで次へ。
プロジェクト名と保存先を適当に入力。プロジェクト名と同じ文字列が自動でソリューション名にも入力されます。
その他はデフォルトのままにして、作成を選択。
エディタが開かれるので、左のソリューションパネルの中にある「依存関係」を右クリック。
その中にある「NuGetパッケージの管理…」を選択。
「NuGetパッケージの管理 – InstallGoogleApi」というウィンドウが開かれるので、左上のプルダウンが「nuget.org」になっていることを確認した上で、以下のパッケージを追加します。
- Google.Apis
- Google.Apis.Auth
- Google.Apis.Core
- Google.Apis.Drive.v3
- Google.Apis.Script.v1
- Google.Apis.Sheets.v4
- Newtonsoft.json
右上に検索窓があるので、検索して見つけてください。
上記リストの項目全てにチェックを入れ、「パッケージの追加」で追加できます。
パッケージの追加には数秒かかりますが、ダウンロードが終わるとソリューションパネルの「依存関係」の子要素に先ほどのパッケージが入っているのが分かります。
対象パッケージのダウンロードが終わったら、左上にある実行ボタン(再生ボタン)を押して、一度実行します。
デフォルトで記述されている「Hello, World!」をコンソールに表示するだけのプログラムが実行されますが、これによってフォルダ内にDLLファイルが生成されます。
生成されたものをFinderで確認しましょう。
「依存関係」の親要素を右クリックし、「Finderで表示」をクリック。
すると、こんな感じで bin/Debug/netcoreapp3.1 内にいくつかファイルが生成されているのが分かります。
最後に、生成されたファイルのうち先ほどのリストにあるDLLファイルをUnityエディタにドラッグ&ドロップします。
今回はPlugins/GoogleApisというフォルダを作ってその中に入れました。
場所は好きなところで大丈夫です。
Google Cloud Platformを設定する
次に、Google Cloud Platformの設定をします。
Google Cloud Platformのページに移動し、GoogleDriveにアクセスした時と同じGoogleアカウントでログインします。
「Google Cloud Platform」の右にある「プロジェクトの選択」をクリック。
(一度も利用したことがない方はもしかしたら文言が違うかも?)
「プロジェクトの選択」モーダルが開かれるので、右上の「新しいプロジェクト」をクリック。
プロジェクト名を適当に入力します。
場所は「組織なし」でOK。
「作成」をクリックします。
規約の同意が求められる場合は問題なければ同意し、左のメニューから「APIとサービス」を選択。
「OAuth同意画面」をクリックし、「外部」を選んで「作成」。
アプリケーション名を適当に入力し、「保存」をクリック。
ちなみにアプリケーション名に「Google」という文字列が入っているとエラーになるため、「Google」などの文字列を含まないアプリケーション名にする必要があるようです。
次に、「認証情報」から「認証情報を作成」をクリックし、「OAuthクライアントID」をクリック。
アプリケーションの種類は「デスクトップアプリ」を選択し、適当にアプリケーション名を入力したら「作成」。
「OAuth クライアントを作成しました」というモーダルが表示されたら閉じます。
「OAuth 2.0 クライアントID」の右端にあるダウンロードアイコンをクリックし、ダウンロードされた設定jsonファイルをUnityエディタ内に入れておきます。
再びGoogle Cloud Platformに戻り「ダッシュボード」を選択、そして上部にある「APIを有効化」をクリック。
APIライブラリのページに行くので、Google Drive APIを選択し、「有効にする」をクリック。
これでGoogle Cloud Platformでの設定は終わりました。
Unityでの実装
長い道のりでしたが、ついにUnityでの実装に入ります。
まず、以下の3ファイルをUnityエディタ内のEditorフォルダ直下に作成します。
FileImporter.cs
using System.Threading;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
/// <summary>
/// GoogleDriveからファイルをインポート
/// </summary>
public static class FileImporter
{
/// <summary>
/// インポート先
/// </summary>
private static string DESTINATION_PATH = "./Assets/destination/path.json";
/// <summary>
/// GoogleDriveにある対象のファイルID
/// </summary>
private static string DRIVE_FILE_ID = "YOUR_DRIVE_FILE_ID";
/// <summary>
/// インポートしたい時に呼び出す
/// </summary>
[MenuItem("Tools/GoogleDriveからインポート")]
private static async void Import()
{
ImportProgress.Init();
var context = SynchronizationContext.Current;
await Task.Run(() =>
{
ImportProgress.UpdateStatus(ImportProgress.ProgressStatus.Downloading);
context.Post(_ =>
{
GoogleDriveImporter.Import(DRIVE_FILE_ID, DESTINATION_PATH,
() => ImportProgress.UpdateStatus(ImportProgress.ProgressStatus.Finished));
}, null);
});
}
}
GoogleDriveImporter.cs
using System;
using UnityEditor;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using Google.Apis.Services;
using Google.Apis.Download;
using Google.Apis.Util.Store;
using System.IO;
using System.Threading;
/// <summary>
/// GoogleDriveからファイルをインポート
/// </summary>
public static class GoogleDriveImporter
{
/// <summary>
/// GoogleDriveAPIの設定ファイル
/// </summary>
private static string CLIENT_SECRET_FILE = "./Assets/client/secret/path/client_secret.json";
/// <summary>
/// GoogleDriveAPIの出力ファイル
/// </summary>
private static string CREDENTIAL_FILE = "./Assets/credential/path/credential.json";
/// <summary>
/// GoogleDriveからインポート
/// </summary>
public static void Import(string fileID, string destPath, Action onComplete)
{
// スコープを設定
string[] scopes = { DriveService.Scope.DriveReadonly };
// 認証
UserCredential credential;
using (var stream = new FileStream(CLIENT_SECRET_FILE, FileMode.Open, FileAccess.Read))
{
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
scopes,
"user",
CancellationToken.None,
new FileDataStore(CREDENTIAL_FILE, true)).Result;
}
// GoogleDriveAPIに必要
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "default name",
});
// ファイル取得
var request = service.Files.Get(fileID);
var output = new FileStream(destPath, FileMode.Create, FileAccess.Write);
request.MediaDownloader.ProgressChanged += (IDownloadProgress progress) =>
{
switch (progress.Status)
{
case DownloadStatus.Completed:
{
// 成功
ImportProgress.UpdateStatus(ImportProgress.ProgressStatus.Converting);
ImportProgress.Post(() =>
{
AssetDatabase.ImportAsset(destPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
output.Close();
onComplete?.Invoke();
});
break;
}
case DownloadStatus.Failed:
{
// 失敗
UnityEngine.Debug.LogError("インポートに失敗しました: " + progress.Exception);
ImportProgress.UpdateStatus(ImportProgress.ProgressStatus.Error);
break;
}
}
};
request.Download(output);
}
}
ImportProgress.cs
using System.Threading;
using UnityEditor;
using UnityEngine.Events;
/// <summary>
/// インポートの進度を表示
/// </summary>
public static class ImportProgress
{
/// <summary>
/// 進度
/// </summary>
public enum ProgressStatus
{
Preparing,
Downloading,
Converting,
Finished,
Error,
}
/// <summary>
/// SynchronizationContext
/// </summary>
private static SynchronizationContext context;
/// <summary>
/// 初期化
/// </summary>
public static void Init()
{
context = SynchronizationContext.Current;
UpdateStatus(ProgressStatus.Preparing);
}
public static void Post(UnityAction action)
{
context.Post(_ => action?.Invoke(), null);
}
/// <summary>
/// 進度を更新
/// </summary>
public static void UpdateStatus(ProgressStatus status)
{
context.Post(_ =>
{
switch (status)
{
case ProgressStatus.Preparing:
EditorUtility.DisplayProgressBar("インポート中", "ファイル作成中...", 0.1f);
break;
case ProgressStatus.Downloading:
EditorUtility.DisplayProgressBar("インポート中", "ファイルダウンロード中...", 0.4f);
break;
case ProgressStatus.Converting:
EditorUtility.DisplayProgressBar("インポート中", "ファイル展開中...", 0.8f);
break;
case ProgressStatus.Finished:
case ProgressStatus.Error:
EditorUtility.ClearProgressBar();
break;
}
}, null);
}
}
FileImporter.csのDESTINATION_PATHには、インポート先のフォルダパスを指定してください。
同じくFileImporter.csのDRIVE_FILE_IDには、インポートするGoogleDrive内のファイルIDを指定します。
ファイルIDはGoogleDriveの対象ファイルを右クリックして「共有」を選択し、
コピーしたリンク「https://drive.google.com/file/d/XXXXXXXXXXXXX/view?usp=sharing」の「XXXXXXXXXXXXX」部分です。
GoogleDriveImporter.csのCLIENT_SECRET_FILEには、先ほどダウンロードした設定jsonファイルのパスを指定します。
そのままだとファイル名が長いので、client_secret.jsonという名前にリネームしました。
同じくGoogleDriveImporter.csのCREDENTIAL_FILEはGoogleDriveAPIの処理をした時に出力される(特に気にしなくて良い)ファイルのパスです。
パスはどこでも良いので、CLIENT_SECRET_FILEと同じフォルダとかにしておきましょう。
エディタでインポートを実行する
ようやくインポート処理を実行します。
Unityエディタのメニューバーから Tools > GoogleDriveからインポート を選択します。
プログレスバーが表示された直後、初回実行時はブラウザが開いて認証を求められます。
先ほどから使っているGoogleアカウントでログインし、いろいろ許可していきます。
上の画像のように警告が出た場合は、左下の「詳細」をクリックして詳細を開き、「FileImporter(安全ではないページ)に移動」をクリック。
もとのページに戻るので、出てきたダイアログで「許可」を選択。
Received verification code. You may now close this window.
というメッセージが表示されたら認証は完了なので、タブを閉じてUnityエディタに戻ります。
すると、指定したパスにダウンロードされたファイルが出力されているはずです。
コメント