【OutSystems】スマホ（PWA）アプリでオフライン登録処理を作る

OutSystemsではPWA（Progressive Web Application）が簡単に作れるので勉強がてら作成したものをメモとして残す。

## 1.スマホアプリの種類について
スマホアプリは大きく３種類に分類されます

<b>ネイティブアプリ</b>
・スマホへ直接インストールして使うアプリ
・配布にあたってアプリストアの承認が必要
・高度なディバイス制御（顔認証やカレンダー機能と連携）が可能
・スマホ側のストレージ消費が発生する
・オフライン操作可能

<b>Webアプリ</b>
・ブラウザで動かすアプリケーション
・アプリストアの承認は不要
・ディバイス制御出来ない（※）
　※教科書的に書いてますが実際はスマホカメラ制御が出来たりしますね。
・スマホ側のストレージ消費は発生しない
・オフライン操作不可

<b>PWAアプリ</b>
・ネイティブアプリとブラウザアプリのハイブリッド（実態はブラウザで動く）
・アプリストアの承認は不要
・ある程度ディバイス制御（カメラやPush通知など）が可能
・スマホ側のストレージ消費が多少発生する
・オフライン操作可能

今回はPWAアプリを作成していオフライン機能を実装してみる。


## 2.アプリ概要
作りたいアプリの概要は以下のイメージです。スマホがオフラインになった際はローカルのストレージにデータ登録を行い、オンライン復帰後にログインしたタイミングでローカルストレージのデータをサーバ側に同期する処理が動作します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/39f55c3c-1711-1295-5005-d0278e410b2b.png)





## 3.オフライン処理を実際に作ってみる

### 3.1 登録画面とサーバ側のEntity作成
画面周りの作成は省略します。Phone Appからユーザー登録用の必要な部品を配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/4df8435c-50e1-bda6-5fc2-caebd2bf4fef.png)
<br>
またユーザー情報登録用のエンティティ（MUser）を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/881f49d0-bff4-1c8b-9159-1f383fa365d5.png)


<br>
登録ボタンタップ時に直接サーバ側のデータベースに登録処理を行うとオフライン時はデータベースへのアクセスが出来なくなり登録エラーとなります。そのためオフライン機能としてスマホ側のストレージに一時的にデータを登録してオンライン時にサーバ側のデータベースとデータの同期を行う処理を実装します。


### 3.2 スマホ側のローカルストレージを作成する
スマホ側の登録処理時に一時的にデータを登録するローカルストレージを作成します。
「Data」タブ → 「Local Storage」→ 「Add Entity from Database」を選択すると既に作成しているEntityの情報を使ってスマホローカルにEntityを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/e6b1f5d3-0554-fe83-588c-83d6b95e6d30.png)
<br>
同期する対象のMuserエンティティを作成して連携する項目を全て選択します。
警告文（全ての項目を連携するとローカルストレージの容量食うから節約しなさいという旨の警告です。）が出ていますがAddとしますとローカルストレージが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/0bcf84dc-0a1c-1ff6-36b6-d9e1acdf46a2.png)
<br>


### 3.3 データ同期処理を作成する
ここではオンラインのタイミングでローカルストレージからサーバ側のエンティティにデータの同期を行います。同期のタイミングは様々なタイミングが設定可能です。

①ログインのタイミング
②データ登録直後
③電波がオフライン → オンラインに切り替わったタイミング

今回は①タイミングで同期処理を実行します。（①時にオフラインであればデータの同期はスキップされます。）

ローカルストレージから「Create Action to SyncData（Read/Wirte）」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/e735f590-1b88-a4ba-4f93-0eca14eb5aa8.png)
<br>
Muserテーブルのデータ同期に必要なクラアントアクションが自動で作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/983a4cfd-0ee8-ebd2-ff47-519240c65efe.png)



<br>
自動作成されたSyncLocalMusersのクライアントアクションを少し見てみると、MUserテーブルのローカルストレージの処理区分（登録・修正・削除）ごとにデータを抽出して同期処理を実行しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/477662ee-cae1-540a-cc51-69a8924e9045.png)
<br>

OfflineDataSyncのクライアントアクションを開いて、同期開始・終了のメッセージと直前で解説したSyncLocalMusersのクライアントアクションを配置して呼び出してあげます。（他に更新する同期するローカルストレージテーブルがあればこのクライアントアクションで同様にセットします。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/a605a339-ca71-40e5-7eab-da65faa63fa3.png)

<br>

データの同期処理（OfflineDataSync）の実行タイミングを定義します。タイミングの設定はOfflineDataSyncConfigurationで設定します。ここではログインのタイミングでデータの同期処理を行うようにセットします。（SyncOnLogin=Trueに変更）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/82c7de1a-bf9e-506a-9911-f483a7a6c88b.png)
<br>

最後に登録ボタンのOnclickイベントでローカルストーレジにデータ登録するクライアントアクション（CreateOrUpdateLocalMuserForSync）をセットしてあげます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/c9872e26-c9a4-f89c-a770-2c33ba223e0b.png)

これで同期処理は終了Publishします。

## 4.配布形式の選択と端末へのセット
### 4.1 PWAタイプでの配布
ServiceStuidoアプリの基本画面からPWAを選択すると、利用者側はPWA形式でアプリのアクセスが可能となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/19f48f38-54ec-1495-ec56-acac1f7787b8.png)

### 4.2スマホ側でセット（iPhone）
アプリのURLにブラウザでアクセスしたのち、デスクトップにアプリの登録を行います。これでPWAタイプでのアクセスが可能となります。
ブラウザでアクセスしたのち、ホーム画面に追加してあげます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/ae425f8c-733c-f524-314c-8d2430f2dbb8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/35358461-f485-a269-c7b2-8d0b3db61809.png)

ホームにアプリが追加されます。こでPWA版のアプリとして動作ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/07b6c66d-c937-4b5c-aa8c-09290e77ab75.png)




## 5.オフライン処理を試してみる
実際にオフライン時のデータ登録処理を試してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/f3e95621-2476-fa95-9ce7-cbad58891035.png)

<br>
登録処理が完了します。（ただしまだサーバ側には同期されてません。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/4823afc8-4401-90c8-aeaa-744e4371f042.png)
<br>
オンライン復帰後に同期トリガーとしてセットしたログイン処理を実行するとデータの同期処理が開始されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/8a214852-50b5-3518-814f-f96f110d83cf.png)
<br>
サーバ側のEntityからもデータの同期が確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3785085/28350840-ba15-6ab7-cfad-5975ac90a150.png)

### 最後に
簡単なオフライン登録処理の実装を行いましたが、複雑な複数テーブルのデータ登録処理や検索時のデータ同期、排他制御なども考慮するのかなり難易度が高い実装になりそうです。気軽にホイホイというよりは最初にアーキテクトの設計を十分に実装して作りこむ必要がありそうですね。