前回の続き。
- 
												 - 
FlutterでTwitterクライアント作成②フッター追加
前回、FlutterでTwitterのクライアントアプリを作ろうということでヘッダーを追加したところまでやりました。 今回はフッターを追加して画面を切り替えられるようにしたいと思います。 目次1 フッ ...
続きを見る
 
今回はホーム画面にTwitterのタイムライン情報を読み込んでみます。
目次
まずはお試し
いきなりTwitter APIだと難しそうなので、もっと簡単なやつで情報取得できるかを確認します。
こちらを参考にしました。
http通信を使えるようにする
pubspec.yamlのdependenciesにhttpを追加します。
| 
 1 2 3 4 5 6 7 8  | 
dependencies:   flutter:     sdk: flutter   # The following adds the Cupertino Icons font to your application.   # Use with the CupertinoIcons class for iOS style icons.   cupertino_icons: ^0.1.2   http: any # 追加する  | 
http通信して情報を表示する
home_route.dartでAPIに接続して情報を取得します。
FlutterリポジトリのIssuesの一覧だそうです。
| 
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34  | 
import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import '../header.dart'; class Home extends StatefulWidget {   @override   _Home createState() => _Home(); } class _Home extends State<Home> {   final String screenName = 'ホーム';   String _timelineData = '';   @override   void initState() {     super.initState();     _load();   }   Future<void> _load() async {     final res = await http.get('https://api.github.com/repositories/31792824/issues');     setState(() {       _timelineData = res.body;     });   }   @override   Widget build(BuildContext context) {     return Scaffold(       appBar: Header(headerTitle: screenName),       body: Center(child: Text(_timelineData)),     );   } }  | 
パッケージの追加
httpを追加します。
as httpとしている理由は
httpパッケージにはgetやpostといった単純な名前があり、他の識別子との衝突を避けたい場合などにこの機能を使います。
とのこと。
| 
 1 2 3  | 
import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; // 追加してhttpという名前を付ける import '../header.dart';  | 
HomeをStatefulWidgetに変更
StatelessWidgetだと取得したデータを描画できないので、StatefulWidgetに変更します。
httpで取得したデータ用に変数を追加してます。
| 
 1 2 3 4 5 6 7 8  | 
