Google Driveにcurlを使ってファイルのアップロードやダウンロードを行う

なぜcurlなのか

公式で提供されているクライアントライブラリを利用するのがお手軽かと思います。

今回は実行するマシン(主にMac)でライブラリのセットアップを必要とせず、そのまま実行できることを目的としてcurlを選びました。

Google Drive APIを実行するために

各種APIを実行するにはアクセストークンが必要になります。

OAuth 2.0クライアントの作成

  1. Google Cloud Platform (GCP)でプロジェクトを作成。

  2. 有効なAPIとサービスより、Google Drive APIを有効化。

  3. 認証情報を作成より、OAuth クライアントIDを選択。

  4. ウェブアプリケーション、リダイレクトURLをhttp://localhost:8080を指定して作成。

  5. 作成後、クライアントIDシークレットIDを控える。

Authorization Codeを取得

認証を行うURLを作成し、ブラウザでGoogle Driveの操作を行うアカウントからOAuth認証します。

パラメータ
client_id 先ほど取得した値
redirect_uri https://localhost:8080
scope 権限
スコープの値はコチラを参照。
ファイルアップロード/ダウンロードであれば2つで十分です。
https://www.googleapis.com/auth/drive : Google ドライブのすべてのファイルの表示、編集、作成、削除を行えます
https://www.googleapis.com/auth/drive.metadata : Google ドライブ内のファイルのメタデータの表示と管理
response_type code
access_type offline

組み立て

https://accounts.google.com/o/oauth2/auth?client_id=[クライアントID]&
redirect_uri=https://localhost:8080&
scope=https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.metadata&
response_type=code&
access_type=offline

アクセスを許可する。

localhostなのでアクセスできません となりますが、アドレスバーからAuthorization Codeを確認できます。

http://localhost:8080/?code=[Authorization Code]&
scope=https://www.googleapis.com/auth/drive%20https://www.googleapis.com/auth/drive.metadata

リフレッシュトークンを取得

先ほど取得したAuthorization Codeを使ってリフレッシュトークンを取得します。

curl 'https://www.googleapis.com/oauth2/v4/token' \
--data 'code=[Authorization Code]' \
--data 'client_id=[クライアントID]' \
--data 'client_secret=[シークレットID]' \
--data 'redirect_uri=http://localhost:8080' \
--data 'grant_type=authorization_code' \
--data 'access_type=offline'

レスポンス

{
  "access_token": "ya29.*****",
  "expires_in": 3599,
  "refresh_token": "1//*****",
  "scope": "https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.metadata",
  "token_type": "Bearer"
}

アクセストークンとリフレッシュトークンが得られます。
アクセストークンは1時間で有効期限が切れるので、リフレッシュトークンを使って再取得します。

アクセストークンを取得

curl 'https://www.googleapis.com/oauth2/v4/token' \
--data refresh_token=[リフレッシュトークン] \
--data client_id=[クライアントID] \
--data client_secret=[シークレットID] \
--data grant_type=refresh_token

レスポンス例

{
  "access_token": "*****",
  "expires_in": 3599,
  "scope": "https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.metadata",
  "token_type": "Bearer"
}

有効期限が切れた状態でAPIを実行するとエラーコード 401 が返るので、再度アクセストークンを取得し直してください。

{
  "error": {
    "code": 401,
    "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
    "errors": [
      {
        "message": "Invalid Credentials",
        "domain": "global",
        "reason": "authError",
        "location": "Authorization",
        "locationType": "header"
      }
    ],
    "status": "UNAUTHENTICATED"
  }
}

アップロード

アップロード先が共有ドライブの場合、supportsAllDrives=trueを指定する。
マイドライブの場合はfalseでも可。

curl -X POST 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&supportsAllDrives=true' \
-F "metadata={name:'[ファイル名]', mimeType:'application/octet-stream', parents:['[ドライブID]']};type=application/json;charset=UTF-8" \
-F 'file=@'[ファイルパス]';type=application/octet-stream' \
-H 'Authorization: Bearer [トークン]'

レスポンス例

{
  "kind": "drive#file",
  "id": "[ファイルID],
  "name": "hoge.png",
  "mimeType": "image/png"
}

ダウンロード

-oオプションでファイル保存。
ドライブ上と同じファイル名が不明で同名で保存したい場合、メタデータを別途取得する必要がある。

curl -X GET 'https://www.googleapis.com/drive/v3/files/[ファイルID]?alt=media' \
-o [ファイル名] \
-H "Accept: application/json" \
-H "Authorization: Bearer [トークン]"

