🎥

【Dart/Flutter】twitter_api_v2でメディアファイルを簡単にアップロードする方法

2022/10/31に公開

twitter_api_v2でメディアファイルを簡単にアップロードする方法

概要

Twitterで面白い画像や動画を共有するのは楽しいですよね。

twitter_api_v2で、このメディアファイルを簡単にアップロードできる機能をサポートしましたので、この記事ではその実装方法を紹介していきます。メディアをアップロードする際の難しい処理は全てカプセル化され、とても簡単に扱えるように設計・実装されていますのでぜひ使ってみてください。

ただし、公式のTwitter API v2.0ではまだv2エンドポイントとしてメディアのアップロードをサポートしておらず、twitter_api_v2では例外的にv1.1エンドポイントを使用しています。

そのため、将来的に公式でv2エンドポイントとしてメディアのアップロードがサポートされた場合には、引数の変更やレスポンス情報に変更が加わる可能性がある点に注意してください。

twitter_api_v2とは

twitter_api_v2とは、DartFlutterで使用できるTwitter API v2.0をラッピングしたライブラリです。全てのエンドポイントやリクエストパラメータをサポートしているだけではなく、直感的なインターフェースや自動リトライなど、DartとFlutterでTwitter API v2.0を使用した開発を強力にサポートします。

https://github.com/twitter-dart/twitter-api-v2

https://pub.dev/packages/twitter_api_v2

このライブラリについては以前からいくつか記事を書いていますので、以下のリンクを参考にしてください。

https://zenn.dev/kato_shinya/articles/released-twitter-api-v2-dart

https://zenn.dev/kato_shinya/articles/twitter-api-v2-is-listed-in-twitter-official

ライブラリのインストール

まずは、DartまたはFlutterでお馴染みの以下のコマンドを実行してライブラリをインストールします。

Dartの場合:

dart pub add twitter_api_v2

Flutterの場合:

flutter pub add twitter_api_v2

また、必要に応じて以下のコマンドを実行しましょう。

Dartの場合:

dart pub get

Flutterの場合:

flutter pub get

メディアをアップロードする際の選択肢

さて、ここまでの工程でtwitter_api_v2のインストールが完了しました。

twitter_api_v2を使用してメディアをアップロードするためには、用途に合わせて以下の2つの選択肢があります。

メソッド名 説明
uploadImage 容量が5MBまでの画像とGIF画像のみをアップロードできます。ただし、公式のリファレンスにも記載されているとおり、容量の少ない画像ファイルのアップロードについても下記のuploadMediaを使用することが好ましいです。
uploadMedia 大容量の画像、GIF画像、動画をアップロードできます。容量が大きいメディアファイルについては内部の処理で適切な容量にファイルを分割し、その分割したメディアファイルを安全にアップロードします。また、容量が大きいファイルについてはアップロードが完了するまでに時間がかかるため、定期的にTwitterのサーバーに対してポーリングを行い、アップロードのステータスを簡単に確認できる仕様もサポートしています。

上記の2つのメソッドについて順番に説明していきます。

uploadImageから画像をアップロード

先に紹介したように、uploadImageからは5MBまでの画像とGIF画像をアップロードできます。使い方はとても簡単で、uploadImageにアップロードしたい画像ファイルを表すFileオブジェクトを渡すだけです。

import 'dart:io';

import 'package:twitter_api_v2/twitter_api_v2.dart';

Future<void> main() async {
  final twitter = TwitterApi(
    // メディアのアップロードはv1.1エンドポイントを使用しているため、
    // OAuth 2.0 のアクセストークンは必要ありません。
    bearerToken: 'NO_NEED_OAUTH2_AUTHORIZATION',

    // その代わりに、OAuth 1.0a のアクセストークンは指定が必須です。
    oauthTokens: OAuthTokens(
      consumerKey: 'YOUR_CONSUMER_KEY',
      consumerSecret: 'YOUR_CONSUMER_SECRET',
      accessToken: 'YOUR_ACCESS_TOKEN',
      accessTokenSecret: 'YOUR_ACCESS_TOKEN_SECRET',
    ),
  );

  try {
    // uploadImageメソッドにアップロードしたい画像ファイルのオブジェクトを渡してください。
    //
    // アップロードが完了するとアップロードファイルの情報が格納されたオブジェクトが返却されます。
    final uploadedMedia = await twitter.media.uploadImage(
      file: File.fromUri(
        Uri.file('funny_image.png'),
      ),
    );

    print(uploadedMedia);
  } on TwitterUploadException catch (e) {
    print(e);
  }
}

