【Flutter】スクリーンショットをSNSにシェアする

#### 概要
Flutterで作成したアプリにシェア機能を実装した際の備忘録です。
3つのパッケージを利用することで、簡単に任意のWidgetのスクリーンショットを添付してSNSなどへシェアすることができるようになります。

下記はiOSシミュレータでサンプルコードを実行した際の挙動になります。
シミュレータのためシェア先の候補が少ないですが、TwitterやInstagramなどがインストールされている場合は、シェア先の候補として自動的に表示されるようになります。
![名称未設定.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738518/24904f8f-983a-eef0-b1b5-3fd5c5f012a1.jpeg)

#### サンプルコード
https://github.com/sakatech-jp/flutter_screenshot_share

#### 動作環境
```
$ flutter --version
Flutter 2.8.1 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 77d935af4d (8 weeks ago) • 2021-12-16 08:37:33 -0800
Engine • revision 890a5fca2e
Tools • Dart 2.15.1
```

#### 使用するパッケージ
()内は本記事で使用しているパッケージのバージョン
・ [share_plus](https://pub.dev/packages/share_plus)（3.0.4）
・ [screenshot](https://pub.dev/packages/screenshot)（1.2.3）
・ [path_provider](https://pub.dev/packages/path_provider)（2.0.9）

#### 要点

<details><summary>main.dart全文</summary><div>

```dart
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:screenshot/screenshot.dart';
import 'package:share_plus/share_plus.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _screenShotController = ScreenshotController();
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Screenshot(
      controller: _screenShotController,
      child: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'You have pushed the button this many times:',
              ),
              Text(
                '$_counter',
                style: Theme.of(context).textTheme.headline4,
              ),
              ElevatedButton(
                onPressed: () async {
                  const _shareText = 'シェアするテキスト';
                  final _screenshot = await _screenShotController.capture(delay: const Duration(milliseconds: 10));

                  if (_screenshot != null) {
                    // スクリーンショットをドキュメントディレクトリに保存
                    final _documentDirectoryPath = await getApplicationDocumentsDirectory();
                    final imagePath = await File('${_documentDirectoryPath.path}/screenshot.png').create();
                    await imagePath.writeAsBytes(_screenshot);
                    // スクリーンショットとテキストをシェア
                    await Share.shareFiles([imagePath.path], text: _shareText);
                  }
                },
                child: const Text('スクリーンショットをシェア'),
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _incrementCounter,
          tooltip: 'Increment',
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}
```

</div></details>
１. 必要なパッケージをimportします。

```dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:screenshot/screenshot.dart';
import 'package:share_plus/share_plus.dart';
```

２. ScreenshotControllerクラスのインスタンスを作成します。

```dart
// FYI: https://github.com/sakatech-jp/flutter_screenshot_share/blob/master/lib/main.dart#L36
final _screenShotController = ScreenshotController();
```

３. スクリーンショットに含めたいWidgetを`Screenshot`でWrapして、controllerに２.で宣言した`_screenShotController`を指定します。

```dart
// FYI: https://github.com/sakatech-jp/flutter_screenshot_share/blob/master/lib/main.dart#L47-L48
@override
Widget build(BuildContext context) {
  return Screenshot(
    controller: _screenShotController,
    child: Scaffold(....)
  );
}
```

４. シェア用のボタンがタップされた際の挙動を`onPressed`に定義します。

```dart
// FYI: https://github.com/sakatech-jp/flutter_screenshot_share/blob/master/lib/main.dart#L64-L79
onPressed: () async {
  const _shareText = 'シェアするテキスト';
  final _screenshot = await _screenShotController.capture(delay: const Duration(milliseconds: 10));

  if (_screenshot != null) {
    // スクリーンショットをドキュメントディレクトリに保存
    final _documentDirectoryPath = await getApplicationDocumentsDirectory();
    final imagePath = await File('${_documentDirectoryPath.path}/screenshot.png').create();
    await imagePath.writeAsBytes(_screenshot);
    // スクリーンショットとテキストをシェア
    await Share.shareFiles([imagePath.path], text: _shareText);
  }
},
```