ファイルメタデータ

共有ドライブ内のファイルの場合、supportsAllDrives=trueを指定。

curl -X GET 'https://www.googleapis.com/drive/v3/files/[ファイルID]?supportsAllDrives=true' \
-H "Accept: application/json" \
-H "Authorization: Bearer [トークン]"

レスポンス例

{
  "kind": "drive#file",
  "id": "[ファイルID]",
  "name": "[ファイル名]",
  "mimeType": "text/plain",
  "teamDriveId": "[チームドライブID]",
  "driveId": "[ドライブID]"
}

フォルダ内ファイルの列挙

少し複雑、クエリを使用します。
デフォルトだとゴミ箱に移動したファイルも列挙されるため、trashed=falseで除外する。
共有ドライブの場合、supportsAllDrivesincludeItemsFromAllDrivesの両方をtrueに指定する。

curl -X GET 'https://www.googleapis.com/drive/v3/files?q='"'"'[フォルダID]'"'"'+in+parents+and+trashed=false&supportsAllDrives=true&includeItemsFromAllDrives=true' \
-H "Authorization: Bearer [トークン]"

レスポンス例

{
  "kind": "drive#fileList",
  "incompleteSearch": false,
  "files": [
    {
      "kind": "drive#file",
      "driveId": "[ドライブID]",
      "mimeType": "text/plain",
      "id": "[ファイルID]",
      "name": "[ファイル名]",
      "teamDriveId": "[チームドライブID]"
    },
    {
      "kind": "drive#file",
      "driveId": "[ドライブID]",
      "mimeType": "text/plain",
      "id": "[ファイルID]",
      "name": "[ファイル名]",
      "teamDriveId": "[チームドライブID]"
    },
    {}
  ]
}

ページング

pageSizeを指定しない場合は最大100件のファイルを列挙しますが、
超える場合はnextPageTokenというフィールドが追加されます。

{
  "nextPageToken": "[ページトークン]",
  "kind": "drive#fileList",
  "incompleteSearch": false,
  "files": [
    {
      "kind": "drive#file",
      "driveId": "[ドライブID]",
      "mimeType": "text/plain",
      "id": "[ファイルID]",
      "name": "[ファイル名]",
      "teamDriveId": "[チームドライブID]"
    },
    {},
  ]
}

全ファイルを列挙する際はnextPageTokenが無くなるまで順次実行します。

※ MacのZshで実行する際のハマりポイント
ページトークンは先頭 ~!!~から始まるのですが、ヒストリー展開されてエラーになることがありました。
なのでURL全体はダブルクォートではなく、シングルクォートでエスケープするようにしています。

curl -X GET 'https://www.googleapis.com/drive/v3/files?q='"'"'[フォルダID]'"'"'+in+parents+and+trashed=false&supportsAllDrives=true&includeItemsFromAllDrives=true&pageToken=[ページトークン]' \
-H "Authorization: Bearer [トークン]"

Unity Androidビルド環境の構築

Android Build Supportのインストール

Unity Hub → Unity → モジュールを加えるより、Android Build Supportがインストールされてるか確認してください。

Androidモジュールは下記ディレクトリにインストールされます

Path
Windows C:\Program Files\Unity\Hub\Editor\{Unityバージョン}\Editor\Data\PlaybackEngines\AndroidPlayer\
Mac /Applications/Unity/Hub/Editor/{Unityバージョン}/PlaybackEngines/AndroidPlayer

Target API Levelの指定・インストール

Project Settingsより、Target API Levelを設定します。

デフォルトではAutomatic (highest installed)が選択されてますが、レベルを指定することを勧めます。
AutomaticはSDKパスにセットアップされてるAPI Levelに依存するため、AさんのPCは34、BさんのPCは33、ビルドマシンでは35でビルドしてしまうなどの問題が生じます。

※ 2024年11月時点、Google Playにアプリを提出する場合は34以上を指定する必要があります。

ディレクトリ{SDKパス}/platforms/より、インストール済のAPIを確認できます。

Unity Editorより、API Level 34までしかインストールされてない状態で35を指定してビルド開始した場合、 アップデート(35インストール) するかインストール済のAPIから最大レベルでビルドするか確認を求められます。

コマンドラインからインストールする場合は下記のように実行することでインストールされます。

# ディレクトリ移動
cd {SDKパス}

# API Level 35のインストール
./tools/bin/sdkmanager "platform-tools" "platforms;android-35"

Androidモジュールの容量を節約する

