JUCEでGoogle Drive APIを使ったクロスプラットフォームアプリを作る

## はじめに

この記事では、**JUCE**フレームワークを使ってGoogle Drive APIと連携するクロスプラットフォームアプリケーションの実装方法を解説します。よくテレビ用のアプリで見るコードを入力してアクティベートするタイプのCXです。

![IMG_9790.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107818/381aadc6-5c31-4cf3-815f-10c3fd03c7f9.jpeg)


**対応プラットフォーム：**
- 🍎 **macOS** - ネイティブで快適な動作
- 🪟 **Windows** - Visual Studio 2022対応
- 🥧 **Raspberry Pi** - ARMアーキテクチャでも完全動作

## 特徴

- ✅ **完全クロスプラットフォーム** - Mac、Windows、Raspberry Piで同一コード
- ✅ **OAuth2認証** - セキュアなGoogle Drive接続
- ✅ **ファイル同期** - ローカルストレージとクラウドの切り替え
- ✅ **モダンなUI** - JUCEによる美しいネイティブインターフェース
- ✅ **プラグイン対応** - VST/AU/AUv3対応のオーディオプラグインとしても動作

## アーキテクチャ概要

```
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   Main App      │    │  Cloud Manager   │    │ Storage Provider│
│                 │◄──►│                  │◄──►│                 │
│ - UI Components │    │ - Service Switch │    │ - Google Drive  │
│ - User Input    │    │ - Auth Manager   │    │ - Local Storage │
└─────────────────┘    └──────────────────┘    └─────────────────┘
                                │
                                ▼
                       ┌──────────────────┐
                       │  Auth Component  │
                       │                  │
                       │ - OAuth2 Flow    │
                       │ - Web Browser    │
                       └──────────────────┘
```

## 実装の核心部分

### 1. クラウドマネージャー（R2CloudManager）

全体の制御を行うメインクラスです。

```cpp
class R2CloudManager
{
public:
    enum class ServiceType
    {
        Local,
        GoogleDrive
        // 今後追加予定: iCloud, Dropbox, OneDrive
    };
    
    enum class AuthStatus
    {
        NotAuthenticated,
        Authenticating, 
        Authenticated,
        Error
    };
    
    // シンプルなファイル操作API
    void saveFile(const juce::String& filename, const juce::String& content, 
                  FileOperationCallback callback = nullptr);
    void loadFile(const juce::String& filename, FileContentCallback callback);
    
    // 認証関連
    void showAuthenticationUI(juce::Component* parentComponent);
    void selectService(ServiceType serviceType);
```

### 2. Google Drive認証（OAuth2実装）

デバイスフローを使用したセキュアな認証を実装しています。

```cpp
void R2CloudAuthComponent::startAuthentication()
{
    // 1. デバイスコードをリクエスト
    requestDeviceCode();
}

void R2CloudAuthComponent::requestDeviceCode()
{
    juce::String postData = "client_id=" + googleClientId;
    postData += "&scope=https://www.googleapis.com/auth/drive.file";
    
    makeHttpRequest("https://oauth2.googleapis.com/device/code", postData,
        [this](bool success, juce::String response, int statusCode) {
            parseDeviceCodeResponse(response);
        });
}
```

### 3. クロスプラットフォーム対応のポイント

**WebBrowserComponent**を使用してOAuth認証画面を表示：

```cpp
// JUCE 8の新しいAPIを使用
juce::WebBrowserComponent::Options options;
options = options.withNativeIntegrationEnabled(true);

// JavaScript関数を登録して認証完了を検知
options = options.withNativeFunction("authComplete",
    [this](const juce::Array<juce::var>& args, auto completion) {
        handleAuthSuccess(args[0].toString());
        completion(juce::var());
    });

webBrowser = std::make_unique<juce::WebBrowserComponent>(options);
```

## セットアップ手順

### 1. プロジェクトのクローンと認証情報設定

```bash
# プロジェクトをクローン
git clone https://github.com/your-repo/r2juce-clouddoc.git
cd r2juce-clouddoc

# 認証情報ファイルを準備
cp Source/Credentials_template.h Source/Credentials.h
```

