Ru: Archive: Qt приложения в Mac App Store

Возможно многие уже задавались вопросом о возможности создания Qt приложения для Mac App Store или отправке уже существующего. Я давно хотел провести пробу этой возможности – как известно Apple и Nokia развивают сейчас разные экосистемы языков/библиотек и можно ожидать много подводных камней связанных с пропуском Qt приложения. Тем не менее это оказалось не так сложно и хотя повозится пришлось достаточно, приложение прошло без проблем и с первого раза.

У меня давно было на “складе” небольшое приложение для изучения иностранных слов которое разрабатывалось как интересный эксперимент. Приложение кросс-платформенное, требовало только QtGui, QtXml и QtCore и также можно было не включать qt plugins.

Сначала был подкручен стиль приложения для большего соответствия с Mac интерфейсом, но это оказалось совсем не трудно для последней версий Qt. Различить разницу в интерфейсе для специалиста конечно можно но нужно знать эти особенности.

Далее приложение (bundle) было собранно с включением всех необходимых Frameworks внутри. Получилось многовато для такого небольшого приложения – около 60МБ. Мне приложение показалось неоправданно толстым и было решено немного его уменьшить. Также, порывшись на Qt форумах оказалось что саму Qt нужно патчить для прохождения контроля.

Была выбрана Carbon версия так как обнаружились очень небольшие баги в интерфейсе для Cocoa и не захотелось портить общую картину и разбираться. Далее отрезали всё лишнее что нашлось в configure и выбрана 10.5 sdk и только 32 bit:

./configure -carbon -fast -no-qt3support -no-xmlpatterns -no-multimedia -no-audio-backend -no-phonon -no-phonon-backend -no-svg -no-webkit -no-javascript-jit -no-script -no-scripttools -no-declarative -no-openssl -arch "x86" -sdk "/Developer/SDKs/MacOSX10.5.sdk" -no-exceptions

Получилось около 30МБ на Frameworks. Но сами Framework папки можно почистить – нам не нужны debug версии, header файлы итд. Так как я пользовал копирование Frameworks с помощью QMAKE_POST_LINK, это выглядело приблизительно так:

QMAKE_POST_LINK = \
mkdir -p $${BUNDLETARGET}/Contents/Frameworks; \
cp -R $${QTFRAMEWORKSPATH}/QtCore.framework \
$${QTFRAMEWORKSPATH}/QtGui.framework \
$${QTFRAMEWORKSPATH}/QtXml.framework \
$${BUNDLETARGET}/Contents/Frameworks; \
...
\
strip $(TARGET); \
strip -x $${BUNDLETARGET}/Contents/Frameworks/QtCore.framework/Versions/4/QtCore; \
strip -x $${BUNDLETARGET}/Contents/Frameworks/QtGui.framework/Versions/4/QtGui; \
strip -x $${BUNDLETARGET}/Contents/Frameworks/QtXml.framework/Versions/4/QtXml; \
\
rm -rf `find $${BUNDLETARGET} -name "*.prl"`; \
rm -rf `find $${BUNDLETARGET} -name "*.lproj"`; \
rm -rf `find $${BUNDLETARGET} -name "*_debug*"`; \
rm -rf `find $${BUNDLETARGET} -name "Headers"`; \
\
otool -L $(TARGET); \
otool -L $${BUNDLETARGET}/Contents/Frameworks/QtCore.framework/Versions/4/QtCore; \
otool -L $${BUNDLETARGET}/Contents/Frameworks/QtGui.framework/Versions/4/QtGui; \
otool -L $${BUNDLETARGET}/Contents/Frameworks/QtXml.framework/Versions/4/QtXml; \
\
echo "Ok"

Результат – 12МБ, в Mac App Store – всего 5.3МБ. Отлично для небольшого приложения которое использует не родные GUI библиотеки.

Итак с размером разобрались, теперь нужно пофиксить Qt для соответствия App Store.

Первое – приложение должно хранить свои данные в ~/Library/Application Support/com.organization.appname, поэтому забираем патч mac-app-store-cache-location.diff. Теперь при использовании QDesktopServices::storageLocation() будет выдаваться правильный путь.

