👨‍🎓

Flutterのデスクトップスタンドアロンアプリケーションの自動更新パッケージを作ったfromGithubAssets

に公開

はじめに

こんにちは、Rerurate_514と申します。
今回はあるFlutterパッケージを作成しました!

今回作成したパッケージの名前はStandalone_application_updaterです。
名前の通り、デスクトップスタンドアロンアプリケーションの自動更新パッケージになります。
https://github.com/Rerurate514/standalone_application_updater

pubにもあります。
https://pub.dev/packages/standalone_application_updater

install:

flutter pub add standalone_application_updater

概要

まず、このパッケージは[[Github]]のReleaseのアセットに最新版ファイルが存在するかをか確認します。
これのことです。

まず、このタグが現行で動いているアプリのバージョンより高い場合、まずそれを報告します。

そして、そこにファイルが存在している場合にダウンロードを行います。
この場合、.sha256がある場合、整合性チェックもすることができます。

さらに、ダウンロードした後、ファイルを解凍、実行までやってくれるものです。

実際のコード

まず、logを出すか出さないかを決めます。大体はなしでもいいです。

final config = SauConfig(
	enableLogging: true,
);

そして、アプリのインスタンスを取得します。

final updater = StandaloneApplicationUpdater.instance;

これがなぜこのような形になっているかというと、OSごとの動作にパッケージが依存する場合、このような形をとることで、パッケージ利用者がOSごとのクラスをインスタンス化する必要がなくなるのです。

そして以下のコードで、Githubのリリースタグが最新のものかどうかを取得できます。

final updateCheckResult = await updater.checkForUpdates(
    RepositoryInfo(
	    owner: "リポジトリオーナー名", 
	    repoName: "リポジトリ名"
    ), 
    config
  );

ここで帰ってくる値はUpdateCheckResult型です。
このとき、最新のタグがある場合、サブクラスのUpdateCheckAvailableが返ってくるので、それで判定します。

if(updateCheckResult is UpdateCheckAvailable) {
	// ...
}

最新版が存在する場合、次のダウンロードフェーズに移れます。

final downloadResult = await updater.downloadUpdate(
	updateCheckResult, 
	config, 
	savePath: "C:\\Users\\rerur\\Downloads"
);

これはavailable判定ifの中です。
downloadUpdateUpdateCheckAvailable型しか受け付けません。

そしてこのコードではDownloadUpdateResult型が返ってくるので、それを判定します。

switch(downloadResult) {
  case DownloadUpdateSuccess(): {
	print("ダウンロードの成功");
  }
  case DownloadUpdateFailure(): {
	print("ダウンロードの失敗");
  }
}

ダウンロードは、Stream形式でも行うことができます。

updater.downloadUpdateStream(
	updateCheckResult,
	config
).listen((downloadResult) {
  switch(downloadResult) {
	case DownloadUpdateStreamProgress(): {
	  print("ダウンロードの進行中: ${downloadResult.downloadProgress.percentage}%");
	}
	case DownloadUpdateStreamSuccess(): {
	  print("ダウンロードの成功");
	}
	case DownloadUpdateStreamFailure(): {
	  print("ダウンロードの失敗");
	}
  }
});

さらにダウンロードを成功した後、asset内に.sha256ファイルがある場合、それの整合性チェックを行うことができます。
checkSHA256メソッドはDownloadUpdateSuccessまたはDownloadUpdateStreamSuccessしか受け付けません。
この整合性チェックはオプションです、やらないともよいです。

print("ダウンロードの成功");

final isSHA256Valid = await updater.checkSha256(downloadResult, config);

switch(isSHA256Valid) {
  case Sha256CheckValid(): {
		print("SHA256の整合性が確認できました。");
  }
  case Sha256CheckInvalid(): {
		print("SHA256が一致しません。");
  }
  case Sha256CheckNotExist(): {
		print("SHA256ファイルが指定されたパスにが存在しません。");
  }
  case Sha256CheckFailed(): {
		print("SHA256ファイルのダウンロード中に問題が発生しました。");
  }
}

さらにダウンロードしたファイルを自動で実行することもできます。

print("SHA256の整合性が確認できました。");

updater.applyUpdate(
  downloadResult, 
  "zipファイルの中の実行ファイルまでのパス", 
  config,
  isAutoExit: true
);

これで自動アップデートを実行することができます!

さいごに

今回学んだこと

  • [[OSごとのインスタンス化を利用者に意識させないパッケージの構築方法]]
  • [[Cryptoパッケージの使い方]]
  • [[FreezedでResultクラスを作成するのがいい]]
  • [[stream]]について
    • yield*は帰ってきたStreamの値をそのまま渡すもの
  • GithubAPIはめっちゃ高性能

そもそも、このパッケージは自分のデスクトップアプリ用に作成したものなのですが、友達も使う予定があるアプリだったので、自動更新を簡単にしたく、作成しました。
結構いい感じになったのではないのでしょうか。

ちなみに、自動実行はOS依存なのですが、これがwindows版しか作成できていないので、そこのPRが欲しかったり。。。。。

Discussion