このサンプルコードを実行すると以下の出力を得られます。

TwitterResponse(rateLimit: RateLimit(limitCount: 415, remainingCount: 414, resetAt: 2022-10-31 10:41:12.000), data: UploadedMediaData(id: 1586880937216061440, expiresAt: 2022-11-01 09:41:13.427949), includes: null, meta: null)

TwitterResponsedataフィールドにアップロードしたメディアのIDがありますので、このIDを使用してツイートをすることで画像つきのツイートを作成することができます。

上記のとおり使い方はとても簡単ですが、上記のサンプルコードのコメントにもあるように、メディアのアップロードはv1.1エンドポイントを使用しているため、OAuth 2.0のトークンではなく、OAuth 1.0aのトークンが必須になりますので注意してください。

uploadMediaから画像をアップロード

さて、先に紹介したuploadImageを使用することでも画像ファイルのアップロードは可能ですが、このメソッドからは大容量の画像ファイルや動画ファイルをアップロードすることはできません。

これらの容量の大きいメディアファイルをアップロードするためには、uploadMediaを使用する必要があります。ただ、メソッドの使い方はuploadImageと基本的には同じであり、アップロードしたい画像や動画を表すFileオブジェクトを引数として渡すだけです。

import 'dart:io';

import 'package:twitter_api_v2/twitter_api_v2.dart';

Future<void> main() async {
  final twitter = TwitterApi(
    // メディアのアップロードはv1.1エンドポイントを使用しているため、
    // OAuth 2.0 のアクセストークンは必要ありません。
    bearerToken: 'NO_NEED_OAUTH2_AUTHORIZATION',

    // その代わりに、OAuth 1.0a のアクセストークンは指定が必須です。
    oauthTokens: OAuthTokens(
      consumerKey: 'YOUR_CONSUMER_KEY',
      consumerSecret: 'YOUR_CONSUMER_SECRET',
      accessToken: 'YOUR_ACCESS_TOKEN',
      accessTokenSecret: 'YOUR_ACCESS_TOKEN_SECRET',
    ),
  );

  try {
    final uploadedMedia = await twitter.media.uploadMedia(
      file: File.fromUri(
        Uri.file('funny_video.mp4'),
      ),

      // アップロードの完了までに時間がかかる場合、
      // onProgressコールバックからアップロードの進捗を確認できます。
      //
      // ステータスは以下の順番で遷移します。
      // 1. UploadState.preparing
      // 2. UploadState.inProgress
      // 3. UploadState.completed
      onProgress: (event) {
        switch (event.state) {
          case UploadState.preparing:
            print('Upload is preparing...');
            break;
          case UploadState.inProgress:
            print('${event.progress}% completed...');
            break;
          case UploadState.completed:
            print('Upload has completed!');
            break;
        }
      },

      // メディアのアップロードに失敗した場合に呼ばれるコールバック関数です。
      onFailed: (error) => print('Upload failed. Due to "${error.message}"'),
    );

    print(uploadedMedia);
  } on TwitterUploadException catch (e) {
    print(e);
  }
}

上記のサンプルコードを実行すると以下の出力を得られます。

TwitterResponse(rateLimit: RateLimit(limitCount: 200, remainingCount: 198, resetAt: 2022-10-31 11:25:41.000), data: UploadedMediaData(id: 1586893070288945152, expiresAt: 2022-11-01 10:32:13.449770), includes: null, meta: null)

また、uploadImageとは異なる点として、onProgressコールバックを使用することで、メディアアップロードの進捗状況を確認することができます。例えば、上記のサンプルコードから容量の大きい動画ファイルをアップロードした場合には、アップロードの進捗を以下のように得られます。これはFlutterアプリで動画ファイルのアップロード状況をポップアップ等でユーザーに示す際に便利です。

