Two ways to Upload an ipa to Testflight with Fastlane

After making builds with Fastlane and exported a valid .ipa, you need to automate the process of uploading the file to Testflight. You can do it in two ways with upload_to_testflight (or pilot) action.

With AppStore Connect API key

https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file

The upload_to_testflight action need an App store connect api key to work. It's result of this action app_store_connect_api_key, the action for creating a JWT from a .p8 file.

lane :release do
  api_key = app_store_connect_api_key(
    key_id: "Q58Q4Y9A5W",
    issuer_id: "69a6de95-7865-47e3-e053-5b8c7c11a4d1",
    key_filepath: "./AuthKey_Q58Q4Y9A5W.p8",
    duration: 1200, # optional (maximum 1200)
    in_house: false # optional but may be required if using match/sigh
  )

  upload_to_testflight(
    api_key: api_key,
    skip_submission: true,
    ipa: "#{ipa_path}",
    skip_waiting_for_build_processing: true,
  )
end

.p8 file, key_id, issuer_id are all easily get from App Store Connect webpage.

Login to your developer account, go to Users and Access, then find Request Access button in Keys tab.

After requesting access, you can Generate any Key for some roles, use Issue ID, KeyID and Download API key (as an .p8 file) for app_store_connect_api_key lane above.

There's another way to specific .p8 key for app_store_connect_api_key lane. It's using key_content instead of key_filepath. In that case, you need to modify the .p8's content by replacing all new lines with \n, to make it in one line.

For example:
Default content from App Store Connect:

-----BEGIN PRIVATE KEY-----
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
EEEEEEEEEEEEE
-----END PRIVATE KEY-----

change to:

-----BEGIN PRIVATE KEY-----\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\nEEEEEEEEEEEEE\n-----END PRIVATE KEY-----

Find more detail about the key here
https://docs.fastlane.tools/actions/app_store_connect_api_key/

With Enviroment variables FASTLANE_USER and FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD

The second way to upload to App Store is to use lane upload_to_testflight. With this lane, you need to prepare two environment variables as Credentials for uploading.

About environment variables: https://support.apple.com/guide/terminal/use-environment-variables-apd382cc5fa-4f58-4449-b20a-41c53c006f8f/mac

Let take a look at an example:

lane :release do
  upload_to_testflight(
    apple_id: "your-app-apple-id"
    skip_submission: true,
    ipa: "#{ipa_path}",
    skip_waiting_for_build_processing: true,
  )
end

It's simpler than the first lane, but there's no any user credentials in lane parameters, like .p8 key, so to let the script work, we need to find out 2 environment variables: FASTLANE_USER &FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD and set it before running the script.

Details can be found: https://docs.fastlane.tools/best-practices/continuous-integration/#application-specific-passwords

  • apple_id can be found in your app's information page in App Store Connect web page.

Let's try to see result. If you found any problem please let me know in comment section down below.

Conclusion

The first way seems more complicated than the second way, and you need to be an admin to generate .p8 key. But you can control the flow by put the key in any place you want to automate and you don't rely on any user's account.

The second way is base on account, and if you work in an organization the account can be expired if people leave. So it's suitable for personal account.

Thanks a lot for reading. Happy coding.