セブン銀行ATM対応のモックアプリをFlutterで作成した話

株式会社フィノバレーでAndroidアプリを開発している照井(id: hotdrop77)です。
弊社MoneyEasyは今年2020年4月、さるぼぼコインとアクアコインでセブン銀行ATMチャージ機能をリリースしました。
プレスリリース記事: https://finnovalley.jp/20200326/1529/

本記事では、そのセブン銀行ATMチャージ機能のサーバーサイド開発を支援するために作成したモックアプリについて書きました。
本当はもっとモックアプリの業務仕様やコードを載せたかったのですが、そうするとセブン銀行ATMの仕様に触れる必要が出てきてしまい、それは守秘義務の関係で公開することができません。
そのため、作成に至った背景やモックアプリの設計概要などを書いています。

背景

セブン銀行ATM対応はサーバーサイド開発がメインでしたが、当時サーバーエンジニアのリソースが不足しており厳しいスケジュールでした。

特に困難だったのがセブン銀行ATMとの疎通テストで、ATMのテスト筐体がポンポン使えるものではなく担当者様とテスト実施日を調整し現地に赴いてテストをする必要があったため、テスト時点である程度の品質を担保して臨む必要がありました。
(少なくとも正常系は一通り動く状態で現地で障害解析もある程度できるレベル)

逆にモバイルアプリ側は簡易な画面を数個作るのみで比較的余裕がありました。
サーバーサイド開発を手伝いたかったのですが自分がGo入門レベルでサーバー側の設計も把握していなかったため期間を考えると邪魔にしかならないことが目に見えていました。

この期間内で有益な支援ができないか考えた結果 「ATMと通信する部分の検証がきつそうなのでそれならモックアプリを用意すれば疎通テストも楽になるのでは?」
と思って私の方でモックアプリを作ることにしました。

モックアプリは当初作成予定はなく、サーバーエンジニアさんが気を遣ってくれる方で
「照井さんもアプリの改修あるし、無理せず時間あったらお願いしますm( )m」
という感じだったので余計に火がついて絶対完成させて負担を軽減してあげようと決意しました。

なお、モックアプリの作成期間はこの話が決まった2019年12月中旬からサーバーがモックアプリでテストを始められるであろう1月中旬くらいの約1ヶ月間でした。

Flutterを採用した経緯について

モックアプリの想定利用者は自分とサーバーエンジニアさんの2名のみであり、完成して使い物になればどんな言語でどう作ろうが問題ありませんでした。

セブン銀行ATM画面の操作をエミュレートするなら画面操作がしやすいものが良く「モックアプリやっぱ無理でしたー」というのは自分の中ではありえないので無難にAndroidで作る想定でいました。

ただ、この頃はFlutterに興味を持っていて趣味でアプリを作成していました。
万が一テストでiPhoneユーザーがこのアプリを使う事態になったり、ブラウザで通信ログやエラーログを見たいという要望が出てきた場合にFlutterならワンチャン対応が可能だと考えました。

この時期はFlutterのWebサポートもそこそこ出来てきており上記の要望に答えられる可能性があったことと、自己学習を兼ねられることからFlutterで作ることに決めました。

モックアプリ概要

モックアプリの大まかな機能は以下の通りです。

  1. セブン銀行ATMのチャージ操作機能
    • ここでは「コード読み取り→金額入力→金額投入→チャージ完了」の一連の流れを画面操作で再現するとともにリクエスト/レスポンスが逐次見えるように作成しました。
  2. 暗号通信の検証機能
    • この部分については何も書けませんがこういう機能を作成しました。
  3. エンドポイントや電文項目の設定機能
    • 通常変更されることはないエンドポイントや電文の固定項目などもモックアプリでは「もしここを変更したら正しくチェックが走るか?」をテストできるようにしました。
  4. 履歴機能
    • 過去のリクエスト/レスポンスが閲覧できる機能です。
      生データからデコードしたものまで段階的に見れるように工夫したのですが、情報量が多くて見辛い画面になってしまいました。
  5. テストモード
    • エラーが発生した場合にモックアプリのバグなのかサーバーのバグなのかを切り分ける最低限の情報を得るためこのモードを作成しました。
      このモードはサーバー通信が発生する操作をしたら仕様書に記載されているサンプル電文をそのまま返す仕様となっています。
      最低限のバグ切り分けには使えましたが、実際にはそんな単純ではなく何回か切り分け調査はすることになりました。

トップ画面はこんな感じですが、諸事情により色々伏せているのであまり分からないですね・・雰囲気だけ読み取ってください。

f:id:hotdrop77:20200729122810p:plain
モックアプリのトップ画面

設計概要

