🥘

share_plusを使用して画像をシェアしたい

2023/09/24に公開

Overview

Flutterで画像をシェアする機能をつけるには、シェアプラスというパッケージを使います。
https://pub.dev/packages/share_plus

こちらのパッケージですが、バージョンアップして破壊的変更があったようです😱
検索して出てくる情報は古いので参考にならずYouTubeの動画とサンプルコードで勉強しました。

Qiitaの記事
https://qiita.com/hmatsu47/items/f0d2e0ca4854862e1357

海外のYouTube動画
こちらのサンプルコード参考になりました。Image.networkの画像をシェアするときは、httpパッケージが必要みたいです。
https://www.youtube.com/watch?v=Gy1by7rKdME

summary

今回は、Flutterプロジェクトに作成したassetsディレクトリに配置したimage.pngという画像を他の人や自分のMacにシェアする機能を実装してみようと思います。

画像を配置したら、pubspec.yamlで設定して読み込めるようにします。

assets:
    - assets/image.png
  #   - images/a_dot_ham.jpeg

画像をシェアする機能を作ってみましょう。配置した画像をシェアする単純な機能ですが結構ハマったので、意外と難しかったですね。公式のREADMEを見ただけではわからなかったです😅

photo_page.dartというファイルを作成してください。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:share_plus/share_plus.dart';

class PhotoPage extends StatefulWidget {
  const PhotoPage({Key? key}) : super(key: key);

  
  State<PhotoPage> createState() => _PhotoPageState();
}

class _PhotoPageState extends State<PhotoPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Flutter Sharing"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // assetsフォルダから、画像をシェアする。
            ElevatedButton(
              onPressed: () async {
                // 画像を取得する。
                final image = await rootBundle.load('assets/image.png');// rootBundle.load()で、assetsフォルダから画像を取得する。
                // 画像をバッファに格納する。
                final buffer = image.buffer;// image.bufferで、画像をバッファに格納する。
                // 画像をシェアする。
                Share.shareXFiles(
                  [
                    XFile.fromData(// XFile.fromDataの引数には、Uint8List型のデータを渡す。
                      buffer.asUint8List(// buffer.asUint8List()で、Uint8List型のデータを取得する。
                        image.offsetInBytes,// image.offsetInBytesで、画像のバイトオフセットを取得する。
                        image.lengthInBytes,// image.lengthInBytesで、画像のバイト長を取得する。
                      ),
                      name: 'Photo.png',
                      mimeType: 'image/png',
                    ),
                  ],
                  subject: 'Flutter Logo',
                );
              },
              child: const Text('assetsフォルダから、画像をシェアする。'),
            ),
          ],
        ),
      ),
    );
  }
}

main.dartでimportして実行してみましょう。私の場合は実機のiPhoneでやらないと上手くいかなかった?

import 'package:flutter/material.dart';
import 'package:widget_catalogue/photo_page.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: PhotoPage(),
    );
  }
}

実行結果

ボタンを押して画像をシェアしてみよう。

今回は自分のMacにpng画像を送ってみる。

おおお!、シェアできたようです!

もし、ネットワーク画像をシェアしたい場合は、httpパッケージが必要なので追加して機能を実装します。今回はハードコードディングですが、FlutterのマスコットキャラクターのDashくんをシェアする機能を作りました。

コードを修正

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:share_plus/share_plus.dart';
import 'package:http/http.dart' as http;

class PhotoPage extends StatefulWidget {
  const PhotoPage({Key? key}) : super(key: key);

  
  State<PhotoPage> createState() => _PhotoPageState();
}

class _PhotoPageState extends State<PhotoPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Flutter Sharing"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // assetsフォルダから、画像をシェアする。
            ElevatedButton(
              onPressed: () async {
                // 画像を取得する。
                final image = await rootBundle.load(
                    'assets/image.png'); // rootBundle.load()で、assetsフォルダから画像を取得する。
                // 画像をバッファに格納する。
                final buffer = image.buffer; // image.bufferで、画像をバッファに格納する。
                // 画像をシェアする。
                Share.shareXFiles(
                  [
                    XFile.fromData(
                      // XFile.fromDataの引数には、Uint8List型のデータを渡す。
                      buffer.asUint8List(
                        // buffer.asUint8List()で、Uint8List型のデータを取得する。
                        image
                            .offsetInBytes, // image.offsetInBytesで、画像のバイトオフセットを取得する。
                        image
                            .lengthInBytes, // image.lengthInBytesで、画像のバイト長を取得する。
                      ),
                      name: 'Photo.png',
                      mimeType: 'image/png',
                    ),
                  ],
                  subject: 'Flutter Logo',
                );
              },
              child: const Text('assetsフォルダから、画像をシェアする。'),
            ),
            // インターネットのFluttetの画像をシェアする。
            ElevatedButton(
              onPressed: () async {
                // httpを使用してDashの画像をシェアする。
                const imageNetwork =
                    'https://upload.wikimedia.org/wikipedia/commons/4/4f/Dash%2C_the_mascot_of_the_Dart_programming_language.png';
                final url = Uri.parse(imageNetwork);
                final response = await http.get(url);
                Share.shareXFiles([
                  XFile.fromData(
                    response.bodyBytes,
                    name: 'Dash.png',
                    mimeType: 'image/png',
                  ),
                ], subject: 'Flutter 3');
              },
              child: const Text('インターネットのFluttetの画像をシェアする。'),
            ),
          ],
        ),
      ),
    );
  }
}

こんな感じで、MacにDashくんをシェアできました🙌

thoughts

今回ハマったのは、新しい書き方の情報が少ないことと画像のデータを扱うのに専門的な知識が求めら得ることでした。

こちらのサイト参考になりそうだったのでリンクを載せておきます。
https://zenn.dev/kgsi/articles/cf1e7c52a3a3ca

オフセットについて

この辺は専門外なので詳しい解説やChatGPTを使って調べました。
https://ja.wikipedia.org/wiki/オフセット_(コンピュータ)

バイトオフセット(Byte Offset)は、データ構造やファイル、メモリブロックの先頭から特定の位置(要素やバイト)までの距離をバイト単位で示したものです。この概念は、特定の位置にランダムアクセスする際によく用いられます。

例えば、ファイルや配列、リストなどがあり、その先頭をオフセット0とした場合、オフセット5は先頭から5バイト目の位置を指します。このオフセット情報を用いて、特定のデータに素早くアクセスできます。

いくつかの使用例:

  1. ファイル操作: ファイル内の特定の位置にジャンプしてデータを読み書きする場合、バイトオフセットが使われます。

  2. メモリ管理: プログラムがRAM内でデータを管理する際、特定のメモリアドレスからオフセットを加算してデータの正確な位置を見つけます。

  3. データ構造: 配列やバッファなどのデータ構造で、特定の要素にアクセスする際にそのオフセットが使用されます。

  4. ネットワークプロトコル: パケットの各部分(ヘッダ、ペイロードなど)がどこから始まるかを示すために、オフセットがしばしば用いられます。

  5. データベース: レコードに直接アクセスするために、オフセットが用いられることもあります。

このように、バイトオフセットは多くのコンピューティングの文脈で用いられる基本的な概念です。

Discussion