Unity HubよりAndroidモジュールは、各Unityバージョン毎のディレクトリに格納されます。
複数のPJに携わり、複数バージョンのUnityをインストールする場合はAndroid SDK/NDK Tools/OpenJDKを切り分けることでストレージの節約できます。

※ 複数のUnityバージョンを扱わない or ストレージに余裕があれば特に設定する必要はありません。

Unityメジャーバージョン毎にそれぞれのバージョンが異なります。

・SDK

Unity version SDK Build tools version
6000.0 34.0.0
2022.3 LTS 32.0.0
2021.3 LTS 32.0.0

・NDK

Unity version NDK version
6000.0 r23b (23.1.7779620)
2022.3 LTS r23b (23.1.7779620)
2021.3 LTS r21d (21.3.6528147)

・Open JDK

Unity version JDK version
6000.0 17 (OpenJDK version 17)
2022.3 LTS 11 (OpenJDK version 11)
2021.3 LTS 11 (OpenJDK version 11)

引用: Unity 6 Android setup

自分の場合はそれぞれのバージョン毎に命名してディレクトリを移動させ、UnityのPreferencesExternal Toolsより設定しました。

GitHubとSourcetreeの連携

GitHubからSourcetree等のGitクライアントと連携を行います。
個人的にはForkがおすすめですが、ここでは利用者が多いであろう、Sourcetreeの手順を掲載します。


Sourcetreeセットアップ

まずはSourcetreeをDL。

Bitbucketを使わない場合はスキップ。

Mercurialを利用しない場合はチェックを外して次へ。

SSHキー読み込みは一旦スキップして完了。

アカウント接続

Sourcetreeの設定 → アカウント → 追加を選択。
ホスト/認証タイプ/プロトコルを下記画像の通り変更し、アカウント接続ボタンを押下。

ブラウザが開くのでログイン & アカウントを選択。

接続されたことを確認する。

この時点で自身がアクセスできるリポジトリ一覧は確認できますが、認証を行う必要があります。

認証

SSHキーやPersonal Access Tokenを生成して認証する手段がありますが、それぞれ一定の管理コストが掛かるため、
GitHub CLI、もしくはgit-credential-managerを使って資格情報を獲得してキャッシュする手法をおすすめします。

参考: GitHub公式 - Git に GitHub の認証情報をキャッシュする


Windowsの場合はSourcetreeインストール時、gitを選択していれば一緒にインストールされます。
Macの場合はHomebrewを使って、GitHub CLIgit-credential-managerをインストールします。

Homebrewをインストールしてない場合は下記の記事を参考にしてみてください。
mii47.hateblo.jp

GitHub CLIの場合

gh auth loginコマンドを実行します。

接続先や接続プロトコルを確認されるので、それぞれGitHub.com HTTPSを選択し、ブラウザ経由でアクティベートします。

$ gh auth login

? Where do you use GitHub? GitHub.com
? What is your preferred protocol for Git operations on this host? HTTPS
? Authenticate Git with your GitHub credentials? Yes
? How would you like to authenticate GitHub CLI? Login with a web browser

! First copy your one-time code: {ワンタイムコード}
Press Enter to open https://github.com/login/device in your browser... 

git-credential-managerの場合

Sourcetree等でリポジトリのクローン/プッシュ時、ブラウザ経由で認証します。

連携完了

ここまでくれば問題なくクローン/プッシュが行えるかと思います。

TIPS

  1. 会社等のチーム開発でUnityを扱うメンバーが複数いる
  2. GitHubのプライベートリポジトリにパッケージを配置してる
  3. Unityのパッケージマネージャーでプライベートリポジトリのパッケージを参照している

の場合、メンバー間で認証方法を統一した方が良いでしょう。
認証方式がバラバラの場合、パッケージの参照エラーを起こす原因になります。

Homebrewのインストール、使い方

インストール

macLinuxで利用できるソフトウェアパッケージ管理システムです。

公式brew.shにアクセスしてコマンドをコピペ、ターミナルから実行します。

しばらく待つとインストール完了します。
インストール直後だとパスが通っておらずHomebrewコマンドを認識しないため、
Next steps に記載のechoevalから始まる3つのコマンドを1行ずつ実行します。

パスを通し、brew -vを実行してバージョンが表示されたら完了です。

パッケージインストール

brew install {パッケージ名}

アンインストール

brew uninstall {パッケージ名}

インストールしたパッケージ一覧

brew list

アップグレード

# 全てのパッケージ
brew upgrade 

# 指定のパッケージ
brew upgrade {パッケージ名}