<<

Qt for iOS A to Z

Mike Krus, Senior Software Engineer at KDAB Qt on iOS Requirements

Recent version of Qt & Creator A Mac Qt 5.4 Basic laptop or sufficient Static build Mac Mini works as headless build machine Not a VM on Not a Mac non-GUI layers of Qt compile as normal Unix / Mach backend for , sockets, memory An Apple Id

QPA layers maps QWindow to UIView An subscription Applies to more than one Apple ID Widget-based UI possible No limit on team size Not recommended iOS 9 introduce 'Personal Teams' QtQuick UI rendered using OpenGL ES (2 or 3) iOS 8 and up (for Qt 5.5)

p.2 p.3

Demo QMake

Time to try Creator... qmake generates

Makefiles

MyProject.xcodeproj

Info.plist

qml files, contained in a qrc

main.cpp

myproject_plugin_import.cpp

myproject_qml_plugin_import.cpp

p.4 p.5 Anatomy of an App QMake Variables

Application is a darwin/mac vs osx vs Specially structured directory Variables Documents, Library/Cache... Not a compressed zip/jar 1 QMAKE_IOS_DEPLOYMENT_TARGET = 8.0 2 QMAKE_IOS_TARGETED_DEVICE_FAMILY = 2 Bundles contain an Info.plist XML file 3 QMAKE_IOS_DEVICE_ARCHS = armv7 arm64 4 QMAKE_IOS_SIMULATOR_ARCHS = i386 x86_64 Metadata about author, supported platforms, architectures, copyright 5 6 VERSION = 1.2.3 Specifies executable to launch inside the bundle 7 BUILDID = 55 File-types / URLs / mime-types 8 9 plist.input = Info.plist.in Bundle has a unique identifier (reverse DNS style), version number, build 10 plist.output = $$OUT_PWD/Info.plist 11 QMAKE_SUBSTITUTES += plist number 12 QMAKE_INFO_PLIST = $$OUT_PWD/Info.plist

Also contains arbitrary resources as plain files Qt 5.8: uikit, , , , QMAKE_APPLE_...

p.6 p.7

PList Template Icons & Splash Screens - Resources