画面は8つと小規模なアプリです。設計は一番慣れているAndroid Architecture ComponentsのMVVMチックな設計としています。
状態管理はProviderを使用し、Flutterアプリでよく出てくるBLoCパターンについては採用を見送りました。
個人的にはBLoCは小規模アプリで採用するには過剰実装だと思っていて今回のような小さいモックアプリではProviderだけで十分かなという認識なのですが、とはいえ言うほどBLoCで実装したことないので一瞬使ってみてもいいかなと考え、でも今回は見送りました。

ViewModelChangeNotifierextendsしておりバインド的にフィールドを使用しました。
本当はLiveDataのように個別に購読できると良かったのですが、その場合はStreamRxDartを使う選択になってしまうと思うのでこのアプリではそこまでやりませんでした。
Providerの4系で登場したselectが使えると近しいことができると思うのですが、この当時はまだ3系を使用しており使えませんでした。

UseCase層は作らずViewModelの下はRepository層としました。
いつも通りRepositoryでAPIを実行するためのネットワーク通信処理やローカルDBへの保存/取得処理を行なっています。
それぞれ使用したライブラリはこんな感じです。

  • ネットワーク通信: http
  • 設定系の保存: shared_preferences
  • 履歴データなどの保存: sqflite

ローカルDBのライブラリは使い慣れているsqfliteにするか、この時期ちょっといいなと思っていたhiveにするか迷いました。
この時点ではhiveはまだ冒険すぎたのでこの時はsqfliteを採用しました。
hiveは別の検証アプリで使ったのでそのアプリについて記事にすることがあればそこで書こうと思います。)

苦労した点

苦労した点は順にこんな感じです。

  1. セブン銀行ATMの仕様理解
  2. バイナリデータの扱い
  3. 暗号方式の扱い

1. セブン銀行ATMの仕様理解

難易度が一番高かったのがこの仕様理解です。
実は12月当初は資料が不足しておりそれが無駄に難易度を高めていたのですが、ここでサーバーエンジニアさんとあーだこーだ色々と話して理解を深めていました。
この話し合いの中でネックになりそうな処理や重点的に見ておいたほうがいい処理が大体わかってきたので、そのままモックアプリの仕様に繋げました。

2. バイナリデータの扱い

Dartでバイナリデータを扱うこと自体はさほど難しくなかったのですが、慣れていないためすぐString型で扱おうとしてしまったり型を変換せずにリクエストにのせようとしてデータ長が狂ったりしました。
本当はAPIを投げる直前の出入り口でMapperを用意してそれぞれ扱う型に変換すれば良いのですが、このモックアプリではリクエスト/レスポンスの生データと複合化したデータ両方を画面表示していたためModelクラスに両データを持つ必要がありました。

3. 暗号方式の扱い

とりあえず資料に出てくる用語は概要レベルでも頭に叩き込むのが望ましいのでそれを最初にやりました。
暗号については以前読んだ結城先生の「暗号技術入門」で基本的なことは把握していました。まあ忘れてることが多かったので再度読み直したのですが。。

そして何よりFlutterの暗号ライブラリEncryptが素晴らしくかなり助けられました。これ一つ導入すれば主要な暗号アルゴリズムはだいたい網羅できると思います。
最初はこんな便利なライブラリの想定をしていなかったため、最悪PlatformChannelでネイティブレイヤーまで降りてガリガリコードを書く覚悟でした。

とはいえこの覚悟も無駄ではなく、どうしても無理なところがあって一部Javaコードで解決しました。
そのため、最初はWeb/iOSでも使えるライブラリだけで頑張っていたのですがこのタイミングで断念し、最終的に完成したモックアプリはAndroidでしか動きません。
もちろんSwiftで同じ処理を書けばiOSでも動くと思いますが、結局他のプラットフォームで動かす要望もなさそうだったためそのまま突き進みました。

まとめ

サーバーエンジニアの方が優秀だったこともありモックアプリでいくつかバグを摘出&修正したのち、予定通りテスト筐体での検証はすんなりいってそのままオンスケで本機能をリリースすることができました。
多少モックアプリのバグで足を引っ張った気もしますが、かなり役に立ってくれたようですし無事にリリースできて良かったと思います。

今回モックアプリをFlutterで作成してみて、やはりFlutterもDartも良いものだなと改めて思いました。
Androidの画面開発はxmlに慣れていてJetpack Composeはどうも好きになれないのですが、宣言的UIが嫌いなわけではなくFlutterはWidgetとホットリロードの恩恵によってUI実装がXMLより早く書けるしMaterialDesignも簡単にできて素晴らしいと思います。

Dartは個人的に好きなのですがKotlinに比べると色々惜しくて、でも最近の進化が早くそろそろnullセーフ機能も入りそうですし期待しています。

まだまだエンジニアの確保をはじめとしてプロダクトに導入するには会社的にハードルが高いと思いますので、まずはモックやプロトタイプなどのアプリを素早く作って事業に貢献していければなと考えています。