Dart

19. Flutterでwebfeedとhtmlを使ってRSSのリスト一覧を作成する

今回は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)
      ),
    );
  }
}

これでビルドすると次のような動作になります。

ツイッターでgifを貼り付けても自動再生されませんでした。。。

f:id:qed805:20200216200259p:plain

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のリンクを使ってウェブページを表示させるのが常套手段ですが、
今回はここまでにします。

ABOUT ME
tamappe
都内で働くiOSアプリエンジニアのTamappeです。 当ブログではモバイルアプリの開発手法について紹介しています。メインはiOS、サブでFlutter, Android も対応できます。 執筆・講演のご相談は tamapppe@gmail.com までお問い合わせください。