Coding with Titans

so breaking things happens constantly, but never on purpose

Flutter for iOS and Push Notifications warning

After publishing a Flutter app to App Store I received following email:

Dear Developer,

We identified one or more issues with a recent delivery for your app, "pl.codetitans.app" 1.2.3 (4). Your delivery was successful, but you may wish to correct the following issues in your next delivery:

ITMS-90078: Missing Push Notification Entitlement - Your app appears to register with the Apple Push Notification service, but the app signature's entitlements do not include the 'aps-environment' entitlement. If your app uses the Apple Push Notification service, make sure your App ID is enabled for Push Notification in the Provisioning Portal, and resubmit after signing your app with a Distribution provisioning profile that includes the 'aps-environment' entitlement. Xcode does not automatically copy the aps-environment entitlement from provisioning profiles at build time. This behavior is intentional. To use this entitlement, either enable Push Notifications in the project editor's Capabilities pane, or manually add the entitlement to your entitlements file. For more information, see https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/HandlingRemoteNotifications.html#//apple_ref/doc/uid/TP40008194-CH6-SW1.

After you’ve corrected the issues, you can upload a new binary to App Store Connect.

Best regards,

The App Store Team

Thankfully it’s nothing critical and I could easily ignore it. However it started to be very disturbing as I received this email every time I published new build into Test Flight via fastlane. According to this explanation and this bug #9984 in Flutter repository it was triggered due to static implementation of UIApplicationDelegate inside the Runner and should be fixed years ago. Now, it’s late 2020, I am using Flutter v1.22.3 and the issue still persists.

Then, what I came out the easiest was to enable Push Notification Capability for the iOS app via proper entitlements definition (following this spec) without any real implementation. Smallest fix to get rid of the warning and this went smooth via Xcode. However at the same time Flutter totally lost the ability of building the app, while it was looking fine, when Runner was build inside Xcode 12.1. The reason could be pretty dull and could be a potential blocker for hours - during the signing phase appropriate provisioning profile couldn’t be found.

Full error looked like following:

# > fastlane beta
[✔] 🚀
[15:19:55]: fastlane detected a Gemfile in the current directory
[15:19:55]: However, it seems like you didn't use `bundle exec`
[15:19:55]: To launch fastlane faster, please use
[15:19:55]:
[15:19:55]: $ bundle exec fastlane beta
[15:19:55]:
[15:19:55]: Get started using a Gemfile for fastlane https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile
[15:19:59]: ------------------------------
[15:19:59]: --- Step: default_platform ---
[15:19:59]: ------------------------------
[15:19:59]: Driving the lane 'ios beta' 🚀
[15:19:59]: -----------------------
[15:19:59]: --- Step: build_app ---
[15:19:59]: -----------------------
[15:20:00]: Resolving Swift Package Manager dependencies...
...
...
[15:20:25]: ▸ Running script 'Thin Binary'
[15:20:28]: ▸ Running script '[CP] Embed Pods Frameworks'
[15:20:40]: ▸ Touching Runner.app (in target 'Runner' from project 'Runner')
[15:20:40]: ▸ Archive Succeeded
[15:20:40]: Generated plist file with the following values:
[15:20:40]: ▸ -----------------------------------------
[15:20:40]: ▸ {
[15:20:40]: ▸   "method": "app-store"
[15:20:40]: ▸ }
[15:20:40]: ▸ -----------------------------------------
[15:20:40]: $ /usr/bin/xcrun /usr/local/lib/ruby/gems/2.7.0/gems/fastlane-2.166.0/gym/lib/assets/wrap_xcodebuild/xcbuild-safe.sh -exportArchive -exportOptionsPlist '/var/folders/qr/7hltk2zx2878bpj92_40pqzh0000gn/T/gym_config20201105-30090-17dj6w1.plist' -archivePath /Users/pawel/Library/Developer/Xcode/Archives/2020-11-05/Runner\ 2020-11-05\ 15.20.03.xcarchive -exportPath '/var/folders/qr/7hltk2zx2878bpj92_40pqzh0000gn/T/gym_output20201105-30090-9h81do' 
+ xcodebuild -exportArchive -exportOptionsPlist /var/folders/qr/7hltk2zx2878bpj92_40pqzh0000gn/T/gym_config20201105-30090-17dj6w1.plist -archivePath '/Users/pawel/Library/Developer/Xcode/Archives/2020-11-05/Runner 2020-11-05 15.20.03.xcarchive' -exportPath /var/folders/qr/7hltk2zx2878bpj92_40pqzh0000gn/T/gym_output20201105-30090-9h81do
2020-11-05 15:20:42.150 xcodebuild[30648:2932072] [MT] IDEDistribution: -[IDEDistributionLogging _createLoggingBundleAtPath:]: Created bundle at path '/var/folders/qr/7hltk2zx2878bpj92_40pqzh0000gn/T/Runner_2020-11-05_15-20-42.150.xcdistributionlogs'.
error: exportArchive: No profiles for 'pl.codetitans.app' were found

