h-1.flutter.4/lib/services/google/gmail_wrapper.dart

194 lines
No EOL
6.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Version: 1.0.0
import 'package:flutter/foundation.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:googleapis_auth/google_auth.dart';
import 'package:googleapis/gmail/v1.dart';
/// Gmail API を介した同期用メールリレー(複数アカウント対応)
///
/// P2P 通信不要なノード識別システムを提供します。
/// BCC の Gmail アドレスをノードの一意キーとして使用。
class GmailWrapper {
final String _gmailAddress; // BCC 用 gmail アドレス(ノードキー)
GAuthClient? _authClient; // OAuth 認証クライアント
final GmailService? _gmail; // Gmail API サービス
final GoogleSignIn _signIn; // GoogleSignIn インスタンス
/// 新しいインスタンスを作成
factory GmailWrapper({
required String gmailAddress,
bool useOAuth = true,
}) {
if (useOAuth) {
print('[Gmail] OAuth 認証モード。GoogleSignIn でアカウント選択を行います');
final signIn = GoogleSignIn(
scopes: [
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/calendar.readonly',
'https://www.googleapis.com/auth/drive.readonly',
'https://www.googleapis.com/auth/spreadsheets.readonly',
],
);
return GmailWrapper._internal(
gmailAddress: gmailAddress,
signIn: signIn,
);
} else {
throw UnsupportedError('OAuth 方式でのみサポートされています');
}
}
GmailWrapper._internal({
required this._gmailAddress,
required GoogleSignIn signIn,
}) : _signIn = signIn,
_authClient = null,
_gmail = null;
/// ノード IDBCC アドレス)を取得
String get gmailAddress => _gmailAddress;
/// 認証状態を確認
bool get isAuthorized => _gmail != null;
/// GoogleSignIn インスタンスを取得
GoogleSignIn get signInInstance => _signIn;
/// 現在選択中のアカウントのメールアドレスを取得
String? get currentAccountEmail => _signIn.currentUser?.email;
/// 認証された Google アカウント情報を取得(初回実行時は null
GoogleSignInAccount? get currentUser => _signIn.currentUser;
/// チャットメッセージをノードに配送する
Future<void> sendMessage({
required String fromNode,
required String message,
String? toNode,
}) async {
if (_gmail == null) return;
try {
final msg = EmailMessage(
subject: '[SalesAssist1] チャット:$fromNode',
to: toNode,
cc: null,
bcc: _gmailAddress, // BCC でノード識別
htmlBody: '<body><p>$message</p></body>',
);
final response = await _gmail.users.messages.send(
userId: 'me',
body: msg,
).root;
print('[Gmail] メッセージ送信完了 (from=$fromNode to=${toNode ?? 'BCC キー'})');
} catch (e) {
print('[Gmail] 送信失敗:$e');
rethrow;
}
}
/// ノードリストを取得(自己認識用)
Future<List<String>> getNodes() async {
// 現在接続可能なノードを返す(ハートビートの結果などから集約)
return []; // ここに母艦が管理するノードリストを読み込むロジック
}
/// OAuth 認証フローを実行(初回またはアカウント切り替え時)
Future<GoogleSignInAccount?> authenticate() async {
try {
final account = await _signIn.signIn();
if (account != null) {
print('[Gmail] 認証成功:${account.email}');
return account;
} else {
throw Exception('ユーザーが認証をキャンセルしました');
}
} catch (e) {
print('[Gmail] 認証失敗:$e');
rethrow;
}
}
/// 現在のアカウントでログアウト
Future<void> logout() async {
try {
await _signIn.signOut();
print('[Gmail] ログアウト済み');
} catch (e) {
print('[Gmail] ログアウト失敗:$e');
}
}
/// アカウント切り替え(複数アカウントを持つ場合)
Future<GoogleSignInAccount?> switchAccount() async {
try {
final account = await _signIn.signIn();
if (account != null) {
print('[Gmail] アカウント切り替え:${account.email}');
return account;
} else {
throw Exception('ユーザーが認証をキャンセルしました');
}
} catch (e) {
print('[Gmail] 切り替え失敗:$e');
rethrow;
}
}
/// Gmail API サービスインスタンスを取得・初期化
Future<void> initializeApi() async {
if (_authClient == null || _gmail != null) return;
try {
// credentials.json が存在する場合、OAuth2 認証を作成
if (await kIsWeb || defaultTargetPlatform == Android) {
// Android では credentials.json を使用せず、GoogleSignIn のトークンを使用
print('[Gmail] GoogleSignIn のアクセストークンを使用');
// GAuthClient を生成し、GmailService を初期化
final client = GAuthClient.withCredentials(
'google_sign_in_credentials.json', // 後実装SDK が生成するファイル名
);
_authClient = client;
_gmail = GmailService(client);
} else {
print('[Gmail] Web/iOS モード。GoogleSignIn で管理');
}
} catch (e) {
print('[Gmail] API 初期化失敗:$e');
rethrow;
}
}
/// アクセストークンを取得GoogleSignIn から)
Future<String?> getToken() async {
if (_signIn.currentUser == null) return null;
try {
final auth = await _signIn.authenticator;
return auth.accessToken.toString();
} catch (e) {
print('[Gmail] トークン取得失敗:$e');
return null;
}
}
}
/// メール送信用モデルGoogleapis ライブラリの仕様に従う)
class EmailMessage {
String? subject;
List<String>? to;
String? cc;
String? bcc;
String? htmlBody;
EmailMessage({
this.subject,
this.to,
this.cc,
this.bcc,
this.htmlBody,
});
}