Второе – Qt приложения всегда читают/пишут ~/Library/Preferences/com.nokia.qt.plist. Отключить нельзя так как это было созданно специально для общих настроек Qt приложений. Но Apple не пропустит приложение которое пишет чужие настройки. Поэтому забираем патч для Qt – mac-settings-in-app-area.diff, а в main() в самом начале добавляем qt_force_trolltech_settings_to_app_area(true);

Есть еще два патча – первый для удаления Hide/Show All в меню приложения, но этот патч появился позднее, хотя моё приложение пропустили и так, и второй для SQLite – с этим не разбирался за ненадобностью.

Сами Frameworks нужно настроить чтобы они ссылись друг на друга через @executable_path. Это хорошо видно с помощью otool:
$ otool -L QtGui.framework/QtGui
QtGui.framework/QtGui:
/usr/local/Trolltech/Qt-4.7.3/lib/QtGui.framework/Versions/4/QtGui (compatibility version 4.7.0, current version 4.7.3)
/usr/local/Trolltech/Qt-4.7.3/lib/QtCore.framework/Versions/4/QtCore (compatibility version 4.7.0, current version 4.7.3)
/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon (compatibility version 2.0.0, current version 136.0.0)
...

Добавим в QMAKE_POST_LINK:
install_name_tool -id @executable_path/../Frameworks/QtCore.framework/Versions/4/QtCore \
$${BUNDLETARGET}/Contents/Frameworks/QtCore.framework/Versions/4/QtCore; \
install_name_tool -id @executable_path/../Frameworks/QtGui.framework/Versions/4/QtGui \
$${BUNDLETARGET}/Contents/Frameworks/QtGui.framework/Versions/4/QtGui; \
install_name_tool -id @executable_path/../Frameworks/QtXml.framework/Versions/4/QtXml \
$${BUNDLETARGET}/Contents/Frameworks/QtXml.framework/Versions/4/QtXml; \
...
+для других ссылок тоже самое

Теперь всё отлично:
otool -L QtGui.framework/QtGui
QtGui.framework/QtGui:
@executable_path/../Frameworks/QtGui.framework/Versions/4/QtGui (compatibility version 4.7.0, current version 4.7.3)
@executable_path/../Frameworks/QtCore.framework/Versions/4/QtCore (compatibility version 4.7.0, current version 4.7.3)
/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon (compatibility version 2.0.0, current version 136.0.0)
...

При простом копировании App Bundle оно будет запускаться на других компьютерах.

Еще нужно подписать приложение своей подписью как Mac разработчик. Получаем подпись в developer.apple.com, платим $99 за год подписки если вы еще этого не сделали.
/usr/bin/codesign -f -s 3rd\ Party\ Mac\ Developer\ Application:\ Firstname\ Lastname $${BUNDLETARGET}; \
и тоже добавленно в pro файл.

А вот для отправки приложения в App Store, пришлось всё-таки открывать Xcode, собирать в режиме dsym+dwarf, тоже подписывать, наши подготовленные Frameworks были добавленны через “New Build Phase -> New Copy Files Build Phase”. Всё хорошо протестированно otool чтобы видеть зависимости, проверенно на другом маке без dev tools и можно отправлять в App Store.

Итог –
1. Всё не так сложно как может показаться на первый взгляд.
2. Apple нормально принимает Qt приложения, саму Qt нужно немного пропатчить.
3. Размер всего Qt приложения (bundle) совсем небольшой (возможно если вы включите различные ресурсы в приложение то объём самих Qt библиотек займёт меньшую часть).

Результат – http://itunes.apple.com/us/app/togmeg/id445287955

О самом приложении – это интересный эксперимент по изучению инстранных слов. Мне оно очень помогло когда нужно было быстро набрать именно “словарь” для наиболее часто используемых слов. С использование качественного voice engine (например от Acapela) создаётся очень хорошая ассоциация звучания слова и его написания. Думаю напишу про сам эксперимент и приложение позже отдельным постом.

Ресурсы:
Основная информация – http://bugreports.qt.nokia.com/browse/QTBUG-16549

This entry was posted in C++, MacAppStore, Projects, Qt, QtSpeech, Ru, TogMeg, TTS, Tutorial. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Clef two-factor authentication