NCMBでは公式SDKとしてSwift/Objective-C/Java/Unity/JavaScript SDKを用意しています。また、それ以外にもコミュニティSDKとして、非公式ながらFlutter/React Native/Google Apps Script/C#/Ruby/Python/PHPなど幅広い言語向けにSDKが開発されています。
今回はコミュニティSDKの一つ、Flutter SDKを使ってニュースアプリを作ってみます。前回は画面の仕様とSDKの初期化について解説しました。今回はニュースの取得と、一覧表示までを実装します。
完成版のコード
作成したデモアプリのコードはNCMBMania/flutter_news: Flutter SDKを使ったニュースアプリデモです。にアップロードしてあります。
ニュース記事をNCMBに登録する
まずニュース記事をNCMBに登録します。この時、RSSフィードを直接読み込んでも良いですが、キャッシュであったりデータへのアクセスのしやすさを考えると一旦NCMBに保存する方がお勧めです。
今回はNCMBのスクリプト機能とRSS2JSONを使ってフィードをJSON化しつつ、データストアに取り込んでいます。YOUR_APPLICATION_KEYとYOUR_CLIENT_KEYを、それぞれ皆さんのものと置き換えてください。
// ライブラリの読み込み
const request = require('superagent');
const NCMB = require('ncmb');
// 定数を定義
const applicationKey = 'YOUR_APPLICATION_KEY';
const clientKey = 'YOUR_CLIENT_KEY';
// NCMBの準備
const ncmb = new NCMB(applicationKey, clientKey);
const Feed = ncmb.DataStore('Feed');
const Entry = ncmb.DataStore('Entry');
// メイン処理
module.exports = async (req, res) => {
if (!req.query.url) {
return res.json({});
}
// キャッシュの検索
const date = new Date;
date.setHours(date.getHours() - 1);
let feed = await Feed.equalTo('url', req.query.url).fetch();
if (Object.keys(feed).length > 0) {
if (new Date(feed.fetchDate.iso) > date) {
res.json({
objectId: feed.objectId,
nextFetchDate: new Date(feed.fetchDate.iso)
});
return;
}
} else {
feed = new Feed;
feed.set('url', req.query.url);
}
// フィードを取得
const url = `https://api.rss2json.com/v1/api.json?rss_url=${encodeURI(req.query.url)}`;
response = await request
.get(url)
.send();
const json = await response.body;
for (const key in json.feed) {
if (key !== 'items' && key !== 'url') {
feed.set(key, json[key]);
}
}
// フィールの中の記事を検索&登録
const entries = [];
const relation = new ncmb.Relation();
for (const item of json.items) {
let entry = await Entry.equalTo('guid', item.guid).fetch();
if (Object.keys(entry).length > 0) {
relation.add(entry);
}
entry = new Entry;
for (const key in item) {
if (['created', 'updated'].indexOf(key) > -1) {
entry.set(key, new Date(item[key]));
} else {
entry.set(key, item[key]);
}
}
relation.add(entry);
}
// フィードを更新
feed.set('entries', relation);
feed.set('fetchDate', new Date);
const method = feed.objectId ? 'update' : 'save';
try {
await feed[method]();
res.json({
objectId: feed.objectId,
nextFetchDate: feed.fetchDate
});
} catch (e) {
console.log(e);
res.json(e);
}
}
実際に呼び出す際にはGETリクエストで、urlパラメータに対してフィードのURLを指定して実行します。このスクリプトを実行すると、ニュース記事がFeedクラスとEntryクラスに登録されます。
ニュース記事を一覧表示する
登録したニュース記事を一覧表示するのが _MyHomePageState クラスになります。まず利用する変数を用意します。
class _MyHomePageState extends State<MyHomePage> {
var listItem = []; // 記事一覧が入る
var _selectedIndexValue = 0; // 記事一覧か、お気に入り登録記事表示の切り替え用
}
そしてクラスの初期化時に、ニュース記事を取得し、その結果をlistItemに入れます。ニュース記事は日付の降順で並べて、前記事を取得しています。データストアを検索する際にはNCMBQueryクラスを使います。
@override
void initState() {
super.initState();
getNews();
}
// ニュースを取得する処理
getNews() async {
// 匿名認証実行
await login();
// ニュース記事が入っているクラスを指定
var entry = NCMBQuery('Entry');
// 登録日時の降順
entry.order('createDate');
// データ取得
var ary = await entry.fetchAll();
// 結果をlistItemに適用
setState(() {
listItem = ary;
});
}
login関数は、匿名認証を使って認証を行っています。セッションはローカルデータに保存されて、次回からそのデータを復元する形になります。そのため、セッションの有効性は確認していません。そこで、復元した際にデータストアにアクセスして、セッションの有効性を確認しています。もし有効でない場合には、元々のUUIDを使って再度匿名認証を実行しています。
login() async {
// 現在ログインしているユーザデータを取得
var user = await NCMBUser.currentUser();
// nullの場合はログインしていない
if (user == null) {
// 匿名認証実行
await NCMBUser.loginAsAnonymous();
// ログインしている場合はセッションの有効性をチェック
} else if (!(await user.enableSession())) {
// セッションが無効だった場合
// 保存されている認証データを取得
var authData = user.get('authData') as Map;
// ログアウトを実行
await NCMBUser.logout();
// 再度同じUUIDを使って匿名認証を実行
await NCMBUser.loginAsAnonymous(id: authData['anonymous']['id']);
}
}
表示処理
表示処理を行う画面の内容です。画面上部にはCupertinoSegmentedControlを使って、記事一覧とお気に入り表示を切り替えできるようにしています。記事一覧はListViewを使って表示しています。記事一覧をタップした際にはMaterialPageRouteを使ってMyDetailPageへ遷移します。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
CupertinoSegmentedControl(
children: const {
0: Text('All entries'),
1: Text('Favorited'),
},
groupValue: _selectedIndexValue,
onValueChanged: (value) async {
await changeList(value);
},
),
Expanded(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
var item = listItem[index];
return Container(
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.black38),
),
),
child: ListTile(
title: Text(item.get('title')),
subtitle: Text(stripTags(item.get('description')),
overflow: TextOverflow.ellipsis, maxLines: 2),
onTap: () {
Navigator.push(
context,
MaterialPageRoute<void>(
settings:
const RouteSettings(name: '/detail'),
builder: (BuildContext context) =>
MyDetailPage(object: item)));
},
));
},
itemCount: listItem.length,
))
]));
}
ここまでで一覧表示機能ができあがります。
まとめ
今回はニュース記事の取得にスクリプトを利用し、取り込んだ記事の表示を行いました。Flutter SDKとしては、記事の表示のみなのでNCMBQueryクラスを使えば簡単にできます。次回は記事の詳細表示(ここはNCMBは使っていません)に加えて、お気に入り登録について解説します。