class Home extends StatefulWidget {   @override   _Home createState() => _Home(); } class _Home extends State<Home> {   final String screenName = 'ホーム';   String _data = '';  | 
httpで情報を取得
initState()は前回やった通り、画面描画前に走る処理です。
画面を表示する前にGitHubから情報を取得する処理を実行しています。
_load()はHTTP通信でデータを取得する処理です。
通常、APIを叩くときは非同期処理を行います。
- asyncを付けることで非同期メソッドにする
 - http.getで非同期通信を行い、Futureを返す
 - awaitを付けてデータが返ってくるのを待ち受ける
 
FutureはJavaScriptでいうPromiseのようなものとのこと。
この仕組みがあるため、データが返ってくるのを待たずに次の処理に進んでいます。
| 
 1 2 3 4 5 6 7 8 9 10 11 12  | 
  @override   void initState() {     super.initState();     _load();   }   Future<void> _load() async {     final res = await http.get('https://api.github.com/repositories/31792824/issues');     setState(() {       _data = res.body;     });   }  | 
取得したデータを表示
bodyには_dataを取得しています。
非同期処理をしているため先に画面描画処理が行われ、setStateで_dataが更新され次第表示されます。
| 
 1 2 3 4 5 6 7  | 
  @override   Widget build(BuildContext context) {     return Scaffold(       appBar: Header(headerTitle: screenName),       body: Center(child: Text(_data)), // http通信で取得したデータを指定     );   }  | 
パーミッションの追加
権限の設定をしておかないと、リリースビルド時に失敗します。
AndroidのAndroidManifest.xmlに追記します。
| 
 1 2 3  | 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"     package="com.example.twitter_client">     <uses-permission android:name="android.permission.INTERNET" /> <!-- 追加 -->  | 
iOS用も何か追加しないといけない気がするけど、今回はAndroidしか動かさないので割愛。
main.dartを修正
今の状態でHot Restartするとエラーが出ました。。。
Headerでエラーを吐いてます。
| 
 1 2 3 4 5 6 7 8 9 10  | 
When the exception was thrown, this was the stack #2      new Text  package:flutter/…/widgets/text.dart:285 #3      Header.build  package:twitter_client/header.dart:18 #4      StatelessElement.build  package:flutter/…/widgets/framework.dart:4291 #5      ComponentElement.performRebuild  package:flutter/…/widgets/framework.dart:4223 #6      Element.rebuild  | 
調べたところ、main.dartとhome_route.dartでそれぞれヘッダーを描画しようとしてるのがダメみたい。
ということで、以下を削除します。
| 
 1 2 3 4 5 6 7 8 9 10 11 12  | 
// import 'header.dart';   Widget build(BuildContext context) {     return MaterialApp(        theme: ThemeData(         primaryColor: Colors.pink[100],       ),       home: Scaffold(            // appBar: Header(),         // body: Center(child: Text('ホーム')),         bottomNavigationBar: RootWidget(),       ),     );  | 
これで改めてHot Restartすると…。
取得した生データが表示されました。
画面を切り替えると再取得しています。
これでAPIを叩いて情報を取得する処理のベースができました。
Twitter API Keyの取得
Twitterのタイムライン他の情報を取得するには公開されているAPIを使用します。
このAPI、以前は割と自由に使えたんですが、2018年に取得が厳しくなってました。。。
とはいえ一般人でも取得は可能です。
取得方法は時々変わるみたいなので、最新の情報をもとにAPI Keyを取得してください。
新しめのはこちら。
Twitter タイムライン情報を取得する
API keyが取得出来たらタイムラインの情報を取得してみます。
公式リファレンスはこちら。
認証用ライブラリを追加する
Twitterの認証は自分で実装することもできますが、Dart用のライブラリがあったのでそちらを使用することにしました。
(結局http使わなかった)
pubspec.yamlに以下を追加します。
| 
 1 2 3 4 5 6 7 8 9  | 
dependencies:   flutter:     sdk: flutter   # The following adds the Cupertino Icons font to your application.   # Use with the CupertinoIcons class for iOS style icons.   cupertino_icons: ^0.1.2   http: any   twitter_1user: ^1.0.1 // 追加する  | 
タイムラインの情報を取得する
home_route.dartを修正してTwitterのAPIに接続します。
_loadの中身を以下のように書き換えます。
API Keyなどは各自取得してください。
| 
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  | 
import 'package:twitter_1user/twitter_1user.dart'; // import 'package:http/http.dart' as http;   Future<void> _load() async {     final String apiKey = 'Twitter Developerで取得したAPI Key';     final String apiSecret = 'Twitter Developerで取得したAPI secret key';     final String accessToken = 'Twitter Developerで取得したAccess token';     final String accessSecret = 'Twitter Developerで取得したAccess token secret';     final String userTimelinePath = 'statuses/home_timeline.json';     Twitter twitter = new Twitter(apiKey, apiSecret, accessToken, accessSecret);     final res = await twitter.request('GET', userTimelinePath, {'count': '30'});     setState(() {       _timelineData = res;     });   }  | 
これを保存した結果がこちら。
何が書いてあるかわかりませんが、twimgなどなんとなくTwitterっぽい文字列が確認できます。
取得した情報をdecodeする
今のままだと何が返ってきているのかよくわからないので、日本語に直してみます。
home_route.dartの_loadにjsonDecodeを追加します。
convertのimportも必要。
_timelineDataはStringじゃないといけないので、textのみを拾って出力します。
| 
 1 2 3 4 5 6 7 8  | 
import 'dart:convert'; ・・・     final res = jsonDecode(await twitter.request('GET', userTimelinePath, {'count': '30'}));     setState(() {       for (int i = 0; i < res.length; i++){         _timelineData += res[i]['text'] + '\n'; // textだけ取得       }     });  | 
これを保存して情報を取り直すとこう。
tweetのテキスト部分だけが表示されました。
ちなみに、home_timeline.jsonはこれだけの情報を持ってます。
| 
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102  | 
{   "created_at": "Wed Oct 10 20:19:24 +0000 2018",   "id": 1050118621198921728,   "id_str": "1050118621198921728",   "text": "To make room for more expression, we will now count all emojis as equal—including those with gender and skin t… https://t.co/MkGjXf9aXm",   "truncated": true,   "entities": {     "hashtags": [],     "symbols": [],     "user_mentions": [],     "urls": [       {         "url": "https://t.co/MkGjXf9aXm",         "expanded_url": "https://twitter.com/i/web/status/1050118621198921728",         "display_url": "twitter.com/i/web/status/1…",         "indices": [           117,           140         ]       }     ]   },   "source": "<a href="http://twitter.com" rel="nofollow">Twitter Web Client</a>",   "in_reply_to_status_id": null,   "in_reply_to_status_id_str": null,   "in_reply_to_user_id": null,   "in_reply_to_user_id_str": null,   "in_reply_to_screen_name": null,   "user": {     "id": 6253282,     "id_str": "6253282",     "name": "Twitter API",     "screen_name": "TwitterAPI",     "location": "San Francisco, CA",     "description": "The Real Twitter API. Tweets about API changes, service issues and our Developer Platform. Don't get an answer? It's on my website.",     "url": "https://t.co/8IkCzCDr19",     "entities": {       "url": {         "urls": [           {             "url": "https://t.co/8IkCzCDr19",             "expanded_url": "https://developer.twitter.com",             "display_url": "developer.twitter.com",             "indices": [               0,               23             ]           }         ]       },       "description": {         "urls": []       }     },     "protected": false,     "followers_count": 6128663,     "friends_count": 12,     "listed_count": 12900,     "created_at": "Wed May 23 06:01:13 +0000 2007",     "favourites_count": 32,     "utc_offset": null,     "time_zone": null,     "geo_enabled": null,     "verified": true,     "statuses_count": 3659,     "lang": "null",     "contributors_enabled": null,     "is_translator": null,     "is_translation_enabled": null,     "profile_background_color": "null",     "profile_background_image_url": "null",     "profile_background_image_url_https": "null",     "profile_background_tile": nulll,     "profile_image_url": "null",     "profile_image_url_https": "https://pbs.twimg.com/profile_images/942858479592554497/BbazLO9L_normal.jpg",     "profile_banner_url": "https://pbs.twimg.com/profile_banners/6253282/1497491515",     "profile_link_color": "null",     "profile_sidebar_border_color": "null",     "profile_sidebar_fill_color": "null",     "profile_text_color": "null",     "profile_use_background_image": null,     "has_extended_profile": null,     "default_profile": false,     "default_profile_image": false,     "following": nul,     "follow_request_sent": null,     "notifications": null,     "translator_type": "null"   },   "geo": null,   "coordinates": null,   "place": null,   "contributors": null,   "is_quote_status": false,   "retweet_count": 161,   "favorite_count": 296,   "favorited": false,   "retweeted": false,   "possibly_sensitive": false,   "possibly_sensitive_appealable": false,   "lang": "en" }  | 
タイムラインは文字だけじゃないので…
とりあえずtweetのテキストはできるようになりましたが、まだまだタイムラインとは程遠いですね。
やっぱりユーザーアイコン、ユーザー名、返信ボタンなども表示しないと。
ということで、次回はタイムラインっぽい見た目にします。
- 
												 - 
FlutterでTwitterクライアント作成④タイムラインをListTileで装飾
前回の続き。 今回はタイムラインの表示をTwitterっぽくします。 目次1 Flutter標準のUIを使用する1.1 tweetをリスト形式で表示する1.1.1 LinkedHashMapの追加1. ...
続きを見る
 
ここまでのコードはGitHubで。



