【Mac不要】iOSとAndroidのFlutterアプリから利用者のGoogle Photosにアクセスする手順 - Codemagic編 (後編)

# はじめに

※この記事は、以下の記事の続編です。

[【Mac不要】iOSとAndroidのFlutterアプリから利用者のGoogle Photosにアクセスする手順 - Codemagic編 (前編)](https://qiita.com/kami_teru/items/8b72cbb2f4adfa10309a)

この記事ではその後、Flutterアプリから利用者のGoogle Photoにアクセスするための手順を説明します。

ただし、具体的な実装方法は [Build a Photo Sharing app with Google Photos and Flutter - Codelabs](https://codelabs.developers.google.com/codelabs/google-photos-sharing) で公開されているので、ここでは主に「Googleアカウント(Firebase認証)からの"Build a Photo Sharing app with Google Photos"」の適用手順を説明します。

では早速始めましょう。

## 前提

この記事は、以下に当てはまる人向けの iOS/Android 対応アプリにGoogle Sign-in APIを組み込む手順を紹介します。

* 開発機はWindowsだ
* **Macを持っていない**
* Flutterで開発したい
* Apple Developer Programに既に登録している。

## 開発環境の前提

以下の4本の記事の手順に沿ってFlutterアプリの作成を進めてください。

1. [【Mac不要】開発中のFlutter製アプリをiOSとAndroidに実機配備する手順 - Codemagic編](https://qiita.com/kami_teru/items/c7ed113d0ecdf7e48ff0)
1. [【Mac不要】FlutterアプリにFirebase SDKを組み込んでiOSとAndroidに実機配備する手順 - Codemagic編](https://qiita.com/kami_teru/items/d3b72f5c0aa97e6c1c08)
1. [【Mac不要】FlutterアプリにFirebase Crashlyticsを組み込んでiOSとAndroidに実機配備する手順 - Codemagic編](https://qiita.com/kami_teru/items/67e26b661167863f0b9b)
1. [【Mac不要】iOSとAndroidのFlutterアプリから利用者のGoogle Photosにアクセスする手順 - Codemagic編 (前編)](https://qiita.com/kami_teru/items/8b72cbb2f4adfa10309a)

## ソースコードの公開

この記事の手順で作成したソースコードはGithubで公開しています。併せてご参照ください。
https://github.com/atsuteru/flutter_firebase_0507/tree/Qiita-GooglePhoto-v1.2

# 本文

## APIのインタフェースを準備する

Google Photos APIを利用して新規アルバムを作成する場合、次のAPIを利用します。

[Method: albums.create - Google Photos APIs](https://developers.google.com/photos/library/reference/rest/v1/albums/create)

そこには、Requestとして必要なJsonデータの形式が記述されていますね。このJsonを組み立てるための型を準備しましょう。
その型は、Codelabsでサンプルを公開してくれているので、それをそのまま利用しちゃいましょう。

次の４つのソースコードをダウンロードしてください。
Github: [googlecodelabs/photos-sharing/lib/](https://github.com/googlecodelabs/photos-sharing/tree/master/)
* lib/photos_library_api/album.dart
* lib/photos_library_api/album.g.dart
* lib/photos_library_api/create_album_request.dart
* lib/photos_library_api/create_album_request.g.dart

これを、自身のアプリの lib/photos_library_api の下に取り込みます。

取り込んだ後、`create_album_request.dart`のimport宣言の一部を書き換えてください。

```dart:create_album_request.dart
//import 'package:sharing_codelab/photos_library_api/album.dart';
import 'album.dart';
```

## APIの認証ヘッダを準備する

Google Photos APIを利用するためには、送信するHTTPリクエストに認証ヘッダを加える必要があります。
認証ヘッダは、Googleアカウントにサインインした情報から得ることができます。

サインイン処理を、以下のように修正しましょう。

```dart:main.dart
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  FirebaseUser _currentUser;
//...(追加ココカラ)...
  Future<Map<String, String>> _authHeaders;
//...(追加ココマデ)...
  Future<bool> _handleSignIn(GoogleSignInAccount googleSignInAccount) async {
    if (googleSignInAccount == null) {
      return false;
    }
    final GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication;
    final AuthCredential credential = GoogleAuthProvider.getCredential(
      accessToken: googleSignInAuthentication.accessToken,
      idToken: googleSignInAuthentication.idToken,
    );
    final AuthResult authResult = await _auth.signInWithCredential(credential);
    final FirebaseUser user = authResult.user;
    if (user.isAnonymous) {
      return false;
    }
    if (await user.getIdToken() == null) {
      return false;
    }
    final FirebaseUser currentUser = await _auth.currentUser();
    if (user.uid != currentUser.uid) {
      return false;
    }

    setState(() {
      _currentUser = currentUser;
//...(追加ココカラ)...
      _authHeaders = googleSignInAccount.authHeaders;
//...(追加ココマデ)...
    });
    return true;
  }
}
```

## 新規アルバムを作成するためのAPI呼び出しをコーディングする

新規アルバムを作成するためのAPI呼び出しの方法は、Codelabsの手順 [(5) Create an album](https://codelabs.developers.google.com/codelabs/google-photos-sharing/#4)で紹介されています。

それを参考にコーディングすると、例えば「`Make Album`ボタンが押された際に新規アルバムを作成するメソッド」は以下のように書くことができます。
`http.post`の引数`headers`に注目。準備しておいたAPIの認証ヘッダ`_authHeaders`が指定されていますね。

```dart:main.dart
//...(中略)...
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import 'photos_library_api/album.dart';
import 'photos_library_api/create_album_request.dart';
//...(中略)...
class _MyHomePageState extends State<MyHomePage> {
//...(中略)...
  Future<void> _handleMakeAlbum() async {
    return http
        .post(
          'https://photoslibrary.googleapis.com/v1/albums',
          body: jsonEncode(CreateAlbumRequest.fromTitle("New Album")),
          headers: await _authHeaders,
        )
        .then(
          (Response response) {
            if (response.statusCode != 200) {
              Crashlytics.instance.log('album create error. reasonPhrase=${response.reasonPhrase}');
            }
            var album = Album.fromJson(jsonDecode(response.body));
            Crashlytics.instance.log('album created. albumId=${album.id}.');
          },
        );
  }
```

なお、ここまでのコーディング内容では、次のライブラリが利用されています。

* [http](https://pub.dev/packages/http)
* [json_annotation](https://pub.dev/packages/json_annotation)

これらを pubspec.yamlに追加しましょう。

```yaml:pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  firebase_core: ^0.4.4+3
  firebase_crashlytics: ^0.1.3+3
  firebase_auth: ^0.16.0
  google_sign_in: ^4.4.6
  json_annotation: ^3.0.1
  http: ^0.12.1
```

追加したら、`packages get`の実行を忘れずに。
ここまでで、ビルドが通るようになります。

## 新規アルバムを作成するボタンを配置する

サインイン後の画面に、新規アルバムを作成するボタン`Make Album`を追加しましょう。

```dart:main.dart
class _MyHomePageState extends State<MyHomePage> {
//...(中略)...
  Widget _buildGoogleSignInBody() {
    if (_currentUser != null) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          Card(
            color: Colors.lightBlueAccent,
            child: ListTile(
              leading: CircleAvatar(
                backgroundImage: NetworkImage(
                  _currentUser.photoUrl,
                ),
                radius: 30,
                backgroundColor: Colors.transparent,
              ),
              title: Text(_currentUser.displayName ?? ''),
              subtitle: Text(_currentUser.email ?? ''),
            ),
          ),
          const Text("Signed in successfully."),
          RaisedButton(
            child: const Text('SIGN OUT'),
            onPressed: _handleSignOut,
          ),
//...(追加ココカラ)...
          RaisedButton(
            child: const Text('Make album'),
            onPressed: _handleMakeAlbum,
          ),
//...(追加ココマデ)...
        ],
      );
    } else {
      return Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          const Text("You are not currently signed in."),
          RaisedButton(
            child: const Text('SIGN IN'),
            onPressed: () async{
              if (await _handleSignIn(await _googleSignIn.signIn())) {
                _handleGetContact();
              }
            }
          ),
        ],
      );
    }
  }
```

以上でコーディングは完了です。
アプリを実行し、任意のGoogleアカウントでサインインすると、次のように`Make Album`ボタンが表示されます。

<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/d4372251-45be-cdc1-ba5a-c27379813b04.jpeg">

それをタップし、サインインしたGoogleアカウントのPhotosの「アルバム」のページを表示すると・・・

![コメント 2020-06-25 224954.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109362/265cd84e-0d9f-4a1f-e28c-9292f2bc75de.png)

`New Album`という名の空のアルバムが作成されていますね！

ちなみに、さらに`Make Album`ボタンをタップすると、`New Album`という名の空のアルバムが増えていきます。
同じタイトルが付けられたアルバムですが、内部的にはAlbumIdが異なっているので、複数作られるというからくりです。

外部サービスへのアウトプットができると、いよいよアプリを作ってる！という感じになりますねっ（空のアルバム作っただけ・・・^^;

さて以上で、この記事における手順は終了ですが、この続きはCodeLabsの記事 [Build a Photo Sharing app with Google Photos and Flutter - Codelabs](https://codelabs.developers.google.com/codelabs/google-photos-sharing) を参考に進めることができます。

写真のアップロードとアルバムへの追加方法などが学習できるので、ぜひやってみてください。

# さいごに

ここまでの連載？で、Codemagicを利用してビルドしたり、GoogleやFirebaseとの連携を手作業で設定したりすれば、Macがない環境でもFlutterでクロスプラットフォームアプリの開発ができることを紹介しました。

Windowsはある、iPhoneもある。

でもMacやAndroidは持っていない。

そんな私と同じ環境の方も、ご自身のiPhoneで動作するアプリ開発を！
ここまでの連載が、そんなチャレンジのお役に立てば、幸いです。

ありがとうございました。