Upload is preparing...
5% completed...
5% completed...
5% completed...
5% completed...
5% completed...
5% completed...
5% completed...
5% completed...
5% completed...
5% completed...
20% completed...
20% completed...
20% completed...
46% completed...
73% completed...
Upload has completed!

このアップロードの進捗について、ステータスは以下のとおりに遷移します。

ステータス 説明
1 UploadState.preparing アップロードが開始したことを示します。onProgressコールバックが指定された場合には、アップロード処理の開始時に必ず発生します。
2 UploadState.inProgress アップロードが進行中であることを示します。アップロードの完了までに時間を要する場合には、Twitterのサーバーに対してポーリングを行うたたびにこのステータスでのイベントが発生します。進捗状況はパーセントで表され、UploadEvent.progressから値を取得できます。ただし、容量が大きくなくTwitterサーバーに対する進捗状況のポーリングが不要な場合には、このイベントは発生せず次のUploadState.completedに遷移します。
3 UploadState.completed アップロードが正常に完了したことを示します。onProgressコールバックが指定された場合には、アップロード処理の完了時に必ず発生します。

さらに、onFailedコールバック関数を指定することで、メディアのアップロードに失敗した際の情報を取得することができます。ただし、onFailedコールバック関数を指定した場合でも、アップロード処理の失敗時にはTwitterUploadExceptionが投げられる点に注意してください。

また、uploadMediaではTwitterへメディアをアップロードする際に発生しがちな瑣末なエラーは発生しないように処理が設計されています。ただ、以下の場合には必ずTwitterUploadExceptionが投げられますので、実装時にはご注意ください。

  • メディアファイルが破損している(外部システムからダウンロード途中等)。
  • 動画ファイルの再生時間が2分20秒を超えている。
  • Twitterでサポートされていないメディアフォーマット。

その他

アップロードしたメディアを使用してツイート

アップロードしたメディアデータは以下の方法で簡単にツイートに添付することができます。

import 'dart:io';

import 'package:twitter_api_v2/twitter_api_v2.dart';

Future<void> main() async {
  final twitter = TwitterApi(
    bearerToken: 'YOUR_BEARER_TOKEN',
    oauthTokens: OAuthTokens(
      consumerKey: 'YOUR_CONSUMER_KEY',
      consumerSecret: 'YOUR_CONSUMER_SECRET',
      accessToken: 'YOUR_ACCESS_TOKEN',
      accessTokenSecret: 'YOUR_ACCESS_TOKEN_SECRET',
    ),
  );

  try {
    final uploadedMedia = await twitter.media.uploadMedia(
      file: File.fromUri(
        Uri.file('funny_movie.mp4'),
      ),
      onProgress: (event) {
        switch (event.state) {
          case UploadState.preparing:
            print('Upload is preparing...');
            break;
          case UploadState.inProgress:
            print('${event.progress}% completed...');
            break;
          case UploadState.completed:
            print('Upload has completed!');
            break;
        }
      },
      onFailed: (error) => print('Upload failed. Due to "${error.message}"'),
    );

    await twitter.tweets.createTweet(
      text: 'Tweet with media!',
      media: TweetMediaParam(
        mediaIds: [
          uploadedMedia.data.id,
        ],
      ),
    );
  } on TwitterUploadException catch (e) {
    print(e);
  }
}

twitter_api_v2を使用してメディアを添付したツイートの作成方法は過去に以下の記事を書いていますので参考にしてください。

https://zenn.dev/kato_shinya/articles/how-to-create-media-tweet-with-twitter-api-v2-dart

アップロードしたメディアの使用可能ユーザーを追加

uploadImageuploadMediaを使用してアップロードしたメディアは、基本的にアップロードを実施した認証ユーザーだけがツイート等で使用することができます。

しかし、uploadImageuploadMediaの引数であるadditionalOwnersにユーザーIDの配列を渡すことで、アップロードしたメディアファイルを使用できるユーザーを追加することができます。

import 'dart:io';