### 2. Google Cloud Console設定

#### 2-1. プロジェクト作成
1. [Google Cloud Console](https://console.cloud.google.com/)にアクセス
2. 新しいプロジェクトを作成
3. **Google Drive API**を有効化

#### 2-2. OAuth同意画面の設定
```
APIs & Services > OAuth consent screen
├── User Type: External
├── App name: CloudDoc Desktop Client
├── User support email: your-email@example.com
└── Test users: 自分のアカウントを追加
```

#### 2-3. OAuth 2.0認証情報の作成
```
APIs & Services > Credentials > Create Credentials > OAuth 2.0 Client ID
├── Application type: Desktop application  
├── Name: CloudDoc Desktop Client
└── Download JSON (後で使用)
```

### 3. 認証情報をコードに設定

生成されたClient IDとClient Secretを`Credentials.h`に設定：

```cpp
// Source/Credentials.h
#define GOOGLE_CLIENT_ID "123456789012-abcdefg...xyz.apps.googleusercontent.com"
#define GOOGLE_CLIENT_SECRET "GOCSPX-AbCdEfGhIjKlMnOpQrSt..."
```

#### 📝 認証情報の取得例
Google Cloud Consoleで生成された認証情報は以下のような形式です：

```json
{
  "client_id": "123456789012-abcdefghijklmnopqrstuvwxyz123456.apps.googleusercontent.com",
  "client_secret": "GOCSPX-AbCdEfGhIjKlMnOpQrStUvWxYz123"
}
```

これを`Credentials.h`の対応する箇所に貼り付けてください。

> ⚠️ **重要**: `Credentials.h`は`.gitignore`に含まれており、リポジトリにコミットされません。各開発者が個別に設定する必要があります。

## ビルドと実行

### 事前準備
1. **JUCE Framework**をインストール（バージョン7.0以上推奨）
2. 各プラットフォームの開発環境を準備

### macOS
```bash
cd Builds/MacOSX
# Xcodeプロジェクトをビルド
xcodebuild -project CloudDoc.xcodeproj -configuration Release
# または、Xcodeで直接開いてビルド
open CloudDoc.xcodeproj
```

### Windows (Visual Studio 2022)
```bash
cd Builds\VisualStudio2022
# コマンドラインでビルド
MSBuild CloudDoc.sln /p:Configuration=Release /p:Platform=x64
# または、Visual Studioで直接開いてビルド
```

### Raspberry Pi (Linux)
```bash
cd Builds/LinuxMakefile
# 依存関係のインストール（Debian/Ubuntu）
sudo apt-get update
sudo apt-get install build-essential libasound2-dev libjack-jackd2-dev \
    ladspa-sdk libcurl4-openssl-dev libfreetype6-dev libx11-dev \
    libxcomposite-dev libxcursor-dev libxext-dev libxinerama-dev \
    libxrandr-dev libxrender-dev libwebkit2gtk-4.0-dev libglu1-mesa-dev

# ビルド実行
make CONFIG=Release
```

### ビルドが成功すると...
- **macOS**: `Builds/MacOSX/build/Release/CloudDoc.app`
- **Windows**: `Builds/VisualStudio2022/x64/Release/App/CloudDoc.exe`  
- **Raspberry Pi**: `Builds/LinuxMakefile/build/CloudDoc`

## 使用方法

### 1. 基本的な使い方

```cpp
// CloudManagerの初期化
cloudManager = std::make_unique<r2juce::R2CloudManager>();
cloudManager->setGoogleCredentials(CLIENT_ID, CLIENT_SECRET);

// コールバック設定
cloudManager->onAuthStatusChanged = [this](auto status) {
    handleAuthStatusChanged(status);
};

// Google Driveサービスを選択
cloudManager->selectService(r2juce::R2CloudManager::ServiceType::GoogleDrive);

// 認証が必要な場合は認証UIを表示
if (cloudManager->needsAuthentication()) {
    cloudManager->showAuthenticationUI(this);
}
```

### 2. ファイル操作

```cpp
// ファイル保存
cloudManager->saveFile("document.txt", "Hello World!", 
    [](bool success, juce::String error) {
        if (success) {
            DBG("File saved successfully!");
        }
    });

// ファイル読み込み
cloudManager->loadFile("document.txt", 
    [](bool success, juce::String content, juce::String error) {
        if (success) {
            DBG("File content: " + content);
        }
    });
```

## 技術的なハイライト

### 1. **プロバイダーパターン**
ローカルストレージとクラウドストレージを統一インターフェースで操作：

```cpp
class R2CloudStorageProvider {
public:
    virtual void uploadFile(const juce::String& fileName, 
                           const juce::MemoryBlock& data,
                           const juce::String& folderId, 
                           FileOperationCallback callback) = 0;
    // ...
};
```

### 2. **非同期処理**
すべてのネットワーク操作は非同期で実行し、UIをブロックしません：

```cpp
juce::Thread::launch([this, url, callback]() {
    auto stream = url.createInputStream(options);
    auto response = stream->readEntireStreamAsString();
    
    juce::MessageManager::callAsync([callback, response]() {
        callback(true, response);
    });
});
```

### 3. **トークン管理**
アクセストークンとリフレッシュトークンを安全に保存・管理：

```cpp
void R2GoogleDriveProvider::saveTokens() {
    auto tokenFile = getTokenFile();
    juce::DynamicObject::Ptr tokenData = new juce::DynamicObject();
    tokenData->setProperty("access_token", accessToken);
    tokenData->setProperty("refresh_token", refreshToken);
    tokenData->setProperty("token_expiry", tokenExpiry.toMilliseconds());
    
    auto json = juce::JSON::toString(juce::var(tokenData.get()));
    tokenFile.replaceWithText(json);
}
```

## ライブラリ構成

本実装は再利用可能なライブラリとして設計されています：

```
r2juce/
├── R2CloudManager.h/.cpp          # メイン管理クラス
├── R2CloudStorageProvider.h       # 抽象基底クラス  
├── R2GoogleDriveProvider.h/.cpp   # Google Drive実装
├── R2LocalStorageProvider.h/.cpp  # ローカルストレージ実装
├── R2CloudAuthComponent.h/.cpp    # 認証UI
└── R2TextEditor.h/.cpp            # カスタムテキストエディタ
```

## 今後の拡張予定

- 🔄 **Dropbox API対応**
- ☁️ **OneDrive API対応**  
- 🍎 **iCloud Drive対応**
- 📁 **フォルダ階層サポート**
- 🔍 **ファイル検索機能**
- 📊 **同期状態の可視化**

## まとめ

JUCEフレームワークを使用することで、**一つのコードベース**でMac、Windows、Raspberry Piすべてで動作するGoogle Drive連携アプリが実現できました。

**🎯 特に注目すべきポイント：**

1. **完全なクロスプラットフォーム対応** - ビルド設定を変えるだけで各OSのネイティブアプリに
2. **モダンなOAuth2実装** - セキュリティベストプラクティスに準拠
3. **プラグイン対応** - VST/AUプラグインとしても動作可能
4. **拡張性の高い設計** - 新しいクラウドサービスの追加が容易

**🚀 ぜひお試しください！**

完全なソースコードは[GitHubリポジトリ](https://github.com/masanaohayashi/R2JUCE)で公開中です。

### 🚀 クイックスタート
```bash
# 1. リポジトリをクローン
git clone https://github.com/masanaohayashi/R2JUCE.git
cd R2JUCE/examples/CloudDoc

# 2. 認証情報を設定
cp Source/Credentials_template.h Source/Credentials.h
# Credentials.hを編集してGoogle認証情報を設定

# 3. Dockerを使ってRaspberry Pi用にビルド
cd Docker/raspi
./build.sh Release
```

---

### 参考リンク

- [JUCE Framework](https://juce.com/)
- [Google Drive API Documentation](https://developers.google.com/drive/api)
- [OAuth 2.0 Device Authorization Grant](https://tools.ietf.org/html/rfc8628)