Thin iOS app frameworks to the target architecture (#7913)
* Support thinning iOS frameworks to supported architectures
When building against frameworks that are distributed as
multi-architecture fat binaries, we want to strip the frameworks we
distribute down to only the architectures specified in $ARCHS.
This patch adds:
* The ability to specify commands to xcode_backend.sh (if none is
specified, run BuildApp for backward compatibility).
* A 'thin' command that invokes lipo to thin down the distributed as
described above.
* Add framework thinning step to iOS build
Invokes xcode_backend.sh thin on the build application.
* Limit architectures to arm64 in Xcode template
Flutter does not yet support armv7 iOS devices. Limit the $ARCHS build
variable to arm64 until then.
diff --git a/packages/flutter_tools/bin/xcode_backend.sh b/packages/flutter_tools/bin/xcode_backend.sh
index a4db9cd..d4d7b3f 100755
--- a/packages/flutter_tools/bin/xcode_backend.sh
+++ b/packages/flutter_tools/bin/xcode_backend.sh
@@ -121,4 +121,77 @@
return 0
}
-BuildApp
+# Returns the CFBundleExecutable for the specified framework directory.
+GetFrameworkExecutablePath() {
+ local framework_dir="$1"
+
+ local plist_path="${framework_dir}/Info.plist"
+ local executable="$(defaults read "${plist_path}" CFBundleExecutable)"
+ echo "${framework_dir}/${executable}"
+}
+
+# Destructively thins the specified executable file to include only the
+# specified architectures.
+LipoExecutable() {
+ local executable="$1"
+ shift
+ local archs="$@"
+
+ # Extract architecture-specific framework executables.
+ local all_executables=()
+ for arch in $archs; do
+ local output="${executable}_${arch}"
+ lipo -output "${output}" -extract "${arch}" "${executable}"
+ if [[ $? == 0 ]]; then
+ all_executables+=("${output}")
+ else
+ echo "Failed to extract ${arch} for ${executable}. Running lipo -info:"
+ lipo -info "${executable}"
+ exit 1
+ fi
+ done
+
+ # Merge desired architectures.
+ local merged="${executable}_merged"
+ lipo -output "${merged}" -create "${all_executables[@]}"
+
+ # Replace the original executable with the thinned one and clean up.
+ cp -f "${merged}" "${executable}" > /dev/null
+ rm -f "${merged}" "${all_executables[@]}"
+}
+
+# Destructively thins the specified framework to include only the specified
+# architectures.
+ThinFramework() {
+ local framework_dir="$1"
+ shift
+ local archs="$@"
+
+ local plist_path="${framework_dir}/Info.plist"
+ local executable="$(GetFrameworkExecutablePath "${framework_dir}")"
+ LipoExecutable "${executable}" "$archs"
+}
+
+ThinAppFrameworks() {
+ local app_path="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
+ local frameworks_dir="${app_path}/Frameworks"
+
+ [[ -d "$frameworks_dir" ]] || return 0
+ for framework_dir in "$(find "${app_path}" -type d -name "*.framework")"; do
+ ThinFramework "$framework_dir" "$ARCHS"
+ done
+}
+
+# Main entry point.
+
+if [[ $# == 0 ]]; then
+ # Backwards-comptibility: if no args are provided, build.
+ BuildApp
+else
+ case $1 in
+ "build")
+ BuildApp ;;
+ "thin")
+ ThinAppFrameworks ;;
+ esac
+fi