AppStore Submission¶
Heidelberg Mobil provides HDMMapCore 2.x as a single dynamic framework, including everything that is needed to embed an indoor map into an iOS application.
“Single” means that HDMMapCore.framework includes binaries for all needed platforms:
$ lipo -info HDMMapCore.framework/HDMMapCore Architectures in the fat file: HDMMapCore.framework/HDMMapCore are: i386 x86_64 armv7 arm64
This approach is convenient and straightforward. However, there’s one drawback - because dynamic framework is linked at runtime, when a dynamic library is compiled separately to the app it ends up in, it’s impossible to tell which architectures will actually be needed. Therefore, Xcode will just copy the whole thing into your application bundle at compile time. Other than the wasted disk space, there’s no real drawback to this. In practice, however, iTunes Connect doesn’t like us adding unused binary slices:
So, how do we work around this?
We could use static framework instead like we did for HDMMapCore 1.x when dynamic libraries were unavailable (before iOS 8). However, this does not work for Swift code, as Swift is not ABI stable. Furthermore, static framework is a step back and will not be supported.
We can provide two types of HDMMapView.framework: develop and appStore. Maintaining two SDK versions inconveniences both the SDK developers and end-users.
In order to try resolving this, try to strip the redundant platform at build-time.
Stripping redundant architectures from HDMMapCore.framework¶
The last option can be implemented by adding the following script to
your build steps. Insert it after your step to embed frameworks and set
it to use /bin/sh
:
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}" # This script loops through the frameworks embedded in the application and # removes unused architectures. find "$APP_PATH" -name 'HDMMapCore.framework' -type d | while read -r FRAMEWORK do FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable) FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME" echo "Executable is $FRAMEWORK_EXECUTABLE_PATH" EXTRACTED_ARCHS=() for ARCH in $ARCHS do echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME" lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH" EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH") done echo "Merging extracted architectures: ${ARCHS}" lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}" rm "${EXTRACTED_ARCHS[@]}" echo "Replacing original executable with thinned version" rm "$FRAMEWORK_EXECUTABLE_PATH" mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH" done
The script will look through your built
application’s Frameworks
folder and make sure only the
architectures you’re building are present in each Framework.
Results:
Bonus:
Size of original HDMMapCore.Framework
$ du -sh HDMMapCore.framework 48M HDMMapCore.framework
Size of Stipped HDMMapCore.Framework inside the App.
$ du -sh HDMMapCore.framework 5.9M HDMMapCore.framework