ShopCard.me、お店詳細画面の非同期による起動シーケンスについて

ふと思う所あって、ShopCard.meというアプリで、画面の起動順番、非同期処理どのようにしているのかを書いてみます。この画面は速度にこだわって作っていて、表示レスポンスとオフライン対応を意識した構成になっているので、少し紹介したいと思います。

そもそもShopCard.meって?!

ShopCard.meは自分のお気に入りのお店を記録しておいて、サクサクと呼び出せるようにしてるiPhone / iPadのアプリです。

距離の近い順にお気に入りのお店を表示するので、前に旅行に行った時のお店とかをすぐに呼び出せるようにしていて、外食大好きで、お店の名前とか覚えるのが苦手な人とかに使っていただけるようにしてます。

グループにまとめて、友達と共有したり、とにかくお気に入りのお店を友達と共有するときのツールとして使ってほしいなあと思って作っています。

ショップの詳細画面例

今回は、この「ショップ詳細情報画面」を例に書いてみます。

scm_detail_view_20150718

上記画面を表示するためには、これ以降に解説するステップすべてを非同期で処理し、データをゲットする度に順繰りにレンダリングを進めています。

画面表示に必要な情報を順繰りに表示していくことで、画面遷移の手間やユーザーさんがお店を探す時の読み込み待ち負荷を、できるだけ下げるようにしています。

STEP1 . 基本画面構造の構成(0リクエストで表示)

この画面は、お店一覧ページから飛んでくる詳細画面です。まずは画面の基本フレームを構成する「お店の基本情報」をまず表示するのですが、その段階ではサーバの通信は発生していません。

前の画面に持っている、「お店情報配列」から持ってきます。

この画面の前のページである、ShopCard.meのお店一覧情報は、Google api、Yahoo! loco APIと、Shopcard.meの独自apiの3種類のお店情報がミックスされていて距離順で配列を持っています。

アプリ起動時では、まだ②に表示したいお店の住所とか電話番号を持っていません。

よって、この画面の表示開始時は、一切、サーバに通信しておらず、最低限「お店の名前」と、画面の基礎的な枠組みだけは表示しています。

お店毎にサーバから得られる情報の有無はわからないという前提で動いています。つまり、このアプリにおいて、お店の情報とは「お店の名前」と「緯度経度」だけ最低限あれば動くようになっています。

STEP2 店舗に関する詳細情報(0秒 or 2リクエスト)

次にお店の詳細情報を、各サービスのapiから取得してきて、②のエリアを構成します。④のエリアにもいくつか表示する方法があるので、それもここで読んできます。以下の2つのAPIを並列処理で呼び出しています。

1.位置情報APIサービスから持ってくるお店の詳細情報
2.Shopcard.meサーバから持ってくる、ユーザ固有の情報

前者はお店の住所や営業時間、連絡先電話番号などですね。

後者は、このカードを保有しているか。レーティング。訪問情報。他の人によって登録されている枚数。お店の紹介コメントなどを取得してきます。

STEP1で基本的な画面構成はすでに表示していますので、データを読み込み次第、遅延させてレンダリングしているため、画面遷移のレスポンスには影響ありません。

また②の部分は折りたたみできるタブとして構成しています。iPhoneだと閉じて表示。iPadだと開いて表示するのがデフォルトにしていますが、特にiPhoneだと遅延表示されても見た目にほとんど影響がないです。

ShopCard.meは、当初、電波の繋がらないお店の奥とかで使ってもらうことを想定していたので、基本的には取得してきたデータをローカルにキャッシュしています。ですので、通信が途切れていても、お店の詳細情報は表示されるし、お店の情報をBluetooth経由で、友達にシェアすることができるようにしていました。

ですので、店舗の詳細情報は、キャッシュさえあれば通信なしで表示できます。一度キャッシュしたら、一覧画面のお店配列に詳細情報をぶらさげているので、画面の行き来をするだけなら二度目以降は通信が発生しない仕組みになっています。

ローカルDBにデータがあれば、お店の情報については通信は不要なように作ってあるのですが、Google place API利用規約の方で、最新情報を表示するために長期間のキャッシュは禁止になっているので、都度APIから最新情報を持ってくるようにしてあります。

STEP3 食べログ、ぐるなびなどの情報サイト検索

ShopCard.meの実態は、お店情報の検索ロボットみたいな作りになっていて、実質Google検索クライアントです。裏で、お店の情報を元に食べログやぐるなび、海外ならYelp!、ホテルとかならTripAdviserなどのお店ページを探してきて、一覧で並べて調べることができるようになっています。

ShopCard.meで既に探索済みもしくは登録済みのURL情報があれば、STEP2の段階でURLを持っていますが、そうでなければ、STEP2でショップの詳細情報を読み込んできた後で探しに行く処理が走っています。たべろぐやぐるなびなど、個別のグルメサイトを探しに行くリクエストはすべて非同期で行われています。

STEP4 サムネイル画像の呼び出し

ShopCard.meが少しややこしいのはこの辺で、1. お店の名前で検索してきた画像、と、 2.ユーザーがShopCard.meに直接アップロードした画像の2種類があります。

もし登録済みの画像があれば、Step2で画像URLを持ってきてるので、遅延ローディングで画面にレンダリングしています。サムネイル画像がない場合は、サーバ側で画像をネットに探しにいく非同期キューが走るようになっています。

そのため一度リクエストがあった場合、過去に誰かがShopcard.meサーバに画像をアップロードしていないのであれば、画像を探しに行くキューがサーバ側で走っています。ですので、一度目は即座にサムネイルが表示されなくても、画像情報が見つかり次第URLを取得し、画像を表示するという流れになっています。

なおサムネイルを探しに行くためのキューは、一つ前の画面のお店一覧画面でも裏側で走っており、見知らぬ土地で検索しても、いい感じに画面表示してくれるようになっています。

なおこの画面は、画面を下に引っ張ると、すべての情報をリロードしてくるようになっており、iPhoneの方で回線が繋がらないような通信エラーが発生したとしても、リロードして画面が再構成されるようになっています。特にサムネイルの再更新は、その処理をで行うようにしています。

今後について

今はユーザーのリクエストベースで、情報を探しに行く処理を走らせていますが、クローラで事前に探しに行くような処理を入れたいのと、位置情報APIに依存しない情報検索機能を作りたいと思っています。

また限られたオフ時間を、今は大学院の研究の方を優先していて、抜本的な作りなおしをする時間が取れないのですが、ちょいちょい時間を作ってはいじっています。あと抜本的な改善という意味では、構成とデザイン自体を全部作り直したいなーと思ってたりします。それ結構、お金も手間もかかるんでアレなんですが、こないだアメリカ行った時に、あ、このデザインいいなってのがありまして。

もしアプリのサービスの方にご興味をもっていただいた方がいたら、是非お使いいただけますと幸いです。

ちなみに裏ワザなんですが、他のアプリとかWebページのURLをクリップボードにコピーすると、状況にあわせて、いい具合にお店の情報を取り込む機能とかをつけています。
俺得な機能すぎてApp Storeでは説明できてないです ><

【PR】BASE株式会社 17職種、仲間を絶賛募集中!