Code Push（Flutter）を触ってみた

## 概要

アプリ開発をしていて、急な仕様変更やバグ修正が発生した時に
「申請通さなきゃ...」とか「アップデート版を浸透させなきゃ...」とか
本当に悩ましい問題だなと感じながら日々仕事をしていました。

そんな時に以下の記事を見つけて「すげぇ」ってなったので触ってみることにしました。

https://zenn.dev/tsuruo/articles/13687d8455d1b1

## Code Pushって何？

記事内でも言及されていますが、簡単にいうと
**ストアを介さずにコードを修正できるツール**です。
これによって、

- 申請を通すのに時間がかかる
- アップデートしてくれたユーザーしか変更が反映されない

といったアプリ特有の課題を全て解決してくれそうです。
Apple / Googleがよく怒らないな...と感心。

使えるのはReactNativeとFlutterだけっぽいです。
ReactNativeは結構前から技術あったみたいですね...

https://qiita.com/wktq/items/6083d96ff60a547cf15a

今回はFlutterで触ってみることにします。

## 環境

- Mac OS Monterey 12.6.3
- Android Studio Giraffe | 2022.3.1
- Flutter 3.13.1
- Dart 3.1.0

## 本題

実際に使ってみます。

#### Code Pushの導入

まずはFlutterプロジェクトを作成します。
Flutterの導入方法については、以下の記事が参考になると思います。

https://qiita.com/nero-15/items/c37ef6cc62a8eb34a331

今回は簡単に以下のように作りました。

```dart
Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Code Push Test'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              height: 100,
              width: 200,
              color: Colors.red,
              alignment: Alignment.center,
              child: const Text(
                  "野球",
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 20,
                ),
              ),
            ),
            Container(
              height: 100,
              width: 200,
              color: Colors.blue,
              alignment: Alignment.center,
              child: const Text(
                  "サッカー",
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 20,
                ),
              ),
            ),
            Container(
              height: 100,
              width: 200,
              color: Colors.pink,
              alignment: Alignment.center,
              child: const Text(
                  "バレーボール",
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 20,
                ),
              ),
            ),
          ],
        )
      )
    );
  }
```

表示させると以下のようになります。

<img width="200" alt="Screenshot_20230901_055945.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1441550/befe57d6-89db-fead-e20c-d1d0b23c6e00.png">

続いて、Flutter用のCode PushはShorebirdが開発しているとのことなので、早速公式を見てみます。

https://shorebird.dev/#products-code-push

ログインすると導入手順が出てくるので、それに従って操作していきます。
（実際の操作はログインして確認してみてください）

#### 初期化

初期化用のコマンドを実行します。

![スクリーンショット 2023-09-01 4.20.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1441550/17fa7aa8-631f-a639-7d52-3ed5ebe72892.png)

ここではshorebird.yamlを生成して、shorebirdをプロジェクトに埋めてるっぽいです。

#### リリース

続いてリリースコマンドを実行。

![スクリーンショット 2023-09-01 15.51.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1441550/9b84db1e-400b-d3e3-6e23-fbca058b570b.png)

shorebirdも含めたaabファイルを作成しています。
このバイナリを実際にストア公開する形になります。
今回は**この状態でapkを作成し、エミュレータにインストール**しておきます。

#### 書き換えた処理を反映させてみる

では、ここまででリリースしたと仮定して、一部コード変更を反映させてみます。
今回はScaffoldの中のColumnをRowに変更します。

```diff_dart
return Scaffold(
    appBar: AppBar(
        title: const Text('Code Push Test'),
    ),
    body: Center(
-       child: Column(
+       child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
                // 中略
            ],
        )
    )
);
```

このコード変更を行った状態でpatchのコマンドを実行します。

![スクリーンショット 2023-09-01 15.57.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1441550/56b520ad-8a2f-82ce-a40e-e741984fd5e2.png)

これで完了したっぽいです。

#### 結果

エミュレータ上のアプリを再起動したところ、以下の様な表示に変わっていました！

<img width="200" alt="after.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1441550/fcac2433-d0f8-e505-f0a1-f514610f0e1f.png">

この間、エミュレータへのビルドも行っていないので、Code Pushが正常に動いていると判断できました。

shorebird上のコンソールを確認すると、新しいpatchがアップロードできていました。

![スクリーンショット 2023-09-01 16.04.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1441550/52a3deb8-3314-59b0-dc34-293a7b0d7671.png)

## 考察

起動時の処理としては以下のようになっているのかな？と実装しながら考えてました。configを読み込む要領でコード自体を読み込むイメージですね。（あくまで推察です）

```mermaid
graph TD
    A("アプリ起動")-->B["shorebirdのBEから\n最新パッチverを取得"]
    B-->C{"アプリverと最新パッチverが同じ"}
    C-->|YES|D("runApp")
    C-->|NO|E["最新パッチを取得しコード反映"]
    E-->D
```

ネイティブ言語でCode Pushがないのも少し納得です。（**あくまで推察です**）

## 感想

手軽に変更を反映できるというのはかなりいいと思いますが、その分リスクも大きいなぁ...と感じています。Code Pushで触れる範囲が限定できる、とかができれば嬉しいですね。

## 最後に

運動通信社は「日本を世界が憧れるスポーツ大国にする」というビジョンを達成するべく、一緒に働く仲間を募集しています！
PMやアプリエンジニア、Webエンジニアなど色んな職種を募集しておりカジュアル面談大歓迎なので是非採用フォームよりご連絡ください！
ぜひ一緒に、自分たちも世の中もワクワクさせるサービスを作りましょう！

https://sportsbull.jp/about/#recruit

https://www.green-japan.com/company/9598