Error Domain=IDEProfileLocatorErrorDomain Code=1 "No profiles for 'pl.codetitans.app' were found" UserInfo={IDEDistributionIssueSeverity=3, NSLocalizedDescription=No profiles for 'pl.codetitans.app' were found, NSLocalizedRecoverySuggestion=Xcode couldn't find any iOS App Store provisioning profiles matching 'pl.codetitans.app'. Automatic signing is disabled and unable to generate a profile. To enable automatic signing, pass -allowProvisioningUpdates to xcodebuild.}

** EXPORT FAILED **
[15:20:47]: Exit status: 70

+---------------+-------------------------+
|            Build environment            |
+---------------+-------------------------+
| xcode_path    | /Applications/Xcode.app |
| gym_version   | 2.166.0                 |
| export_method | app-store               |
| sdk           | iPhoneOS14.1.sdk        |
+---------------+-------------------------+

[15:20:47]: ▸ ** ARCHIVE SUCCEEDED ** [35.785 sec]
[15:20:47]: 
[15:20:47]: ⬆️  Check out the few lines of raw `xcodebuild` output above for potential hints on how to solve this error
[15:20:47]: 📋  For the complete and more detailed error log, check the full log at:
[15:20:47]: 📋  /Users/pawel/Library/Logs/gym/Runner-Runner.log
[15:20:47]:
[15:20:47]: Looks like fastlane ran into a build/archive error with your project
[15:20:47]: It's hard to tell what's causing the error, so we wrote some guides on how
[15:20:47]: to troubleshoot build and signing issues: https://docs.fastlane.tools/codesigning/getting-started/
[15:20:47]: Before submitting an issue on GitHub, please follow the guide above and make
[15:20:47]: sure your project is set up correctly.
[15:20:47]: fastlane uses `xcodebuild` commands to generate your binary, you can see the
[15:20:47]: the full commands printed out in yellow in the above log.
[15:20:47]: Make sure to inspect the output above, as usually you'll find more error information there
[15:20:47]:
[15:20:47]: Looks like no provisioning profile mapping was provided
[15:20:47]: Please check the complete output, in particular the very top
[15:20:47]: and see if you can find more information. You can also run fastlane
[15:20:47]: with the `--verbose` flag.
[15:20:47]: Alternatively you can provide the provisioning profile mapping manually
[15:20:47]: https://docs.fastlane.tools/codesigning/xcode-project/#xcode-9-and-up
+------------------+----------+
|        Lane Context         |
+------------------+----------+
| DEFAULT_PLATFORM | ios      |
| PLATFORM_NAME    | ios      |
| LANE_NAME        | ios beta |
+------------------+----------+
[15:20:47]: Error packaging up the application

+------+------------------+-------------+
|           fastlane summary            |
+------+------------------+-------------+
| Step | Action           | Time (in s) |
+------+------------------+-------------+
| 1    | default_platform | 0           |
| 💥   | build_app        | 47          |
+------+------------------+-------------+

[15:20:47]: fastlane finished with errors

[!] Error packaging up the application

Trying…

Fighting iOS code-signing errors on MacOS is very tedious and Apple doesn’t make this thing easier. That’s why usually my approach is to use brutal force and especially Xcode to fix it again from scratch. Other tools will simply fail.

First, if you try to add the capability and then enable/disable the Automatically managed signing of the target it will only work within Xcode. Flutter will be blocked by the error mentioned above. Asking it to re-download all certificates in Xcode -> Preferences -> Accounts tab won’t work neither, similarly crappy results via fastlane, even if the tool returns success:

# > fastlane sigh download_all
[✔] 🚀 
[16:18:31]: fastlane detected a Gemfile in the current directory
[16:18:31]: However, it seems like you didn't use `bundle exec`
[16:18:31]: To launch fastlane faster, please use
[16:18:31]:
[16:18:31]: $ bundle exec fastlane sigh download_all
[16:18:31]:
[16:18:31]: Get started using a Gemfile for fastlane https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile
[16:18:36]: Starting login with user 'codetitans-apple-id@gmail.com'
[16:18:37]: Successfully logged in
[16:18:38]: No profiles available for download

Solution

There are simply too many provisioning profiles laying around and getting smelly. And honestly, I have no idea, what selection method is used during signing process and why Xcode actually picks up the correct one. It uses probably most powerful dragon or other stronger magic.

I am a simple developer. I deleted everything like following:

  1. Navigate into ~/Library/MobileDevice/Provisioning Profiles.

  2. Move away all profiles to any other folder outside, so this one stays empty.

    NOTE: If you are stubborn enough, you can browse through those profiles and check via Properties in Finder, to see, if it relates to your application-id.

  3. Switch back to Xcode and prepare the IPA to upload to TestFlight:

    • Select active configuration: Runner >> Any iOS Device (armv7, arm64)

    • Create an archive (using top menu: Product > Archive)

    • Then once the archive is ready, click the Distribute App button inside opened Organizer (on the right panel)

    • Now, pretend you want to upload the IPA with automatic signing process run at the end (on active wizard select: App Store Connect > Next > Upload > Next > then just hit Next to skip components screen > Automatically manage signing !! )

    • Clicking Next on the last mentioned screen (with Automatically manage signing; see below) that will restore our required provisioning profile.

      IPA Signing

    • Finally - IPA is ready to be uploaded. It’s not required to do and you can safely abort it.

From now on, there is no chance for Flutter to mess-up or fail with signing as everything required for it was automatically restored.

I hope it helps!