uploader 1.1.0
uploader: ^1.1.0 copied to clipboard
This package is used for creating AAB/APK and IPA files, and sending them to Play Console, TestFlight, and Firebase App Distribution
Uploader #
This package is used for creating AAB/APK and IPA files, and sending them to Play Console, TestFlight, and Firebase App Distribution
Installation #
IOS #
- Create a JSON file with
issuer_idandauth_key, and provide the path of the JSON file to theUploader'stestFlightConfig->pathparameter. - issuer_id can be obtained in
Users and AccessunderApp Store Connect. - For
auth_key, create a newDeveloper Keyin the same section asissuer_id. The id value of this key can be used as theauth_key. Download the created key file and place it in the~/private_keys/directory on the computer where the package will be called.

ANDROID #
- Configure the
keystore(https://developer.android.com/studio/publish/app-signing#secure-shared-keystore). - Activate the
Google Play Android Developer APIonGoogle Cloud(https://console.developers.google.com/apis/api/androidpublisher.googleapis.com/?hl=en). - Create a
service accountfrom this link: https://console.cloud.google.com/iam-admin/serviceaccounts?hl=en. After creating theservice account, generate a newJSONKeyfile from theKeystab of theservice account. Provide the path of this JSON file to theUploader'splayStoreConfig->pathparameter. - Finally, the service account needs to be granted permission. From the
Users and Permissionssection of theGoogle Play Console, send an invitation to theservice accountemail withAdminorReleasespermissions.
FIREBASE APP DISTRIBUTION #
- Install
Firebase CLI(https://firebase.google.com/docs/cli?hl=tr). - Activate
App DistributiononFirebase. - Under Settings in
Firebase, integrate withGoogle Playin theIntegrationstab. If the app has not been published yet, this integration cannot be done, and in this case,Uploader'sandroidBuildTypeparameter should be set toapk.
Usage #
dev_dependencies:
uploader: any
dart run uploader # asks for confirmation before it starts
dart run uploader --yes # no prompt, for CI
dart run uploader --dry-run # prints every command without running any
dart run uploader --help
The process exits with a non-zero status when anything fails, so it can be used as a CI step directly.
Configuration #
uploader:
platform: all # ios, android, all
uploadType: all # appDistribution, store, all
testFlightConfig:
path: ios_deploy_config.json # must include auth_key and issuer_id
playStoreConfig:
path: android_deploy_config.json # must include client_email, client_id, private_key
track: internal # internal, alpha, beta
releaseStatus: completed # completed, draft. default: completed
skslPath: null
appDistributionConfig:
androidBuildType: abb # abb, apk
androidTesters:
path: android/testers.txt
iosTesters:
url: https://testers.txt
androidGroups: # Firebase App Distribution group aliases
- qa
iosGroups:
- qa
releaseNotesPath: release_notes.txt
useParallelUpload: true # default: true
uploadRetryCount: 2 # extra attempts per upload step. default: 2
enableLogFileCreation: false # default: false
extraBuildParameters: null
Build parameters #
extraBuildParameters is appended to every flutter build the run performs.
Two optional lists narrow that down to a single target:
uploader:
extraBuildParameters: # every build
- --no-tree-shake-icons
appDistributionExtraBuildParameters: # App Distribution builds only
- --dart-define=APP_CHANNEL=staging
storeExtraBuildParameters: [] # store builds only
A build receives the common list followed by its own target's list. Writing none of these keys behaves exactly as before.
This works because a run builds each target separately, so the two never share an artifact:
| App Distribution build | Store build | |
|---|---|---|
| iOS | flutter build ipa --export-method=ad-hoc |
flutter build ipa --export-method=app-store |
Android, androidBuildType: apk |
flutter build apk |
flutter build appbundle |
Android, androidBuildType: abb |
flutter build appbundle |
flutter build appbundle |
With uploadType: all in abb mode that means two app bundles are produced.
The cost is one extra build; the gain is that a diagnostic --dart-define
meant for testers never reaches the binary that goes to the store.
The confirmation screen prints the resolved list for each target before anything is built, so a flag written to the wrong list is visible up front.
Production releases are deliberately out of scope: the tool publishes to the test tracks and the production rollout stays a Play Console decision.
Only platform and uploadType are required. Every other key falls back to
the default shown above.
iOS size check #
After each IPA is built the run prints how large it is and compares that to the App Store's 200 MB over-the-air download limit:
[INFO]
[ios] IPA payload is 177.9 MB, 22.1 MB under the 200 MB App Store limit
Within 15 MB of the limit the line becomes a WARNING, and over the limit an
ERROR. Both of those also list the fifteen largest items in the archive, so a
build that grew says what grew:
[ERROR]
[ios] IPA payload is 203.8 MB, 3.8 MB over the 200 MB App Store limit
51.5 MB Runner
21.0 MB Frameworks/media_kit_libs_ios_video.framework
15.3 MB Frameworks/App.framework
10.1 MB Frameworks/App.framework/flutter_assets/assets/images
...
The number is the uncompressed total of everything under Payload/, in decimal
MB. An IPA also carries Signatures/ and Symbols/, which are not installed on
a device — counting the whole archive reads far larger than the app actually is.
Items are grouped at frameworks and resource bundles, because that is the unit
that gets added or removed. Flutter's assets are reported separately from
App.framework even though they ship inside it; otherwise an asset that grew
would look like the Dart snapshot growing.
unzip closes its listing with a totals row, and the run checks the entries it
read against it. That matters because the figure can only ever be too low: if a
line were skipped, an oversized build would otherwise be reported as a
comfortable one. When the two do not agree the size is presented as a lower
bound and the limit is reported as unresolved rather than cleared — an
oversized build still reads as oversized either way.
The check never stops a run. Whether an oversized build is still worth sending to testers is a decision for whoever reads the warning, and failing here would only strand an artifact that was built successfully.
It needs unzip on the PATH. With no archive on disk nothing is printed, so
--dry-run is unaffected; if the archive is there but cannot be read, the run
says the size was not checked instead of staying quiet.