import 'package:twitter_api_v2/twitter_api_v2.dart';

Future<void> main() async {
  final twitter = TwitterApi(
    // メディアのアップロードはv1.1エンドポイントを使用しているため、
    // OAuth 2.0 のアクセストークンは必要ありません。
    bearerToken: 'NO_NEED_OAUTH2_AUTHORIZATION',

    // その代わりに、OAuth 1.0a のアクセストークンは指定が必須です。
    oauthTokens: OAuthTokens(
      consumerKey: 'YOUR_CONSUMER_KEY',
      consumerSecret: 'YOUR_CONSUMER_SECRET',
      accessToken: 'YOUR_ACCESS_TOKEN',
      accessTokenSecret: 'YOUR_ACCESS_TOKEN_SECRET',
    ),
  );

  try {
    final uploadedMedia = await twitter.media.uploadMedia(
      file: File.fromUri(
        Uri.file('funny_video.mp4'),
      ),

      // メディアファイルの使用可能ユーザーを追加。
      additionalOwners: ['11111', '22222'],
    );

    print(uploadedMedia);
  } on TwitterUploadException catch (e) {
    print(e);
  }
}

アップロードするメディアにAltテキストを追加

Twitterではアップロードしたメディアに280文字を超える説明文をAltテキストとして登録することができます。

twitter_api_v2でもこの仕様をサポートしており、uploadImageuploadMediaの引数であるaltTextに任意の文字列を指定することで、メディアのアップロード時にAltテキストを登録可能です。

import 'dart:io';

import 'package:twitter_api_v2/twitter_api_v2.dart';

Future<void> main() async {
  final twitter = TwitterApi(
    bearerToken: 'NO_NEED_OAUTH2_AUTHORIZATION',
    oauthTokens: OAuthTokens(
      consumerKey: 'YOUR_CONSUMER_KEY',
      consumerSecret: 'YOUR_CONSUMER_SECRET',
      accessToken: 'YOUR_ACCESS_TOKEN',
      accessTokenSecret: 'YOUR_ACCESS_TOKEN_SECRET',
    ),
  );

  try {
    final uploadedMedia = await twitter.media.uploadMedia(
      file: File.fromUri(
        Uri.file('funny_movie.mp4'),
      ),

      // Altテキストを登録するためにはこの引数を指定してください。
      altText: 'This is alt text!',
    );

    print(uploadedMedia);
  } on TwitterUploadException catch (e) {
    print(e);
  }
}

まとめ

簡単な説明でしたが、以上がtwitter_api_v2でメディアをアップロードする方法になります。

uploadImageよりもuploadMediaのエンドポイントほうが好ましいと公式のリファレンスにも書かれていますが、これはケースバイケースだと思いますので状況に応じて好きなほうを使用していただいて構いません。なにより、容量の少ない画像ファイルであれば、余計な処理が実行されないだけuploadImageのほうが圧倒的に高速に動作します。

また、twitter_api_v2は他にも多くのエンドポイントをサポートしていますので、Twitter API v2.0を使用したアプリケーションを作成する際にはぜひ使用してください。

貢献者の募集

twitter_api_v2オープンソースですのでどのような方でも開発に貢献することができます。開発リポジトリの公用語は英語にしていますが、日本人の方々も大歓迎ですのでお気軽にIssuePull Requestを作成してください。

また、このライブラリが役に立った場合にGitHub の開発リポジトリスターを付けることや、Pub.devいいねを付けることもよろしくお願いします!これはtwitter_api_v2の開発コミュニティを活性化するためにとても大きな意味があります。

もしなにか疑問がある場合は開発リポジトリのディスカッションにでもスレッドを立てていただければと思います。

https://github.com/twitter-dart/twitter-api-v2

https://pub.dev/packages/twitter_api_v2

スポンサーの募集

オープンソース開発をサポートしてくださるスポンサーを募集しています。少額($1)からの寄付も可能ですので、以下のリンクから是非ご支援ください。

https://github.com/sponsors/myconsciousness

また、この記事にバッジを贈っていただくことでも支援は可能です。

GitHubで編集を提案

Discussion