Question

Alternative Titles (to aid searches)

Compressing PNGs

Reduce the size of an iPhone Archive (.ipa)

Adding a build rule to compress images in Xcode


iOS Apps can only be downloaded via 3G if they are less than 100MB. What are the best strategies for reducing the size of an App?

Areas I'd like to focus on are:

  • Images
  • Databases
  • Code
  • Static Libraries

NB: The original question can be viewed in the revisions of this question

Was it helpful?

Solution

PNG is really the best option for lossless image compression. You can optimize your PNGs for size using PNGOUT, but may I inquire which files specifically are taking much space? How does it compare to a non-debug release?

Edit: If you'd like a free GUI-version of PNGOUT, take a look at PNGGauntlet.

OTHER TIPS

Adding an Xcode Build Rule to compress PNGs

Images in an iOS App can make up the majority of it size. This is especially true if it is a Universal App requiring it to have all image in triplicate (iPhone Standard, iPhone Retina iPad).

The best type of image to use in an iOS App is a PNG. When your designer created these images in Photoshop they are saved with a lot of meta data that can be discarded.

However you don't want to loose all that data completely as it's useful to designers if they need to alter the image.

PNGOUT Optimisation

There are several tools for optimising PNG files, but pngout seems to be the best option.

  1. Download the Mac Version of pngout.
  2. Copy the binary command-line application pngout to a directory with in your project. Adding the binary to the project directory makes sure is is available to anyone building the project on any system.

Creating a Build Rule (Xcode 4)

Build rules are Target specific, so if you have more than one target you must copy the rule into each.

  1. Add DEBUG and DISTRIBUTION macros to your build configurations. Optimising the PNGs is quite processor intense and as such you only want to do it on distribution builds. Pre-processor macros As you can see amongst others I have added DEBUG_BUILD=1 and DISTRIBUTION_BUILD=1.

  2. Add a build rule for PNG files. A build rule simply processes a specific file (and/or) file type during the build process. The power of this is rules can be chained together. Build Rule - Xcode 4 http://tinypic.com/images/404.gif

  3. Click the "Add Rule" button;

    • Set Process to "Source files with names matching" and its value *.png.
    • Set Using to "Custom Script"

Paste this code into the script box

echo "----------------------------------------------------------------" >> "${DERIVED_FILES_DIR}/pngout-log.txt"
echo "${INPUT_FILE_PATH}" >> "${DERIVED_FILES_DIR}/pngout-log.txt"
echo "${DERIVED_FILES_DIR}/${INPUT_FILE_NAME}" >> "${DERIVED_FILES_DIR}/pngout-log.txt"
echo ${GCC_PREPROCESSOR_DEFINITIONS} >> "${DERIVED_FILES_DIR}/pngout-log.txt"

BUILD=`echo ${GCC_PREPROCESSOR_DEFINITIONS} | grep -o DISTRIBUTION_BUILD`

echo $BUILD >> "${DERIVED_FILES_DIR}/pngout-log.txt"

if [ "${BUILD}" == "DISTRIBUTION_BUILD" ]; then
echo "COMPRESS" >> "${DERIVED_FILES_DIR}/pngout-log.txt"
"${PROJECT_DIR}/build-process/pngout" -y -q -force "${INPUT_FILE_PATH}" "${DERIVED_FILES_DIR}/${INPUT_FILE_NAME}"
else
echo "COPY" >> "${DERIVED_FILES_DIR}/pngout-log.txt"
cp -f "${INPUT_FILE_PATH}" "${DERIVED_FILES_DIR}/${INPUT_FILE_NAME}"
fi

echo "...done." >> "${DERIVED_FILES_DIR}/pngout-log.txt"

There are several environment variables that are of note:

  • ${INPUT_FILE_PATH} — full path to the image file
  • ${INPUT_FILE_NAME} — image file name (with extension)
  • ${DERIVED_FILES_DIR} — where Xcode stores build files etc
  • ${GCC_PREPROCESSOR_DEFINITIONS} — the macros you set above

The work is done on this line:

    "${PROJECT_DIR}/build-process/pngout" -y -q -force "${INPUT_FILE_PATH}" "${DERIVED_FILES_DIR}/${INPUT_FILE_NAME}"

${PROJECT_DIR} is the full path to your project, the -y overwrites existing files, -q limits pngouts output and -force prevents pngout from exiting with status of 2 when a file can't be optimised and causing Xcode report build errors.