1 Include properly named files in your bundle 2 meta.files = $$files($$PWD/meta/*) 4 QMAKE_BUNDLE_DATA += meta 5 6 CFBundleIdentifier Reference in Info.plist 7 com.kdab.${PRODUCT_NAME:rfc1034identifier} 8 CFBundleDisplayName 1 ... 9 ${PRODUCT_NAME} 2 CFBundleIcons 10 CFBundleName 3 11 ${PRODUCT_NAME} 4 CFBundlePrimaryIcon 12 CFBundleShortVersionString 5 13 $$VERSION 6 CFBundleIconFiles 14 CFBundleVersion 7 15 $$VERSION.$$BUILDID 8 Icon-57.png 16 LSRequiresIPhoneOS 9 Icon-72.png 17 10 [email protected] 18 UISupportedInterfaceOrientations 11 19 12 UIPrerenderedIcon 20 UIInterfaceOrientationLandscapeLeft 13 21 UIInterfaceOrientationLandscapeRight 14 22 15 23 UIFileSharingEnabled 16 ... 24 25 ... 26 27

p.8 p.9 Icons & Splash Screens - Asset Catalogs Getting to know Xcode

Include asset bundles in your bundle Don't be afraid of Xcode

meta.files = $$files($$PWD/meta/*.xcassets) Entrypoint to dedicated editors QMAKE_BUNDLE_DATA += meta Manages developer account Edit in Xcode Manages devices and applications

Builds & deploys your code

Archive management

SDK documentation and examples

Excellent Remember you're working on a copy!

p.10 p.11

The Simulator Running on real hardware

The simulator is not an emulator You must run your app on real hardware

Application compiled for or x64 iOS applications must always be code signed Certifies origin of the app Links against custom frameworks providing iOS Prevents tampering Simulator frontend allows hardware emulation Entitlements Runtime environment Enables some features, iCloud, , Push Notifications...

Differences from real hardware Deployment requires Provisioning Profiles Code-signing, OpenGL performance, sensors Controls where app can run Developer profiles AppStore or Ad-Hoc profiles

p.12 p.13 p.14 p.15

Sandboxing Qt UI - Widgets

iOS never exposes the filesystem to the user Widgets work, but...

At runtime, applications can only access files within their 'sandbox' Implemented as kernel access control (ACL), not a chroot

No access to other application's data

Other restrictions No use of private APIs Checked mechanically by tooling No downloading code or JIT-ing Attempts to mark data as executable will fail

Application groups in iOS 8 Apps with matching group IDs can share containers Group IDs defined in the member center, registered in the provisioning

... don't

p.16 p.17 QML - 1 QML - 2

QML Retina & resources UI rendered using OpenGL Coordinates are in qreal, points NOT pixels Designer friendly Set border.pixelAligned: false Animations Image sources support @2x Quick.Controls, Quick.Dialogs More layouts Image { src: "/images/foo.png"; width: 200; height 200 } ComboBox If present, will load [email protected] (400x400 px) on retina devices StackView Embrace this, don't fight it by playing with size and scale of root item! FileDialog (fileDialog.folder: fileDialog..pictures) Text Input Selection is different (much better in 5.7!) Keyboard avoidance is a pain (see Qt.inputMethod.hide())

p.18 p.19

QML - 3 UIKit idioms

Plain QML has no visual style UIKit provides standard high-level view structures Paged, tabbed, master / detail Controls1 look like widgets User and designers familiar with the behaviour and visual presentation Controls2 no iOS look Also supports navigation and transitions Native appearance is problematic Push / Pop navigation Define native! Modal presentation Moving target: Apple restyle UIKit across OS upgrades Absence of pop-up / pop-over UI Qt Demo /Users/Shared/Qt/Examples/Qt-5.7/quickcontrols/controls/touch Modal yes / no dialogs the (infrequent) exception

Qt Demo /Users/Shared/Qt/Examples/Qt-5.7/quickcontrols2/gallery Transitory modal UI for rotary wheels

Powerful animation engine

p.20 p.21 Handling Views Other UI issues

Hard to not load everything at start up Phone vs tablets

Loader useful but destructive, can't transition Portrait vs landscape

Using components Cross-platform considerations

1 var component = Qt.createComponent("foo.qml") Accessibility 2 if (component.status == Component.Ready) { 3 newView = component.createObject(parent, {opacity: 0, "anchors.fill": parent}) 4 5 previousView = currentView 6 currentView = newView 7 if (previousView) { 8 previousView.viewWillDisappear() 9 fadeOut.target = previousView 10 fadeOut.running = true 11 } 12 currentView.viewWillAppear() 13 fadeIn.target = currentView 14 fadeIn.running = true 15 }

p.22 p.23

Qt Modules Qt not enough?

Sensors Coverage not complete File-type association Camera Background operations Position (GPS), Location (Maps) Sharing In-App purchase iCloud Access to , accounts ( / Facebook) Qt3D CoreMotion (steps...), MapKit, HealthKit, GameKit, PassKit, Security, PushKit...... WebKit! ...

Through specialised Objective- APIs

Not wrapped by Qt, easy to invoke yourself

p.24 p.25 Software Platform Objective-C++

Low-level system shared with OS X Objective-C & C++ combined Mach microkernel Language syntaxes are orthogonal BSD userspace libraries (libC, crypto) .mm file extension Apple system libraries CoreAudio, CoreAnimation, CoreLocation, AVFoundation, CoreWLAN OBJECTIVE_SOURCES in qmake

Cocoa Touch Bridging the Objective-C and Qt object systems is possible. Potentially relevant Objective-C, like Cocoa if incorporating a 3rd-party framework for iOS. Natively designed for mobile & touch UIKit, Standard widgets UI class prefix Many others (MapKit, HealthKit, ...)

p.26 p.27

Mixing Qt & UIKit - Using QQuickItem Mixing Qt & UIKit - Using QPA

Derive from QQuickItem QPA layer exposes native resources

Handle windowChanged(QQuickWindow*) signal to create UIView Parent UIView hierarchy to main Qt window

Handle visibleChanged() signal to show/hide Unsuitable for embedding individual widgets QT += gui-private Overload geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) to resize 1 QWindow* window = ... ; 2 UIView *view = static_cast(QGuiApplication::platformNativeInterface()-> 3 nativeResourceForWindow("uiview", window)); Demo ios/UITextView 4 Q_ASSERT(view); 5 6 UIViewController* controller = [[view window] rootViewController]; 7 Q_ASSERT(controller);

Create a view / controller heirarchy programmatically

Via a system or 3rdparty library

p.28 p.29 Application Delegate Application Delegate

Use Objective C categories Use own delegate

1 @interface QIOSApplicationDelegate 1 @interface MyAppDelegate : UIResponder 2 @end 2 +(MyAppDelegate *)sharedAppDelegate; 3 3 @end 4 @interface QIOSApplicationDelegate(MyApp) 4 5 @end 5 @implementation MyAppDelegate 6 6 static MyAppDelegate *sharedAppDelegate = nil; 7 @implementation QIOSApplicationDelegate(MyApp) 7 +(MyAppDelegate *)sharedAppDelegate { 8 - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application 8 static MyAppDelegate *shared = nil; 9 { 9 if (!shared) 10 qDebug() << "Lets release some memory before we get killed"; 10 shared = [[MyAppDelegate alloc] init]; 11 } 11 return shared; 12 12 } 13 - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url 13 14 { 14 - (BOOL)application:(UIApplication *)application 15 ... 15 willFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 16 } 16 return YES; 17 } 18 @end 19 20 int main(int argc, char *argv[]) { 21 ... 22 [[UIApplication sharedApplication] setDelegate:[MyAppDelegate sharedAppDelegate]]; 23 ... 24 }

p.30 p.31

Debugging & Profiling Debugging & Profiling

p.32 p.33 Common Issues External Testing

QML / JS: slow startup, no JIT compiler Test Flight

Memory allocation The applicationDidReceiveMemoryWarning: method of your app delegate. The didReceiveMemoryWarning method of your UIViewController classes. The UIApplicationDidReceiveMemoryWarningNotification notification.

Graphical effects...

Hockey App, AWS Device Farm...

p.34 p.35

Thank you!

[email protected] - www.kdab.com