Support for iOS and tvOS

From Qt Wiki
Revision as of 21:02, 19 August 2015 by Timday (talk | contribs) (clarify target)
Jump to navigation Jump to search

Support for iOS

Introduction

If this page is in a crude state, it's because it's a quick brain dump of experiences taking a simple (QQuickView + QML, minimal UI) app from Linux & OS X Desktop to iOS, and written in the hope it will be useful to other developers with Qt/Desktop experience who are quite unfamiliar with "mobile" and iOS and Xcode. Please feel free to edit mercilessly. This page doesn't (yet) describe App Store submissions.

Prerequisites

  • You'll need an iOS device.
  • To deploy an application onto an iOS device, you'll need a key (or "team provisioning profile" as Apple calls it) from Apple to sign the executables. The easiest way to get this is probably to register on the Apple iOS Developer Program. A yearly fee must be paid.
  • You need Xcode, and therefore a Mac running OS X.
  • You need the iOS device connected to your Mac via the provided USB.
  • You need to "Provision Your iOS Device for Development": this can be done from the xcode device organizer: https://developer.apple.com/library/ios/recipes/xcode_help-devices_organizer/articles/provision_device_for_development-generic.html
  • You need a Qt x.x.x for iOS SDK (note that this also includes the OS X support; whereas if you download the Qt x.x.x for Mac SDK, it's just the OS X stuff. Hence the considerably larger size of the iOS SDK).

(If you're happy just programming Xcode's iOS device simulators then you just need a Xcode and a Mac running OS X; there's no need to register as an iOS developer for that. Be warned the simulator performance characteristics are significantly different from real HW!)

Workflow (not using QtCreator)

Preparation

Assuming you have a Qt project which builds for desktop from a qmake .pro file, you should be able to get an iOS build by:

  • Get the right tools in your path: You'll find the iOS Qt SDK has both (e.g for Qt 5.3.1) 5.3/clang_64/bin/ and 5.3/ios/bin . The clang_64 one is for OS X; make sure it's the iOS version of the tools is in your path for the below.
  • Run
    qmake -spec macx-xcode myproject.pro
    
    . You can add iOS specific .pro file details in an "ios { }" block.
    QMAKE_BUNDLE_DATA
    
    is probably the most useful, notably for adding the arcane set of application icons needed by various devices (note that Xcode asset catalogs can also help a lot in this area).
  • Open the resulting myproject.xcodeproj in Xcode.
  • The first time you do this, you'll probably need to create a myproject.xcworkspace workspace file to contain the project (c.f Visual Studio's "solutions" which contain projects). But once you've done that you can forget about it. (Actually, XCode 6+ seems to be happy to just open an xcodeproj without any xcworkspace entanglements).
  • When qmake runs it also creates an Info.plist file (XML) which contains a great many interesting settings. While these can be tweaked from within Xcode, this isn't recommended as the next qmake run will obliterate any changes. Instead, it is better to have a script make any needed changes which can be run after a qmake. (There may be some QMAKE_ macros which set certain plist properties too.)
  • If you rerun the qmake, it's a good idea to close the xcode project.

Info.plist

Useful settings (can be got into the qmake-generated Info.plist using sed/regexps/xslt transforms… whatever works for you - but note the existence of PListBuddy mentioned below):

Adding

  <key>UIFileSharingEnabled</key>
  <string>YES</string>

in the

<dict>

section enables "file sharing" (more on this below).

Adding

  <key>UISupportedInterfaceOrientations</key>
  <array>
    <string>UIInterfaceOrientationLandscapeLeft</string>
    <string>UIInterfaceOrientationLandscapeRight</string>
  </array>

locks the application to landscape mode (useful if it's been designed on Desktop aspect ratio screens!).

Adding

  <key>UIStatusBarHidden</key>
    <true/>
  <key>UIViewControllerBasedStatusBarAppearance</key>
    <false/>

hides the status bar (recent iOS versions; maybe version dependent).

Additionally/alternatively Apple provides a useful utility /usr/libexec/PlistBuddy for modifying these files e.g

  /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString 1.2.3" Info.plist

would set a version number (not to be confused with CFBundleVersion, which appears to be intended for use as a build number).

Deploying

  • You can compile from the commandline using
    xcodebuild -project myproject.xcodeproj -alltargets
    
    . However, you'll still need to open Xcode and the xcodeproj to deploy it to an iOS device. But it's useful for commandline mavens who'd rather not open Xcode until they absolutely have to.
  • In Xcode, hit the big "arrow" icon top left of xcode to "Build and then run the current scheme". If all goes well (assuming no compile errors), you'll get (if your target isn't a simulator) a dialog "codesign wants to sign using key" (you can opt to always allow this) and it'll deploy to the device (physical or simulator) you have selected just to the right of that arrow icon. Your application should start up on the device in a short while.
  • Note that XCode's default behaviour is to build and run in debug mode. You can change this frome the Product->Scheme dialog (which is also where commandline options and environment variables can be set).
  • If Xcode doesn't seem to be "seeing" your iOS device, some combination/escalation of unplug/replug , restart Xcode, restart Mac generally fixes it.
  • Any logging to stdout/stderr from your app appears in a window in Xcode, which is handy.

Other considerations about the iOS environment

Stuff you need to know:

Files on iOS devices

  • iOS apps run in a "sandbox" where they keep their data. They don't get to mess with other apps data. When the app is uninstalled, the entire sandbox contents is deleted. There are some important conventions to be aware of.
  • You can transfer files to and from a Mac (using iTunes) to that sandbox if the app has enabled "file sharing" (see above mention re Info.plist).
  • Such file transferring does seem to be individual files. You can't select a folder and have that and all its contained files and subfolders be transferred. Solutions probably involve "container files" like tar or zip… more on this here.

https support

  • The iOS platform does not expose OpenSSL as a public library. The Qt for iOS distribution does not contain OpenSSL.
  • Qt for iOS supports REST (get/put/post/delete) over https using the following API:
    • C++: QNetworkAccessManager
    • QML: XMLHttpRequest
  • Overriding certificate errors is not supported with the current implementation.
  • Qt for iOS does not support QSSLSocket out of the box. It's possible to build and link OpenSSL manually. See QTBUG-3689.

"Installers" for iOS

The workflow described above refers to deploying an app to a USB-attached iOS device. If you want to send an "installer" for an app to someone remote with an iOS device (NB must be one which has somehow been inducted into your limited pool of development/test machines, for example by adding the device GUID in your Apple developer account and creating and downloading a new app signing certificate including the device):

  • In xcode, there is a “Product” menu with “Archive” on it (NB need to have iOS device selected as build target, not a simulator).
  • That creates an archive in the Organizer window’s Archives tab.
  • Select the archive and hit the “Distribute” button.
  • This brings up a dialog where you get to select “Save for Enterprise or Ad Hoc Deployment” then “use iOS Team Provisioning Profile”, and then save a .ipa file (an “iOS application archive file” apparently).
  • Send the ipa file to the intended user.
  • If they double-click the ipa file it should open iTunes’ to install or update the app on the device (when iTune's "apply" is hit).

Plugins

Qt's own plugins for image format support and QtQuick/QML just work.

If you're using your own custom plugins: it's believed these will need to be of the static variety due to iOS restrictions on .dylib usage. Apple may have changed policy on this from iOS8+, although the new policy may be more about dylib use by reusable frameworks and it's not clear if application plugins are intended to be allowed too of not. In any case, CONFIG += plugin targets just seem to build static libs automatically on iOS even without CONFIG += static.

This is slightly non-trivial (at least for QQmlExtension plugins); see thread at https://forum.qt.io/topic/56878/qml-plugin-on-ios and linked https://bugreports.qt.io/browse/QTBUG-47827 and example code at https://bitbucket.org/timday/qt-example-plugin/overview

General

  • If you're used to developing for desktop platforms, you may find the ratio of "graphics power" (OpenGL GPU rendering power) to conventional CPU "compute power" somewhat skewed (towards graphics) compared to your previous experience! QtQuick's QSG's separate rendering thread probably really pays off here, helping a couple of feeble ARM cores keep the PowerVR GPU beast fed.