Power Apps スプラッシュ画面のススメ

Power Apps ではアプリの起動時の処理を書く場所として App.OnStart が、アプリ起動後に最初に表示する画面を定義する場所として App.StartScreen が用意されています。しかしアプリの要件によってはそれらの場所に処理・定義を実装するのが難しい場合があります。

私がとある Power Apps アプリを作ったときもそういった状況でしたが、それらの課題を解決するためにスプラッシュ画面をつくりました。

この記事では、スプラッシュ画面をつくることにした経緯、各箇所のコード、および実装理由とメリット・デメリットを説明します。アプリを実装する際のご参考になれば幸いです。

## 経緯

とある Power Apps アプリを作ったときのこと。
そのアプリでは以下の2つの要求があり、それぞれで課題を抱えていました。

### 課題1: データ参照
データソースは複数の SharePoint リスト。リスト同士の参照関係がないため、 Power Apps アプリ内で LookUp 関数を使って参照を実装することになりました。
コンフィグ情報やマスタデータはアプリ内で頻繁に参照する必要がありました。ただしそれらは頻繁に更新されるものではなかったため、アプリの起動時にデータを読み込みグローバル変数に格納しておいて、アプリ使用中に変数を都度参照する必要がありました。
しかし Power Apps ではアプリの起動時の処理は App.OnStart に記載することが多いですが、
仕様上、最初の画面の OnVisible 処理は App.OnStart の処理完了を待たないのです。
参考：
https://powerplatformnikki.com/formulasvsonstart/

もし App.OnStart の処理時間が長く、 また OnVisible イベントの処理が App.OnStart の処理結果に依存していると、 OnVisible 処理内で不具合が起きる可能性があるのです。

### 課題2: 最初の画面の表示条件

最初に表示する画面を何にするかは、SharePoint リストにどんなデータが格納されているかで変わります。
最初に表示する画面は通常、 App.StartScreen で定義されます。が、 SharePoint リストのデータを参照するといった複雑な処理を必要とする場合、処理を実行するタイミングをうまく調整することが難しい場合があります。

### 対策

対策として、アプリ起動時だけ表示される画面を用意しました。
その画面の OnVisibleにはアプリの起動時の処理を実装し、
起動時の処理が完了した後に、次の画面（ユーザーに最初に見せたい画面）に遷移します。
またせっかくなので、最初の画面をスプラッシュ画面としてデザインしてしまおう！　と考えました。

## アプリ・画面・コンポーネント・コード

サンプルアプリの構成を紹介します。
先述のスプラッシュ画面は、Power Appsアプリの実装上 "SplashScreen" という名前をつけました。

### App

#### App.StartScreen
SplashScreen を設定します。

#### App.OnStart
空っぽにします。

### 画面: SplashScreen

![20250331-144503.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260552/f499ba12-7bcc-4c25-a0ec-8963055f6b8d.png)

アプリの起動中を表すデザインをします。（上のスクリーンショットはサンプルのため、Spinner を置くのみにしました）
この画面で肝心なのは、画面の OnVisible イベントと、起動時の処理が実装されたボタン "Splash_HiddenButton_Init" です。

OnVisible
``` JavaScript
If(
    Or(
        IsBlank(gblAppInitedFlag),
        gblAppInitedFlag = false
    ),
    // 初回アクセス時: フラグの値を変えてボタンを押す
    Set(gblAppInitedFlag, true);
    Select(Splash_HiddenButton_Init);
);
```

ボタン "Splash_HiddenButton_Init"
画面上に表示されないよう、Visible プロパティに false を設定します。
そのうえで OnSelect に以下のコードを書きます。

OnSelect
``` JavaScript
// ---------------------------------------- データ取得

Concurrent(
    // 製品マスタ
    ClearCollect(
        gblProductMaster,
        ShowColumns(
            Filter(ProductMaster, DeleteFlag = 0),
            DisplayNameJa, ProductId, UnitPriceJpy
        )
    );
    ,
    // アカウントマスタ
    ClearCollect(
        gblAccountMaster,
        ShowColumns(
            Filter(AccountMaster, DeleteFlag = 0),
            DisplayNameJa, Email, IsAdmin
        )
    );
    ,
    // コンフィグ
    ClearCollect(
        gblConfig,
        ShowColumns(
            Filter(Config, DeleteFlag = 0),
            ConfigKey, ConfigValue
        )
    );
);

// ---------------------------------------- データ加工

// 自分のアカウント情報を取得
Set(
    gblMyAccountInfo,
    LookUp(gblAccountMaster, Email = User().Email)
);

// 管理者フラグ (私が管理者かどうか)
Set(gblAmIAdmin, false);
If(
    And(
        !IsBlank(gblMyAccountInfo),
        gblMyAccountInfo.IsAdmin = 1
    ),
    Set(gblAmIAdmin, true);
);

// ---------------------------------------- 画面遷移先

// デフォルトの遷移先
UpdateContext({locNextScreen: MainScreen});

// 自分自身が管理者である場合は画面遷移先を変える
If(
    gblAmIAdmin,
    UpdateContext({locNextScreen: AdminScreen});
);

// ---------------------------------------- 画面遷移する

Navigate(locNextScreen);
```