This script simply tests the ${GCC_PREPROCESSOR_DEFINITIONS} to see if it a DISTRIBUTION_BUILD if so it uses pngout to optimise the file, otherwise it copies it to the ${DERIVED_FILES_DIR} so Xcode can continue to process it.

Finally, don't forget to add ${DERIVED_FILES_DIR}/${INPUT_FILE_NAME} to the "Output files" list this is how Xcode knows how to find the files you have processed.

A debug build will usually be much larger than a release build. Try building in release mode.

There's a few compiler options that may help too. Not sure whats default for iphone release mode though. -Os will optimize for a smaller binary. There's also an option for dead code stripping that will remove any code that can never be run. Also you might try stripping the binary .. not sure if that works for iphone binaries though.

This is assuming that your problem is due to executable binary size and not the image resources.

I used ImageOptim and ImageAlpha for reducing app size. Have a look at this casestudy for more information. Tweetbot for iPad

@rjstelling has a really nice answer, and I couldn't begin to say it better, but there is one small problem with it. It won't work with localized images. This is only a problem if you embed text in images, which is something I highly recommend never doing if you can avoid it. However, if you have to use localized images, follow all of rjstelling 's steps except instead of using:

if [ "${BUILD}" == "DISTRIBUTION_BUILD" ]; then
echo "COMPRESS" >> "${DERIVED_FILES_DIR}/pngout-log.txt"
"${PROJECT_DIR}/build-process/pngout" -y -q -force "${INPUT_FILE_PATH}" "${DERIVED_FILES_DIR}/${INPUT_FILE_NAME}"
else
echo "COPY" >> "${DERIVED_FILES_DIR}/pngout-log.txt"
cp -f "${INPUT_FILE_PATH}" "${DERIVED_FILES_DIR}/${INPUT_FILE_NAME}"
fi

use the code below:

if [ "${BUILD}" == "DISTRIBUTION_BUILD" ]; then
echo "COMPRESS" >> "${DERIVED_FILES_DIR}/pngout-log.txt"
"${PROJECT_DIR}/build-process/pngout" -y -q -force "${INPUT_FILE_PATH}" "${DERIVED_FILES_DIR}/${INPUT_FILE_REGION_PATH_COMPONENT}${INPUT_FILE_NAME}"
else
echo "COPY" >> "${DERIVED_FILES_DIR}/pngout-log.txt"
cp -f "${INPUT_FILE_PATH}" "${DERIVED_FILES_DIR}/${INPUT_FILE_REGION_PATH_COMPONENT}${INPUT_FILE_NAME}"
fi

Note the only change is to the export file path. You have to prepend INPUT_FILE_REGION_PATH_COMPONENT to the export path to get localization of image to work properly. INPUT_FILE_REGION_PATH_COMPONENT is empty normally unless there is localized folder for the specific file. That being the case, it provides the folder name and a trailing slash, so you don't have to.

You must also change your Output Files setting to ${DERIVED_FILES_DIR}/${INPUT_FILE_REGION_PATH_COMPONENT}${INPUT_FILE_NAME} in order for this to work.

Not sure if I'm the only one who's ever had that problem, but hopefully it helps someone.

I have reduce an iOS app from 90MB to 50MB in the last few monthes. Here are some tips and tools:

To Profile iOS App Size

  1. unzip your ipa to check resources like video, font and images files.

  2. Profile your binary file by library and object files(classes) using Linkmap file and XCode Linkmap Parser.

To Reduce Image Files

To Reduce Binary File

  • Strip debug symbols
  • Find unused imports using fui

Inspecting an .ipa File

Simply change the extension of an .ipa file to .zip, then open it with Finder to decompress it. Right-click on the unzipped .app bundle and choose "Show Package Contents" to see the resources inside. This can give you an idea of what is using the most space.

You can examine the compressed size of each item in your .ipa by opening Terminal and executing the following command:

unzip -lv /path/to/your/app.ipa

The size column has the compressed size of each file within your .ipa file. You should evaluate this size as you work to reduce the size of resources in your app. You may reduce the size of a resource by a lot, but after producing an .ipa file, you may discover the compressed size of that resource has not changed as dramatically. The most effective technique for reducing the size of an .ipa file is to remove unnecessary resources.

To access the full article, see the link from Apple Developer Website.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top