The problem
Both generated fetch scripts assume the vendor handed you an already-unpacked
artifact. Vendors very often hand you a .zip instead — one archive containing
the .xcframework, or the .aar plus a README and a sample project.
iOS, local form — refuses outright:
$ tool/fetch_ios_sdk.sh /path/to/AcmeSDK.xcframework.zip
error: not a directory: /path/to/AcmeSDK.xcframework.zip
The download form does unzip (unzip -q "$TMP_DIR/sdk.zip" then
find ... -name '*.xcframework'), so the capability already exists in the
script — it is just not reachable from the local path.
Android, both forms — worse, because it fails silently. The local form only
checks [[ ! -f "$1" ]], so a .zip passes and is copied straight to
android/libs/AcmeSDK.aar. The download form never unzips at all: it curls the
URL to $TMP_DIR/sdk.aar and copies it. Either way you end up with a zip
wearing an .aar extension, sdkPresent in build.gradle.kts reads true,
and the failure surfaces later as a Gradle error about the archive rather than
as "you gave me the wrong file".
Why it matters
This is the first command a new user runs after generating, with whatever the
vendor emailed them. Getting told "not a directory" is survivable; silently
installing a corrupt .aar is the exact failure class this project exists to
remove — a build that looks like it has the SDK and does not.
Suggested approach
In lib/src/templates/script_templates.dart:
fetchIosSh — in the local branch, accept a file as well as a directory. If
it is an archive, unpack it into $TMP_DIR and reuse the existing
find "$TMP_DIR/unpacked" -maxdepth 3 -type d -name '*.xcframework' | head -1
logic. Factoring that into an install_from_archive() helper next to
install_from_dir() keeps both entry points on one code path.
fetchAndroidSh — detect an archive in both the local and download branches
and extract the .aar from it. Error clearly if the archive holds zero or
more than one .aar rather than picking one.
- Keep the checksum on the downloaded bytes, not on the extracted file. The
vendor pins the archive.
One design note worth knowing before you start: an .aar is itself a zip
archive, so sniffing for the PK magic bytes cannot tell an .aar from a
zip that contains one. Distinguish by listing the entries — a real .aar has
AndroidManifest.xml at the archive root (unzip -l "$f" | grep -q ' AndroidManifest.xml$'
or similar). Say in the PR which test you used and why.
Files involved
lib/src/templates/script_templates.dart — fetchIosSh, fetchAndroidSh
test/generator_test.dart — the lessons the generated code must not lose
group is where the other script assertions live
How to verify
dart test
dart analyze --fatal-infos
CI also runs bash -n over every generated script, so a syntax slip fails
there. Beyond that, exercise it for real:
dart run bin/binary_sdk_bridge.dart --name acme_ads --org com.example \
--ios-framework AcmeSDK --android-aar AcmeSDK --out /tmp/gen
mkdir -p /tmp/fake/AcmeSDK.xcframework && (cd /tmp/fake && zip -qr AcmeSDK.xcframework.zip AcmeSDK.xcframework)
/tmp/gen/acme_ads/tool/fetch_ios_sdk.sh /tmp/fake/AcmeSDK.xcframework.zip
ls /tmp/gen/acme_ads/ios/acme_ads/Frameworks/ # AcmeSDK.xcframework should be here
Please paste the generated script diff into the PR — per CONTRIBUTING, the
generated output is the product, and escaping mistakes in a shell template look
fine in the Dart source and wrong in the output.
The problem
Both generated fetch scripts assume the vendor handed you an already-unpacked
artifact. Vendors very often hand you a
.zipinstead — one archive containingthe
.xcframework, or the.aarplus a README and a sample project.iOS, local form — refuses outright:
The download form does unzip (
unzip -q "$TMP_DIR/sdk.zip"thenfind ... -name '*.xcframework'), so the capability already exists in thescript — it is just not reachable from the local path.
Android, both forms — worse, because it fails silently. The local form only
checks
[[ ! -f "$1" ]], so a.zippasses and is copied straight toandroid/libs/AcmeSDK.aar. The download form never unzips at all: it curls theURL to
$TMP_DIR/sdk.aarand copies it. Either way you end up with a zipwearing an
.aarextension,sdkPresentinbuild.gradle.ktsreadstrue,and the failure surfaces later as a Gradle error about the archive rather than
as "you gave me the wrong file".
Why it matters
This is the first command a new user runs after generating, with whatever the
vendor emailed them. Getting told "not a directory" is survivable; silently
installing a corrupt
.aaris the exact failure class this project exists toremove — a build that looks like it has the SDK and does not.
Suggested approach
In
lib/src/templates/script_templates.dart:fetchIosSh— in the local branch, accept a file as well as a directory. Ifit is an archive, unpack it into
$TMP_DIRand reuse the existingfind "$TMP_DIR/unpacked" -maxdepth 3 -type d -name '*.xcframework' | head -1logic. Factoring that into an
install_from_archive()helper next toinstall_from_dir()keeps both entry points on one code path.fetchAndroidSh— detect an archive in both the local and download branchesand extract the
.aarfrom it. Error clearly if the archive holds zero ormore than one
.aarrather than picking one.vendor pins the archive.
One design note worth knowing before you start: an
.aaris itself a ziparchive, so sniffing for the
PKmagic bytes cannot tell an.aarfrom azip that contains one. Distinguish by listing the entries — a real
.aarhasAndroidManifest.xmlat the archive root (unzip -l "$f" | grep -q ' AndroidManifest.xml$'or similar). Say in the PR which test you used and why.
Files involved
lib/src/templates/script_templates.dart—fetchIosSh,fetchAndroidShtest/generator_test.dart— thelessons the generated code must not losegroup is where the other script assertions live
How to verify
dart test dart analyze --fatal-infosCI also runs
bash -nover every generated script, so a syntax slip failsthere. Beyond that, exercise it for real:
Please paste the generated script diff into the PR — per CONTRIBUTING, the
generated output is the product, and escaping mistakes in a shell template look
fine in the Dart source and wrong in the output.