Push通知を有効にしたFlutterアプリGitHub Actionsで配布したらAPNS Tokenが取得できなかった件

:::note warn
2024/11/24 追記：
結論だめでした。が、知見のため残しておきます。

この記事の内容をGitHub ActionsのRunner上で実行する場合、毎回クリーンな環境となるので開発者証明書が毎回Apple Developerに登録されてしまいます。

これを回避するには、開発者証明書をSecretsに登録し、Keychainにimportしてから `xcodebuild archive` します。
ただし、開発者証明書は有効期限が１年間なので毎年入れ替える必要があります。
:::


## TL;DR

Push通知をCI/CD上でxcodebuildを使ってビルドする場合、`xcodebuild archive` 時にもコード署名しよう。

```
flutter build ios --config-only --release --build-number=$BUILD_NUMBER $VERSION -t $ENTRY_POINT --no-codesign --dart-define-from-file=$ENV_FILE_PATH
xcodebuild \
  archive \
  -workspace ios/Runner.xcworkspace \
  -scheme Runner \
  -sdk iphoneos \
  -configuration Release \
  -archivePath build/ios/Runner.xcarchive \
  -allowProvisioningUpdates \
  -authenticationKeyIssuerID $APP_STORE_CONNECT_API_KEY_ISSUER_ID \
  -authenticationKeyID $APP_STORE_CONNECT_API_KEY_ID \
  -authenticationKeyPath $P8_FILE_PATH

xcodebuild \
  -exportArchive \
  -archivePath build/ios/Runner.xcarchive \
  -exportOptionsPlist $EXPORT_OPTIONS_PLIST \
  -exportPath build/ios/ipa \
  -allowProvisioningUpdates \
  -authenticationKeyIssuerID $APP_STORE_CONNECT_API_KEY_ISSUER_ID \
  -authenticationKeyID $APP_STORE_CONNECT_API_KEY_ID \
  -authenticationKeyPath $P8_FILE_PATH
```


## 経緯

* Firebase Messagingを利用するFlutterアプリを作成していた
* ローカルビルドでPush通知を受け取れることを確認して、Firebase App Distributionで配布した→これは正常にPush通知を受け取れた
* GitHub ActionsでFirebase App Distributionに配布するワークフローを組んで配布した
* iOSの署名はXcode Cloudでの自動署名
* Androidは問題なかったがiOSで `FirebaseMessaging.instance.getToken()` を実行する箇所で `apns-token-not-set` エラーが発生した

```
[firebase_messaging/apns-token-not-set]APNS token has not been set yet. Please ensure the APNS token is available by calling `getAPNSToken()`.
```

## 解決へ

:::note alert
解決していないので記事先頭の追記をみてね
:::

[こちらの記事](https://zenn.dev/ohtsuki/scraps/799e5b7c3f2498#:~:text=2024/01/29-,%E5%BE%8C%E6%97%A5%E8%AB%87,-DeployGate%E9%85%8D%E4%BF%A1%E3%81%A8%E5%90%8C%E6%99%82%E3%81%AB)でExportする際にもコード署名をしないと、生成されるIPAに `	[Key] aps-environment` が付与されず、Push Notificationが有効にならない。 

https://github.com/flutter/flutter/issues/129075

IPAに含まれるEntitlementsを比較したところ、確かに `aps-environment` が設定されていなかった。

* ローカルビルド(XcodeでExport)
```
%> codesign -d --entitlements - Payload/Runner.app
Executable=/Users/nitakan/Desktop/Runner 2024-11-24 00-55-51/Payload/Runner.app/Runner
[Dict]
	[Key] application-identifier
	[Value]
		[String] XXXXXXXX.com.example.app
	[Key] aps-environment
	[Value]
		[String] production
	[Key] com.apple.developer.team-identifier
	[Value]
		[String] XXXXXXXX
	[Key] get-task-allow
	[Value]
		[Bool] false

```


Github Actionsでビルド(xcodebuildでexport)

```
%> codesign -d --entitlements - ~/Downloads/Payload/Runner.app
Executable=/Users/nitakan/Downloads/Payload/Runner.app/Runner
[Dict]
	[Key] application-identifier
	[Value]
		[String] XXXXXXXX.com.example.app
	[Key] com.apple.developer.team-identifier
	[Value]
		[String] XXXXXXXX
	[Key] get-task-allow
	[Value]
		[Bool] false
```


当初のビルドコマンド

```
flutter build ios --config-only --release --build-number=$BUILD_NUMBER $CMD_VERSION -t $ENTRY_POINT --no-codesign --dart-define-from-file=$ENV_FILE_PATH  $DEVELOPER  $CI
xcodebuild \
  -workspace ios/Runner.xcworkspace \
  -scheme Runner \
  -sdk iphoneos \
  -configuration Release archive \
  -archivePath build/ios/Runner.xcarchive CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
xcodebuild \
  -exportArchive \
  -archivePath build/ios/Runner.xcarchive \
  -exportOptionsPlist $EXPORT_OPTIONS_PLIST \
  -exportPath build/ios/ipa \
  -allowProvisioningUpdates \
  -authenticationKeyIssuerID $APP_STORE_CONNECT_API_KEY_ISSUER_ID \
  -authenticationKeyID $APP_STORE_CONNECT_API_KEY_ID \
  -authenticationKeyPath $P8_FILE_PATH
```

ここから `CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO` を削除し、`exportArchive` 時と同様にコード署名するようにした。

```
flutter build ios --config-only --release --build-number=$BUILD_NUMBER $VERSION -t $ENTRY_POINT --no-codesign --dart-define-from-file=$ENV_FILE_PATH
xcodebuild \
  archive \
  -workspace ios/Runner.xcworkspace \
  -scheme Runner \
  -sdk iphoneos \
  -configuration Release \
  -archivePath build/ios/Runner.xcarchive \
  -allowProvisioningUpdates \
  -authenticationKeyIssuerID $APP_STORE_CONNECT_API_KEY_ISSUER_ID \
  -authenticationKeyID $APP_STORE_CONNECT_API_KEY_ID \
  -authenticationKeyPath $P8_FILE_PATH

xcodebuild \
  -exportArchive \
  -archivePath build/ios/Runner.xcarchive \
  -exportOptionsPlist $EXPORT_OPTIONS_PLIST \
  -exportPath build/ios/ipa \
  -allowProvisioningUpdates \
  -authenticationKeyIssuerID $APP_STORE_CONNECT_API_KEY_ISSUER_ID \
  -authenticationKeyID $APP_STORE_CONNECT_API_KEY_ID \
  -authenticationKeyPath $P8_FILE_PATH
```

そうすると、以下のようなipaが出力された。

```
%> codesign -d --entitlements - ~/Downloads/Payload\ 2/Runner.app
Executable=/Users/nitakan/Downloads/Payload\ 2/Runner.app/Runner
[Dict]
	[Key] application-identifier
	[Value]
		[String] XXXXXXXX.com.example.app
	[Key] aps-environment
	[Value]
		[String] production
	[Key] com.apple.developer.team-identifier
	[Value]
		[String] XXXXXXXX
	[Key] get-task-allow
	[Value]
		[Bool] false
```



## その他

Codemagicで配布している別のアプリは上記のようなビルド設定を自動的にしているのであろう。
開発者証明書は自力で管理していそう。