### 画面 "MainScreen" と "AdminScreen"

今回のサンプルでは、SharePointリスト "AccountMaster" に
管理者権限のある人がアプリを起動すると最初に AdminScreen が表示され、
管理者権限のない人に対しては MainScreen を表示する、という処理をするものとします。

### 画面: DevScreen

![20250331-160515.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260552/a5979cde-796a-4deb-9d0a-634d3d3b00bd.png)

開発作業をスムーズに進めるために、開発に使用する処理を実装した、開発専用の画面を用意しました。
実装上、アプリの利用者がこの画面に移動することがないように、他の処理を実装します。

#### ボタン Dev_Restart

アプリの起動処理を再実行するボタンです。
開発時はこのボタンを押すことで、アプリの起動処理を再実行させることができます。

ボタン Dev_Start の OnSelect イベント
``` JavaScript
// アプリ初期化フラグを戻す
Set(gblAppInitedFlag, false);

// 画面遷移する
Navigate(SplashScreen);
```

## 上記の実装をする理由


### SplashScreen.OnVisible の処理を If で囲む理由

アプリの編集をスムーズに行うためです。

もし If なしに実装してしまうと、Power Apps Studio で編集中に SplashScreen を選択した時、OnVisible 処理が動いて、すぐに次の画面に遷移してしまうのです。
そう、SplashScreen を編集できなくなってしまいます。

そこで gblAppInitedFlag 変数を用意します。
OnVisible イベントの冒頭で gblAppInitedFlag 変数を使って条件分岐することで、アプリの編集中に SplashScreen を選択しても処理が止まってくれるようになるのです。

ただしこれだけの実装では、 OnVisible の処理は Power Apps Studio の起動時 1回のみしか動いてくれません。
そこで作業中に初期処理を再度実行できるようにするため、 DevScreen と Dev_Restart ボタンを用意するのです。
Dev_Restart ボタンを押すと、SplashScreen.OnVisible の処理が再度動いてくれるようになります。

DevScreen は構成要素自体はシンプルなので、リリース時に消さずに残しておいても良いですし、消しても問題ありません。


### SplashScreen.OnVisible の処理上でボタンを Select する理由

アプリ起動時の処理は、 SplashScreen.OnVisible ではなくボタン Splash_HiddenButton_Init に実装しています。
というのも Power Apps の仕様上、 OnVisible の処理内で Navigate 関数（画面遷移処理）を実行することができないためです。
そこで対策として、処理本体をボタンに実装したうえで、 OnVisible ではそのボタンを押す処理を行っています。



### コンテキスト変数 locNextScreen を使う理由

コンテキスト変数 locNextScreen は、SplashScreen.OnVisible の処理完了直後に何の画面に遷移させるかを定義するために使われます。
Power Apps 既定で用意されている App.StartScreen に相当する処理をさせています。

今回のサンプルでは SharePoint リストのアイテムのデータを参照して画面を切り替えていますが、
アプリによってはさらに複雑な処理を実装することになるかもしれませんので、その際にも流用できるように、コンテキスト変数を使って制御しています。




## 上記の実装のメリット・デメリット


### メリット： 初期処理が長くなっても問題なく動作する
App.OnStart とは異なり、たとえ初期処理が長い時間かかろうとも着実に処理してくれます。


### メリット： 初期処理後の遷移先について複雑な実装ができる
初期処理が完了した後に遷移させたい画面について、より複雑な条件を実装できるようになります。


### デメリット： Analytics "最初の画面までの時間" を正確に計測できなくなる
Power Apps の Analytics では、最初の画面までの時間を確認することができます。
SplashScreen を実装したアプリでは、 SplashScreen が表示されるまでの時間が計測されてしまうため、 SplashScreen 上で行われた処理の時間はカウントされません。


## まとめ

アプリの起動時にどのような処理を行うかは、アプリの使われ方といった条件によって異なります。
起動時の処理が多くなるほどに、ユーザーがアプリを使い始めるまでの時間が長くなるため、その点では使いにくいものになります。
しかし一方で、必要なデータを起動時に読み込んでおくことで他の処理を速くすることができる場合もあります。

スプラッシュ画面を用意することで、起動時により多くの処理を実装できるようになるため、
アプリ利用時の全体的なパフォーマンス向上をするためのチューニングの幅が広がりますので、
とくに複雑な処理を行うアプリを作る際には、スプラッシュ画面を採用するかどうか検討してみると良いかと思います。




## セカンドファクトリーでは、エンジニアメンバーを大募集しています！

Microsoftプラットフォームを使い倒し、クライアント企業の事業課題を解決したい方、私たちと一緒に経験を積んでみませんか？ローコード・ノーコード、生成AIなど、エンジニアを取り巻く環境は大きく変化しています。チームで一緒に楽しみながら、エンジニアとしての価値を高めたいと思っている方がいらっしゃいましたら、以下の求人情報からお気軽にご応募ください！皆さんとお話できることを楽しみにしています！

【PowerPlatformを使い倒して、事業を変革する仕事に挑戦したい方】PowerPlatformエンジニア募集！／チームと一緒に企画段階から関わりたい方、大歓迎

https://www.green-japan.com/company/7387/job/270032