📜 ⬆️ ⬇️

Qt applications in the Mac App Store

Perhaps many have already wondered about the possibility of creating a Qt application for the Mac App Store or sending an existing one. I have long wanted to test this possibility - as is well known, Apple and Nokia are currently developing different ecosystems of languages ​​/ libraries, and we can expect a lot of pitfalls associated with skipping Qt applications. Nevertheless, it turned out to be not so difficult and although I had to tinker enough, the application passed without problems and from the first time.



I have long been in the "stock" a small application for learning foreign words which was developed as an interesting experiment. The application is cross-platform, it required only QtGui, QtXml and QtCore and also could not include qt plugins.
')
At first, the style of the application was enhanced by matching the Mac interface, but it turned out to be not at all difficult for the latest versions of Qt. Of course, you can distinguish the difference in the interface for a specialist, but you need to know these features.

Next, the application (bundle) was assembled with the inclusion of all the necessary Frameworks inside. It turned out a bit too much for such a small application - about 60MB. The application seemed to me unnecessarily thick and it was decided to reduce it a little. Also, having rummaged on the Qt forums, it turned out that Qt itself needs to be patched to pass control.

The Carbon version was chosen because very small bugs appeared in the interface for Cocoa and did not want to spoil the overall picture and understand. Then they cut off all the excess that was found in configure and selected 10.5 sdk and only 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

It turned out about 30MB on Frameworks. But the Framework folders themselves can be cleaned - we do not need debug versions, header files, etc. Since I used Frameworks to copy using QMAKE_POST_LINK , it looked something like this:

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"


The result is 12MB, in the Mac App Store - just 5.3MB. Great for a small application that uses non-native GUI libraries.

So you figured out the size, now you need to fix Qt to match the App Store.

The first is that the application must store its data in ~ / Library / Application Support / com.organization.appname , so we take the patch mac-app-store-cache-location.diff . Now when using QDesktopServices :: storageLocation (), the correct path will be displayed .

Second, Qt applications always read / write ~ / Library / Preferences / com.nokia.qt.plist . It cannot be disabled as it was created specifically for general Qt application settings. But Apple will not miss the application that writes other people's settings. Therefore, we take the patch for Qt - mac-settings-in-app-area.diff , and in the very beginning () we add qt_force_trolltech_settings_to_app_area(true); to main ( qt_force_trolltech_settings_to_app_area(true);

There are two more patches - the first to remove Hide / Show All in the application menu, but this patch appeared later, although my application was missed and so, and the second for SQLite - I didn’t understand this as superfluous.

Frameworks themselves need to be configured so that they are excused at each other via @executable_path . This is clearly seen with 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)
...


Add to 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; \
...
+


Now everything is fine:
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)
...

With a simple copy of the App Bundle, it will run on other computers.

You also need to sign the application with your signature as a Mac developer. We get a signature in developer.apple.com , pay $ 99 for the year of subscription if you have not done so.
/usr/bin/codesign -f -s 3rd\ Party\ Mac\ Developer\ Application:\ Firstname\ Lastname $${BUNDLETARGET}; \
and also added to the pro file.

But to send the application to the App Store, we still had to open Xcode, compile in dsym + dwarf mode, also sign, our prepared Frameworks were added via “New Build Phase -> New Copy Files Build Phase”. Everything is well tested by otool to see the dependencies, verified on another poppy without dev tools and can be sent to the App Store.

The result -
1. Everything is not as difficult as it may seem at first glance.
2. Apple normally accepts Qt applications, Qt itself needs to be patched a bit.
3. The size of the entire Qt application (bundle) is quite small (perhaps if you include various resources in the application, then the volume of the Qt libraries themselves will take up a smaller part).

The result is http://itunes.apple.com/us/app/togmeg/id445287955

About the application itself is an interesting experiment in the study of foreign words. It helped me a lot when it was necessary to quickly type the “dictionary” for the most frequently used words. Using a high-quality voice engine (for example, from Acapela) creates a very good association of the sound of the word and its writing. I think I will write about the experiment itself and the application later in a separate post.

Resources:
Summary - http://bugreports.qt.nokia.com/browse/QTBUG-16549

Source: https://habr.com/ru/post/122826/


All Articles