今回はFlutterでRSSの導入みたいなものを作成したいと思います。
RSSアプリの概要
今回RSSで使うXMLファイルはQiitaにユーザーフィードにしています。
ここで学習できた内容は
- ListViewとListTileの使い方
- 画面遷移
- ライブラリのインストール
- ウィジェットのイニシャライズ
こちらになります。
Flutterのライブラリのパッケージ
Flutterで使うパッケージは
- webfeed (RSSパーサーライブラリ)
- http (httpクライアント)
この2つを使って開発していきます。
それぞれのパッケージのインストールと使い方については上記ページの「Installing」タブに記載されています。
私のpubspec.yaml
は下記の通りです。
pubspec.yaml
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
webfeed: ^0.4.2
http: ^0.12.0+4
RSSの構造はXMLをとってきてパースしてFeedのitemに変換しなければなりません。
XMLの取得についてはhttpを使って
Feedの変換についてはwebfeedを使って
それぞれ行います。
変換したitemをListTileのウィジェットに代入してそれをListViewにセットします。
サンプルコードについて
それではRSSアプリの基礎になるList一覧までのソースコードを書いていきます。
main.dart
import 'package:flutter/material.dart';
import 'package:rss_app/rss_list_page.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: RssListPage(),
);
}
}
rss_list_page.dart
import 'package:flutter/material.dart';
import 'package:rss_app/item_detail_page.dart';
import 'package:webfeed/webfeed.dart';
import 'package:http/http.dart';
class RssListPage extends StatefulWidget {
final String title;
final String url;
RssListPage({@required this.title, @required this.url});
@override
_RssListPageState createState() => _RssListPageState(title: title, url: url);
}
class _RssListPageState extends State<RssListPage> {
final String _rssUrl = "https://qiita.com/tamappe/feed.atom";
final String title;
final String url;
List<Widget> _items = [];
_RssListPageState({@required this.title, @required this.url}) {
convertItemFromXML();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("RSS リーダー"),
),
body: Center(
child: ListView(
padding: EdgeInsets.all(10.0),
children: _items,
),
),
);
}
void convertItemFromXML() async {
List<Widget> list = [];
Response res = await get(_rssUrl);
var atomFeed = new AtomFeed.parse(res.body);
for (AtomItem item in atomFeed.items) {
list.add(ListTile(
contentPadding: EdgeInsets.all(10.0),
title: Text(
item.title,
),
subtitle: Text(
item.published
),
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (_) =>
ItemDetailPage(
item: item,
)
));
},
));
}
setState(() {
_items = list;
});
}
}
item_detail_page.dart
import 'package:flutter/material.dart';
import 'package:webfeed/webfeed.dart';
class ItemDetailPage extends StatefulWidget {
final AtomItem item;
ItemDetailPage({
@required this.item
});
@override
_ItemDetailPageState createState() => _ItemDetailPageState(item: item);
}
class _ItemDetailPageState extends State<ItemDetailPage> {
AtomItem item;
_ItemDetailPageState({@required this.item});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(item.title),
),
body: Center(
child: Text(item.title)
),
);
}
}
これでビルドすると次のような動作になります。
自分のQiitaのフィードをもとにRSSアプリの基礎であるXMLファイルのパースが出来上がる。
httpとwebfeedを使って実装する。 pic.twitter.com/ei1xEpRWgs— Tamappe@オンライン英会話のエンジニア (@tamapppe) 2020年2月16日
ツイッターでgifを貼り付けても自動再生されませんでした。。。
rss_list
解説
それではhtmlとwebfeedの使い方について解説していきます。
今回ではRSSのURLをgetしてXMLファイルを取得するために使いました。
Response res = await get(_rssUrl);
get(url)でhttp通信を行うことができます。今回はGET
の通信を行いました。await
はDartにおける非同期処理を行うために使うものです。
await
を使うためにはメソッドにasync
が必要になるためメソッドにasync
を記載しています。
void convertItemFromXML() async {}
取得したresponseであるres
がFeedです。
公式でも次のように解説しています。
var atomFeed = new AtomFeed.parse(xmlString); // for parsing Atom feed
ちなみにQiitaのユーザーフィードはAtom仕様らしいのでAtomFeed
オブジェクトに変換しました。
RSS仕様の場合は次のとおりです。
var rssFeed = new RssFeed.parse(xmlString);
AtomFeedオブジェクトの取得に成功したらfor文を使ってそれぞれの記事のitemを取得しに行きます。
for (AtomItem item in atomFeed.items) {
}
AtomItem
からItemの情報を取得する場合は
item.id
item.title // 記事タイトル
item.updated // 更新日
item.published // 投稿日
という感じになります。
そして、取得できた情報をListTileにセットしてListViewを表示させました。
これでRSSアプリの基本であるリスト一覧までが完成しました。
あとはまあ取得できたWEBのリンクを使ってウェブページを表示させるのが常套手段ですが、
今回はここまでにします。