昨年OutSystemsに追加された新機能、PWA (Progessive Web Apps) を作成する手順です。
簡単なアプリケーション(個人で利用する血圧管理用アプリケーション)を作ってみます。
Table of Contents
対象読者
- Service Studioの基礎的な操作を知っている人
- 以下の前提条件を満たすPersonal Environmentを持っている人
プログレッシブWebアプリ(PWA)として配布の「前提条件」に記載されている条件。
OutSystems開発経験がある人向けの簡単なまとめ
- プラグインの制限に気をつけつつモバイルアプリケーションを用意
- Service Studioでアプリケーションを開く
- Distributeタブを開いて、Distribute as PWAスイッチをオンにする
これだけで利用できます。
PWA概要
PWAは、ネイティブアプリのような見た目で、iOS/Androidにインストールできるアプリケーションをストアを介さずに配布できるものです。
通常、PWAを提供するには、Service WorkerやManifestといったものを作成しなければいけません。しかし、OutSystemsを使う場合は、その部分は基盤が面倒を見てくれます(カスタマイズすることもできる)。
OutSystemsのPWAは、モバイルアプリケーションを作成し、PWAを有効にするスイッチを入れるだけで機能します。
仕様検討
この手順で作成するアプリケーションは、以下のような簡単な仕様にしてみました。
- 血圧、脈拍を測定、時間を登録
- 1日に登録できるデータは1件のみ
- 結果はローカルに貯めて、自分で結果を見られる
- カレンダー画面を用意し、データを登録/表示する日を選択できる
モバイルアプリケーション・モジュールを作成
Service Studioでアプリケーションを作成します。
アプリケーション一覧画面で、New Applicationを選択。
「How do you want to start?」ダイアログで、Start from scratchを選択して「NEXT」ボタンをクリック。
「What are you building?」ダイアログでは、「Phone App」を選択します[1]モバイルアプリケーションであればよいので、Tablet Appでもよい。
アプリケーション名と説明を入力し、「CREATE APP」ボタンをクリック。
OutSystemsでは、モジュールが実際に動作する単位であり、アプリケーションはその入れ物。アプリケーションができたので、今度はモジュールを作成しましょう。
Choose module typeでアプリケーション作成時に選択したテンプレート名と同じ「Phone App」を選択して、「CREATE MODULE」。モジュールが作成できたらF5キーを押すか、Service Studio上の緑の○をクリックしてPublishしてください。
Publishが終わったら、再びアプリケーション画面に戻り、「Distribute」タブを開く。すると、右側に「Distribute as PWA」というスイッチがあるのでこれをオンにすれば、PWAとして動く準備は完了。
ここからは、モバイルアプリケーションの中身を作っていきます。
Local Entity設計
Local Entityというのは、アプリケーションをインストールする端末内にデータを保存するEntityのことです。
PWAなので計測したデータは端末内に保存することにします。
Service Studio右上のDataタブ > Entitiesフォルダ > Local Storageを右クリックして「Add Entity」を選択。するとLocal Entityができるので以下のように設定します。
EntityのNameプロパティ:Measurement
(作成されたEntityをクリックして選択すると右下にプロパティ編集用のUIが表示されるので、そのNameプロパティの値を編集する)
作成したEntityを選択して右クリックし、「Add Entity Attribute」を選択するとEntityの属性を追加できます。
以下の4つの属性を追加しました。
Data Typeはその属性にどんなデータを入力できるか、Is Mandatoryはデータベースにデータを格納する際に、その属性は入力必須かどうか、を指定するプロパティです。
- MeasuredAt
- Description:測定日時
- Data Type:Date Time
- Is Mandatory:Yes
- SystolicBloodPressure
- Description:収縮期血圧
- Data Type:Integer
- Is Mandatory:Yes
- DiastolicBloodPressure
- Description:拡張期血圧
- Data Type:Integer
- Is Mandatory:Yes
- Pulse
- Description:脈拍
- Data Type:Integer
- Is Mandatory:Yes
画面設計
次に画面を作っていきます。
まずはメイン画面。Service Studio右上のInterfaceタブ > UI Flowsフォルダ > MainFlowを選択して、ショートカットキー「Ctrl+N」を入力[2]画面作成時の画面テンプレート選択を省略するためショートカットキーを利用している。
カレンダー
作成された画面の名前を変更(作成した時点であれば編集状態。F2を押せば再び編集状態になります)して「Calendar」にします。
この画面は以下の仕様にします。
- 上半分に月間カレンダー、下半分に選択した日のデータ入力フォームを配置
- データ入力済みの日付にはマークを付ける
- データ入力済みの日付を選択すると、データ入力フォームにそのデータを表示
- データ入力フォームに入力したデータをデータベースに登録できる
カレンダーを表示
カレンダーを表示する部品は、「DatePicker」です。
Service Studio左上の「Search… (Ctrl+E)」にdateと入力すると、自動的に該当Widgetのみに絞り込まれます。
表示された「Date Picker」のアイコンを画面にドラッグ&ドロップして配置してください。
ドロップする前にマウスを止めて、画面右に表示されたWidget Tree上で「Content」Placeholderが点滅しているのを確認してから離すようにしてください[3]変な場所に配置されてしまうのを防ぐため。
このWidgetは、日付を選択したときのイベントハンドラーが必須であるため、デフォルトでは、プロパティ一番下のOnSelectのHandlerが赤くなっています[4]エラーが有ることを示す。Handler右のドロップダウンリストを展開し、「New Client Action」を選択してください。
これで自動的にイベントハンドラーが作成されます。
この時点ですでに当月のカレンダーが表示される状態になっています。
カレンダー上で選択した日付を持っておく変数が必要なので、画面に「SelectedDate」変数を用意します。画面を右クリックして、Add Local Variableで追加できます。
用意した変数のDefault Valueに「CurrDate()」(今日の日付)を設定しておいてください。また、この変数をカレンダーのInitialDateプロパティに設定しておくと、後でデータを更新するときに選択日付が戻るのを防げるので設定しておいてください。
用意したハンドラー((デフォルトでは「DatePickerOnSelect」のような名前になる))をダブルクリックして開き、画面左のツールボックスからAssignをおいて、「SelectedDate = StartDate」を設定します。StartDateはイベントハンドラーについてくるパラメータです。カレンダー上で選択した日付を表すもの。
データ入力済みの日付にカレンダー上でマークをつける
カレンダー部品には、EventListというプロパティがあり、日時型のListを設定すると、日付の下に「●」で表示してくれるという機能があります。
そこでここに、すでに血圧測定を行っている日時型のListを渡して置きます。
Calendar画面を右クリックして、「Fetch Data from Local Storage」を選択するとAggregate[5]OutSystemsでデータ検索を行うための機能。GUIで検索条件を設定できるが自動作成され、編集画面が開きます。
Aggregateの編集画面に、Local Entity 「Measurement」をドラッグ&ドロップしてMeasurement検索設定を開始します。Filterに、今月測定されたデータを返す条件を追加してください。
例:Year(Measurement.MeasuredAt) = Year(SelectedDate) and
Month(Measurement.MeasuredAt) = Month(SelectedDate)
こうして用意したAggregateの取得結果を、カレンダーのEventListプロパティに設定します。
この場合、データ型が違う(Aggregateの結果はMeasurement Listで、EventListプロパティがDateTime List)ので、Mappingを指定する必要があります。Valueには「Measurement.MeasuredAt」です。
登録フォーム
登録フォームを自動作成
次に画面下部に登録フォームを配置します。
登録フォームの作成にはOutSystemsのUI自動作成機能が使えます。
今度はForm Widgetを先程のDate Pickerの下の位置にドラッグ&ドロップで配置してください。
次に、作っておいたLocal Entity「Measurement」を配置したForm((下のスクリーンショットでは黄色い枠で囲まれている部分))にドラッグ&ドロップすると、入力UIとそこに表示するデータを取得するAggregateが自動作成されるはず。
登録フォームを修正
この状態だと、画面をLocal Entityの主キーをパラメータで開くことを前提として、そのIdで検索する処理になっています。実際には画面上で選択した日付で検索したいのでそこを修正します。
まず画面にあるInput Parameter「MeasurementId」は不要なので、選択してDelキーで消してしまいます。代わりに今開いている日付を表すSelectedDateを追加します。画面を選択して右クリック→Add Local Variableし、名前をSelectedDateに変更。この時点でDate Typeは名前から推測されてDate型になっているはずですが、念の為確認してください。
次にAggregateを修正しましょう。
まず名前を修正します。適切な名前がついていないと保守時に混乱の元となるためです。GetMeasurementByIdをGetMeasurementBySeletedDateに変更。
名前を修正したら、Aggregateをダブルクリックして、Aggregateの変更画面を開く。
画面上部の「Filters」内に既にある「Measurement.Id = MeasurementId」の条件を右にあるゴミ箱のアイコンをクリックして削除。
別の条件を追加します。「Add Filter」開いたダイアログで「DateTimeToDate(Measurement.MeasuredAt) = SelectedDate」という条件を設定
また、本来Date Time型であるMeasuredAt属性ですが、実際には日付はカレンダーで固定されているため、フォーム内で入力するのは時刻のみです。この部分を対応します。
まず、Calendar画面にEnteredTime変数を追加。Data TypeはTime型になっているはず。なっていなかったら修正してください。
フォーム上で「Measured At」の下のInputを選択し、VariableをEnteredTime、Input TypeをTimeに変更します。これで時刻を設定するように入力部品を変更できました。
カレンダーで日付を選択したときの処理を変更する
選択した日付が変わったときには、新しい日付のデータをフォームに表示したいのでその対応をします。
DatePickerOnSelect Actionを開き、Assignの下にRefresh Dataを画面左のツールボックスからドラッグ&ドロップし、Data Sourceプロパティにフォームに紐付けたAggregateを指定します。
次にEnteredTimeに、以前に入力したときのMeasured Atから時刻を設定する手順。
フォームに紐付けたAggregateを選択し、On After Fetchプロパティ右のドロップダウンリストを展開し、New Client Action。このActionはAggregate取得完了後自動で動作するもの。
作成されたActionにAssignを配置し、「EnteredTime = DateTimeToTime(GetMeasurementBySelectedDate.List.Current.Measurement.MeasuredAt)」とします。検索結果の測定日時属性から時刻を取得してEnteredTimeに設定しています。
保存処理の実装
再び画面「Calendar」をダブルクリックして画面を開いてみてください。
下の方にあるSaveボタンが赤い枠になっていると思います。これも必要な設定がなされていないことを表します。ボタンの場合はクリックしたときのハンドラーが必須です。今度はボタンをダブルクリックしてハンドラーを作成してみましょう。
作成したら以下の赤枠の部分を追加します。順に、
- 更新対象レコードのMeasuredAtへのAssign:「GetMeasurementBySelectedDate.List.Current.Measurement.MeasuredAt = BuildDateTime(SelectedDate, EnteredTime)」(カレンダーで選択した日付とフォームで入力した時刻から日時データを作る関数を呼んでいる)
- CreateOrUpdateMeasurement Action:SourceにGetMeasurementBySelectedDate.List.Currentを設定(フォームで入力していたレコード)
- Measurement Local Entityの下にあるのでドラッグ&ドロップで配置してください
- カレンダーに表示する入力済みを示すデータを再取得するRefresh Data:「データ入力済みの日付にカレンダー上でマークをつける」で用意したAggregateを指定。カレンダーの「●」表示を更新するためです
- 更新ができたことを示すMessage:表示するテキストは何でもいいです
インストール・利用方法
実装が終わったらPublish(F5キーか、画面上部の緑の●をクリック)して動作確認をしておきましょう。
Windowsの場合
「Distribute as PWA」のスイッチを入れると表示されるQRコードの右側に「click here to open in the browser」というリンクが有るのでこれをクリックすると、ブラウザで開きます。URLは「https://ホスト/モジュール名」という構成。
Chromeでアプリケーションが開きます。アドレスバー右側のアイコンをクリックするとWindowsにもインストールできました。
インストールしたPWAを起動するとこんな感じの画面です。操作は①カレンダー上で日付を選択②画面下部のフォームで4項目全て入力してSaveボタンをクリック③いくつかの日付で①-②を繰り返す。
iOSの場合
iOSにインストールするには
- カメラアプリでQRコードを読み取る(メール等でURL連携でもよい)
- ブラウザでアプリが開く
- Shareボタン(上向き矢印が出ているアイコン)をタップ
- ホーム画面に追加をタップ
Androidの場合
ブラウザで開くまでは同じですが、Androidでは、画面下部にホーム画面に追加するためのリンクが表示されます。