記事

Unity で Google Sheet を連携する

Unity で Google Sheet を連携する
Visitors

目次




Google Sheet Sync コード



1. DataSheet 連携コード

UnityWebRequest を使って GoogleSheet の gid から csv ファイルとして保存できます。
* UnityEditor を使ってツール化して運用できます。

補足すると、Sheets[] 配列に各シートの gid を入れて、複数シートを一括で csv 取得する構成です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
using Cysharp.Threading.Tasks;

namespace DataSheets
{
    [Serializable]
    public struct Sheet
    {
        public string Name;
        public long Id;
    }	
    
    /// <summary>
    /// Downloads spritesheets from Google Spreadsheet and saves them to Resources.
    /// </summary>
    [ExecuteInEditMode]
    public class GoogleSheetSync : MonoBehaviour
    {
        /// <summary>
        /// Table id on Google Spreadsheet.
        /// Let's say your table has the following url https://docs.google.com/spreadsheets/d/1RvKY3VE_y5FPhEECCa5dv4F7REJ7rBtGzQg0Z_B_DE4/edit#gid=331980525
        /// So your table id will be "1RvKY3VE_y5FPhEECCa5dv4F7REJ7rBtGzQg9Z_B_DE4" and sheet id will be "331980525" (gid parameter)
        /// </summary>
        public string TableId;
        
        /// <summary>
        /// Table sheet contains sheet name and id. First sheet has always zero id. Sheet name is used when saving.
        /// </summary>
        public Sheet[] Sheets;
        
        /// <summary>
        /// Folder to save spreadsheets. Must be inside Resources folder.
        /// </summary>
        public UnityEngine.Object outPutFolder;
        
        private const string UrlPattern = "https://docs.google.com/spreadsheets/d/{0}/export?format=csv&gid={1}";

#if UNITY_EDITOR

        public void DataSync()
        {
            SyncSheetData().Forget();
        }
        
        public async UniTaskVoid SyncSheetData()
        {
            string folder = UnityEditor.AssetDatabase.GetAssetPath(outPutFolder);
            
            Debug.Log("<size=15><color=yellow>Sync started, please wait for confirmation message...</color></size>");
            
            var dict = new Dictionary<string, UnityWebRequest>();
            
            if(String.IsNullOrEmpty(TableId))
            {
                Debug.LogError("Table ID is Empty !!");
                return;
            }			
            
            try
            {
                Debug.Log("<size=15><color=yellow> Set Sheet URL Info....</color></size>");
                
                foreach (var sheet in Sheets)
                {
                    var url = string.Format(UrlPattern, TableId, sheet.Id);
                    
                    Debug.Log($"Downloading: {url}...");
                    
                    dict.Add(url, UnityWebRequest.Get(url));
                }
                
                if (dict.Count < 1)
                {
                    Debug.LogError("Sheet Count Zero !!");
                    return;
                }
                
                Debug.Log("<size=15><color=yellow> Request Sheet Data.... </color></size>");
                
                foreach (var entry in dict)
                {
                    var url = entry.Key;
                    var request = entry.Value;
                    
                    if (!request.isDone)
                    {
                        await request.SendWebRequest();
                    }
                    
                    if (request.error == null)
                    {
                        var sheet = Sheets.Single(i => url == string.Format(UrlPattern, TableId, i.Id));
                        var path = System.IO.Path.Combine(folder, sheet.Name + ".csv");
                        
                        System.IO.File.WriteAllBytes(path, request.downloadHandler.data);
                        
                        Debug.LogFormat("Sheet {0} downloaded to {1}", sheet.Id, path);
                    }
                    else
                    {
                        Debug.LogError("request.error:" + request.error);
                        
                        throw new Exception(request.error);						
                        }
                }
                
                UnityEditor.AssetDatabase.Refresh();
                
                Debug.Log("<size=15><color=green>Successfully Synced!</color></size>");
            }
            catch(Exception e)
            {
                Debug.LogError(e);
            }
        }

#endif
    }
}



2. DataSheet Editor コード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    /// <summary>
    /// SpreadSheetSync カスタム Editor UI
    /// </summary>
    [CustomEditor(typeof(GoogleSheetSync))]
    public class GoogleSheetSyncEditor : Editor
    {        
        public override void OnInspectorGUI()
        {
            DrawDefaultInspector();

            GUIStyle style = new GUIStyle(GUI.skin.button);
            style.normal.textColor = Color.green;
            style.fontSize = 20;

            var component = (GoogleSheetSync)target;          

            if (GUILayout.Button("Get Data Sync", style))
            {
                component.DataSync();
            }
        }
    }



3. Table ID と Sheet gid の探し方

これを上部ツールバーにカスタム追加して使っても構いません。実務ではテーブル更新の間隔が長いことが多いため、私はシーンに置いてプレハブ化して使っていました。

ざっくり言うと、Inspector の Google Sheet Sync コンポーネントで自分の Google Spreadsheet の Table ID を入力し、Sheets 配列に各 Sheet の name と gid を入れれば動きます。 sheet01


Table ID は URL の中で、下の画像でドラッグしている領域です。

sheet02


Sheet[] 配列に入れる Sheet 情報を入力します。Sheet ID には gid、name には下部タブの Sheet 名を入力します。
- ID

sheet03

- Name

sheet04



4. データ取得

読み込みたいテーブルをすべて入力したら “Get Data Sync” ボタンを押します。

注意点として、スプレッドシート側で削除されたテーブルがある場合は、コンポーネント側にも反映しないとエラーになります。
また Sheets に変更があった場合、既存項目は維持しつつ追加シートだけを増やす運用が安全です。
変更したシーン/プレハブは SVN や協業ツールで同期すると楽です。 sheet05

最終的に、スプレッドシート上のテーブルを csv ファイルとして取得できました。

ただし csv はかなり Raw Data なので、別途バイナリ化して最低限の保護を入れるのが望ましいです。

(バイナリ化しても本気で解析されれば突破されるのが現実ですが、誰でも簡単に見られる状態を防ぐという意味で、最低限の安全策は入れておくべきという考えです。)


5. スプレッドシートの共有設定は必ず「リンクを知っている全員」に設定してください。そうしないとアクセス拒否やエラーになります。

sheet06

これはセキュリティ上のデメリットですが、運用のしやすさとのトレードオフです。
開発時や更新時だけ公開設定にし、ローカルに取り込んだら再度制限する、といった運用で補うのが現実的です。

この記事は著者の CC BY 4.0 ライセンスの下で提供されています。