LoginSignup
18
13

More than 5 years have passed since last update.

FlutterでTwitterにツイートを投稿する

Last updated at Posted at 2018-05-08

こんなのを作る

And
iOS

Androidの方はintentでTwitterアプリに飛ばしてツイート、iOSはTwitterKitのサポート終了の件もあるのでUIActivityViewControllerを使ってツイートするようにしました。

デザインも一応AndroidとiOSで少し変えてみてます。

どうやってやるのか

タイトルに「Flutterで」と書きましたが、実はツイートの部分はFlutterのPlatform Channelsというものを使っていて、実装自体はそれぞれMainActivity/AppDelegateに書いています。

なので半分Platform Channelsの使い方を説明する記事になります。
Platform Channelsの実装方法については公式にも書いてあるのでそちらを読んでいただくとよりわかりやすいです。
Writing custom platform-specific code with platform channels

本題

流れとしては、

  1. MethodChannelというものを使って各プラットフォームと連携できるチャネルを作り、
  2. 各プラットフォーム側でチャネル経由でメソッドが呼ばれた時の準備をしておいて、
  3. Flutter側からチャネル経由でメソッドをinvokeする

感じになります。
それぞれ詳しく解説していきます。

MethodChannelの作成

MethodChannelというものを使って各プラットフォームと連携できるチャネルを作り、

これは簡単で、MethodChannelのインスタンスを作っておくだけです。

static const channel = const MethodChannel('com.kitoko552.flutter_post_tweet_example/tweet');

com.kitoko552.flutter_post_tweet_example/tweetの部分はなんでもよくて、私はiOS出身なのでDispatchQueueのラベルと同じような感じかなと考えて上のような文字列を付与しましたが、これがベストプラクティスかはわかりません🤔

公式にも「we recommend prefixing the channel name with a unique ‘domain prefix’」と書いてあるのでそんなに間違ってはいないはずです。

各プラットフォーム側の準備

各プラットフォーム側でチャネル経由でメソッドが呼ばれた時の準備をしておいて、

これはAndroidならMainActivity、iOSならAppDelegateにそれぞれ実装することになります。
ただどちらもやることはツイートを行う部分以外は一緒で、特定のMethodChannelを監視して、メソッドがinvokeされた時にツイートする処理を走らせるようにするだけです。

Android

Androidはこんな感じになりました。
上にも書きましたが、私は元々iOSエンジニアでAndroidは軽く触ったことがある程度なのでほぼ公式のコードをコピペしていて、Twitterを開く処理はこちらを参考に書きました。

android/app/src/main/java/com/example/flutterposttweetexample/MainActivity.java
public class MainActivity extends FlutterActivity {
  private static final String CHANNEL = "com.kitoko552.flutter_post_tweet_example/tweet";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);

    new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
            new MethodCallHandler() {
              @Override
              public void onMethodCall(MethodCall methodCall, Result result) {
                if (methodCall.method.equals("tweet")) {
                  openTwitter();
                } else {
                  result.notImplemented();
                }
              }
            }
    );
  }

  private void openTwitter() {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    String message= Uri.encode("This tweet is posted on Flutter app!");
    intent.setData(Uri.parse("twitter://post?message=" + message));
    startActivity(intent);
  }
}

ちなみにプロジェクトディレクトリ配下にandroidというディレクトリがあるので、そこから辿っていけばMainActivity.javaに辿りつけます。

iOS

iOSはこんな感じになりました。
iOSは得意や任せろと思ってworkspaceを開いたらObjective-Cでびっくりしましたが、私がFlutterのプロジェクトを作る時に設定しなかっただけっぽいのでご安心を。
設定すればSwiftで作られるはずです。
今回は途中でSwiftに変えるのが面倒だったのと、何かよくわからないエラーが起きるのが嫌だったのでObjcのまま書きました(Objc久しぶりに書いたので不備があったらすみません🙇)。

ios/Runner/AppDelegate.m
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [GeneratedPluginRegistrant registerWithRegistry:self];

    FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
    FlutterMethodChannel* channel = [FlutterMethodChannel
                                            methodChannelWithName:@"com.kitoko552.flutter_post_tweet_example/tweet"
                                            binaryMessenger:controller];

    __weak AppDelegate* wself = self;
    [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
        if ([call.method isEqualToString:@"tweet"]) {
            [wself openActivity];
        } else {
            result(FlutterMethodNotImplemented);
        }
    }];

    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (void)openActivity {
    UIActivityViewController* controller = [[UIActivityViewController alloc] initWithActivityItems:@[@"This tweet is posted on Flutter app!"] applicationActivities:NULL];
    [self.window.rootViewController presentViewController:controller animated:true completion:NULL];
}

@end

やってることはAndroidのものと同じです。
違うのはツイートするまでの処理だけです。

Flutter側でメソッドをinvoke

Flutter側からチャネル経由でメソッドをinvokeする

こちらも簡単で、任意のタイミングでメソッドを呼ぶだけです。
上の実装で、AndroidもiOSも"tweet"というメソッド名の時にそれぞれの処理を呼ぶようにしているので、今回の場合は以下のようになります。

Future<void> _onPressedButton() async {
  try {
    await channel.invokeMethod('tweet');
  } on PlatformException catch (e) {
    print(e);
  }
}

おわりに

コードはGitHubにあげているのでもし良かったら参考にしてください。

今回はデザインについては言及しませんでしたが、Android/iOSごとにデザインを変えるということも試験的にやっているので、大したことはしていませんが興味がある方はコードを読んでみてください。

リファレンス

18
13
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
13