Category Archives: Apple

WinterFest 2021

Winterfest 2021

Easy Data Transform and Hyper Plan Professional edition are both on sale for 25% off at Winterfest 2021. There is also some other great products from other small vendors on sale, including Tinderbox, Scrivener and Devonthink. Some of the software is Mac only, but Easy Data Transform and Hyper Plan are available for both Mac and Windows (one license covers both). Sale ends 11th January.

A Windows Developer in Mac Land

This is a guest post from fellow software developer, Simon Kravis.

Few developers would choose their development platform on the merits of their respective Integrated Development Environments (IDEs)  but it happens that applications developed in Windows need to be made available on the Mac platform.

There are many environments offering cross-platform (Mac, Windows and sometimes Android) functionality, but close inspection shows that they all have limitations.  Visual Studio (the native Windows IDE) can produce apps which will run on a Mac using .Net Core – but only if they are command line apps on Windows. Other environments (like Xamarin) do support interfaces, but only involving simple controls like text boxes or drop-downs. There are other cross-platform IDEs (such as Qt)  which offer better graphics support, but they are not cheap and the extent of their support is not evident. If you need functionality such as computer vision, there seems to be no alternative to creating a separate code base for the Mac. Once you start on this path it becomes obvious that Macs handle graphics (and interfaces) very differently from Windows.

Macs have evolved rather more than PCs over the decades: they abandoned their proprietary Mac operating system in favour of UNIX in 1999, adopting the NeXTSTEP platform created by NeXT. Apple originally used PowerPC chips, replacing them with Intel Core processors in 2006, and they are currently transitioning to RISC chips. The Mac NeXTSTEP programming language was Objective C, developed in the 1980s and this is still supported, although the modern Swift language was introduced in 2014, and the Xcode IDE appeared in 2003. Xcode is free, even for teams. It uses the Cocoa API, which is accessible from other environments. The current release (MacOS  13.0) supports both Objective-C and Swift and is also used for developing iPhone and iPad apps. Mac operating systems since Catalina (released in 2019) are 64-bit only.  Xcode can only develop apps for Apple operating systems, notably iOS, which powers the iPhone. Most of the web questions and examples relate to iOS rather than MacOS. MacOS uses different frameworks from iOS, so some functions used in iOS are not available in MacOS, or have different parameters.

The Windows IDE (Visual Studio) dates from 1997, when it bundled together Visual Basic, Visual Fox Pro and Visual Source Safe and Visual C++.  It has an open architecture based on plug-ins and supports 36 different programming languages, but the major ones are C#, VB.Net and C++. Visual Studio can develop apps for any platform via the .NetCore framework, but capability for non-Windows platforms is limited. The Community edition is free, and has almost all the functionality of paid versions.

Both Visual Studio and Xcode are highly complex applications. They both have graphical interface builders where controls are dragged from a library onto a form.  Each application has a vocal supporters and detractors. My experience comes from about 5 years with Visual Studio developing C# applications. Before this I worked with Visual Basic for Applications in Microsoft Access, so I am well-versed in the Microsoft way of doing things.

Like most complex applications, Visual Studio and Xcode each have plenty of bugs, often producing completely unhelpful error messages. Reporting an Xcode bug through standard channels resulted in … nothing. Not even an automated message saying “Thank you for feedback. It will be used to improve future versions”. I haven’t even tried to report a Visual Studio bug, but I suspect that the much larger user base for Visual Studio will mean that workarounds are more readily available, even if the giant ship of Microsoft takes years to respond.

Moving to the Mac and Xcode for development was a shock as I found I didn’t know how to do the most basic things. String manipulation (used in most applications) in Objective C is highly verbose compared to C#. Google was invaluable for finding answers – mostly they were from Stack Overflow, but often from 10 or more years ago, sometimes from Apple Developer Forums. As Xcode has changed considerably since then, answers often had to be adjusted before they could be used.  Another problem is that functionality once provided externally has since been incorporated into Cocoa, so attempts to find a current version of a component (or framework as they called in Cocoa) are often unsuccessful.

MacOS provides more native functionality than Windows. Features such as computer vision and PDF generation are included in MacOS, rather than requiring the use of 3rd party components, which may not as robust as desired, and may require a license for commercial use. However, documentation of MacOS functionality, if present at all, was rarely useful. A few times I asked questions on Stack Overflow which attracted the ire of the Mac gurus for either through having obvious (to them) answers or through not conforming to the forum guidelines (in their opinion). However, the integration of NuGet with Visual Studio provides easy access to the massive number of 3rd party  libraries available for .Net on Windows.

The model-view-controller paradigm used on the Mac took some getting used to, as did the design of the main Xcode screen. Sometimes a useful display would disappear and I had difficulty in finding it how to bring it back. I often had to resort to retrieving earlier versions from the excellent Time Machine backup.  Form design is similar on both platforms – dragging and dropping components from a library. Both Xcode and Visual Studio have bugs, as would be expected for such complex apps. Events from components are generated automatically in Windows, but have to be defined on the Mac (as Actions). References to the component you’ve added also need to be defined on the Mac (as Outlets) and are not a property of the component, whereas on Windows they are.

The Xcode environment provides only basic facilities from scratch: if you need to do something more sophisticated you’ll have to Google around to find out how. Once you know – it’s easy, but the learning curve for Xcode is much higher than for Visual Studio.   

Rather than starting from scratch with the Mac version of my Caption Pro  app, which uses local computer vision functionality to detect multiple photos, changes image dimensions and adds text to images,  I found an existing open-source project on GitHub with similar basic functionality. This dated from 7 years ago and used Objective-C, so that was the language I opted for. An immediate handicap was that many of the answers I found to my questions used Swift in their example code, which is not interconvertible with Objective-C  in the way that C# and VB.Net are. iOS applications for the iPhone (which are most common) use different frameworks from Mac apps, and routines in them sometimes have completely different syntax.

The user interfaces for the Mac and Windows versions look quite different, as shown below. There are some basic differences – menus appear separately to the application window on the Mac and are locked to the top of the screen, whereas Windows menus are part of the application screen. Toolbars offer access to common functionality on the Mac. Differences also arise from the fact the Mac application was adapted from existing code rather than created from scratch.

Figure 1 Windows App main screen
Figure 2 Mac App main screen

Open-source examples (often from GitHub) are useful, but rarely work out-of-the- box. Sometimes the modifications need are minor – like defining the development team-  but sometimes it’s not possible to get them to build in a current version of Xcode.

Debugging on Xcode is frustrating – the call stack frequently contains assembler (which is perhaps why app performance tends to be better on Macs), and the debug variables window does not list all relevant variable values. Variable types may not be correct – Boolean values may appear as dates, and sometimes variables cannot even be evaluated by po (print out) statements. Printing out structure variables may show nothing.  Despite the generally superior performance of Mac apps, building apps in Xcode appears to be much slower than in Visual Studio on similar vintage machines, and after code stops at a breakpoint, it may take a long time before the variables window is filled. Deployment of Mac apps can still be done on an ad-hoc basis, but you have to register as an Apple Developer to avoid blockages in installation arising from being an ‘untrusted source’. Bypassing these blockages is more than a matter of clicking “Install anyway” so it’s hard to avoid forking out US$100 per year for registration. Windows has similar blockages, which can be bypassed with a code-signing certificate. These certificates are available from many vendors, and are slightly cheaper than Apple developer registration, but the process of obtaining one may be very involved.

Ad-hoc deployment is somewhat easier on the Mac than on Windows, but the method of doing it via Archive generation is anything but obvious. Mac applications are actually disk images and applications keep all of relevant files in a folder. This makes uninstallation a matter of dragging the application icon into the recycle bin, a far simpler process than on Windows. dmg files are not recognized by IIS web servers (and may not be by Apache either), so unless the file type is registered, download from a web site will not be possible.

Apple pioneered the App Store for iPhones (it is the only way in which iPhone apps can be installed) and Mac apps can also be put there. Apple takes a commission of 30% (or 15% if you are a small company) and they review all apps before adding them. Passing the review process may be a lngthy process, as not all problems are detected in a review cycle. Fixing these issues and resubmitting may result in further problems coming to light.  The review process may also be somewhat arbitrary. One App Store app presented an interface in German by default. English was available as Preferences option, but only after guessing where the Preferences option was located. App Store apps operate within a sandbox, which places restrictions on filesystem operations. Whether App Store deployment makes economic sense depends on the nature of the app, its market and price structure. Its advantages are that it targets the 16% of desktop users who use Macs, and streamlines installation (and payment, if applicable). The App Store supports ‘freemium’ pricing, where additional features are made available to paying users, but apps with free trial periods are shown as being free but with ‘in-app purchases’, which annoys some users.

Windows deployment can use .msi files, which have been around for decades, but are not easily installed by non-admin users. Self-extracting executables are more tractable, but 3rd party tools have to be used to create them. Windows 10 introduced Universal Windows Programs, which are easier to install and can be placed in the Microsoft Store, which operates in a similar way to the Apple App store, but for Windows desktops and tablets.

A key question which is very difficult to answer is “How long will it take me to convert my Windows app to run on a Mac?” Factors affecting this are app complexity, functionality and programmer skill.  The time between starting work on the Mac app and first deploying it on the company web site was about 3 months, but the amount of time spent on the project each day varied between zero and 3 or 4 hours. If you are a paid resource, then the cost of a cross-platform IDE may be justified, but the requirement for local computer vision functionality added a great deal of complexity to my requirements, which is one reason why I opted for a separate code base. Substantial evaluation would be required before deciding if a cross-platform environment could support any required  functionality.

Simon Kravis runs Aleka Consulting, a small software and consultancy company in Canberra, Australia specializing in information management and offering a number of software products. He has mainly developed scientific and engineering programs, starting in the era of paper tape.

How to add a dark theme to your Qt application

Dark themes are now available for Windows 10 and Mac and it is increasingly expected that desktop applications will offer a dark theme. Previously Qt support for dark themes was patchy. But I am happy to say that it now seems to work fine with Qt 5.12.2, and I have added dark themes to both Windows and Mac versions of my Easy Data Transform and Hyper Plan applications.

Easy Data Transform for Mac with a dark theme:

Easy Data Transform for Windows with a dark theme:

Hyper Plan for Mac with a dark theme:

Hyper Plan for Windows with a dark theme:

I haven’t decided yet whether to add a dark theme to PerfectTablePlan.

Adding dark themes was a fair amount of work. But a lot of that was scouring forums to work out how to integrate with macOS and Windows. Hopefully this article will mean you don’t have to duplicate that work.

Dark themes work a bit differently on Windows and Mac. On Windows changing the UI theme to dark won’t directly affect your Qt application. But you can use an application stylesheet to set the appearance. On Mac changing the UI theme to dark will automatically change your application palette, unless you explicitly block this in your Info.plist file (see below). On both platforms you will need to change any icons you have set to the appropriate light/dark version when the theme changes. Some of this may change in future as dark themes are more closely integrated into Qt on Windows and Mac.

macOS

You can add the following helper functions to a .mm (Objective-C) file:

#include "Mac.h"
#import <Cocoa/Cocoa.h>

bool macDarkThemeAvailable()
{
    if (__builtin_available(macOS 10.14, *))
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool macIsInDarkTheme()
{
    if (__builtin_available(macOS 10.14, *))
    {
        auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
                @[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
        return [appearance isEqualToString:NSAppearanceNameDarkAqua];
    }
    return false;
}

void macSetToDarkTheme()
{
   // https://stackoverflow.com/questions/55925862/how-can-i-set-my-os-x-application-theme-in-code
   if (__builtin_available(macOS 10.14, *))
   {
        [NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]];
   }
}

void macSetToLightTheme()
{
    // https://stackoverflow.com/questions/55925862/how-can-i-set-my-os-x-application-theme-in-code
    if (__builtin_available(macOS 10.14, *))
    {
        [NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]];
    }
}

void macSetToAutoTheme()
{
    if (__builtin_available(macOS 10.14, *))
    {
        [NSApp setAppearance:nil];
    }
}

The macSetToLightTheme() and macSetToDarkTheme() are useful if you want to give the user the option to ignore the OS theme. Call macSetToAutoTheme() to set it back to the default.

Corresponding header file:

#ifndef MAC_H
#define MAC_H

bool macDarkThemeAvailable();
bool macIsInDarkTheme();
void macSetToDarkTheme();
void macSetToLightTheme();
void macSetToAutoTheme();

#endif // MAC_H

You then need to add these files into your .pro file:

macx {
   ...
   HEADERS += Mac.h
   OBJECTIVE_SOURCES += Mac.mm
}

You can detect a change of theme by overriding changeEvent():

void MainWindow::changeEvent( QEvent* e )
{
#ifdef Q_OS_MACX
    if ( e->type() == QEvent::PaletteChange )
    {
        // update icons to appropriate theme
        ...
    }
#endif
    QMainWindow::changeEvent( e );
}

If you decide you *don’t* want to add a dark theme to your Mac app, the you should add the bold entry below to your Info.plist file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    ...
    <key>NSRequiresAquaSystemAppearance</key>
    <true/>
</dict>
</plist>

This will then force it to be shown in a light theme, regardless of the theme the operating system is in.

Windows

To set a dark theme palette you can use a stylesheet:

QFile f( ":qdarkstyle/style.qss" );
if ( !f.exists() )
{
   qWarning() << "Unable to set dark stylesheet, file not found";
}
else
{
   f.open( QFile::ReadOnly | QFile::Text );
   QTextStream ts( &f );
   getApp()->setStyleSheet( ts.readAll() );
}

The stylesheet I used was a modified version of qdarkstyle from a few years ago.

To unset the stylesheet and return to a light theme just call:

getApp()->setStyleSheet( "" );

Alternatively you can do it by changing the application palette.

Windows helper functions:

bool windowsDarkThemeAvailable()
{
    // dark mode supported Windows 10 1809 10.0.17763 onward
    // https://stackoverflow.com/questions/53501268/win10-dark-theme-how-to-use-in-winapi
    if ( QOperatingSystemVersion::current().majorVersion() == 10 )
    {
        return QOperatingSystemVersion::current().microVersion() >= 17763;
    }
    else if ( QOperatingSystemVersion::current().majorVersion() > 10 )
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool windowsIsInDarkTheme()
{
    QSettings settings( "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", QSettings::NativeFormat );
    return settings.value( "AppsUseLightTheme", 1 ).toInt() == 0;
}

Currently there seems to be no way to conect to a signal or event that shows the theme has changed in Windows. So I connected to a signal from a QTimer that fires every 5 seconds to check windowsIsInDarkTheme().

Icons

When the theme changes you potentially need to update any icons you have set, e.g. for the toolbar.

In a light theme you can usually set the active icons and let Qt calculate the corresponding disabled icons. This doesn’t work for a dark theme as you want the disabled icons to be darker than the enabled icons, rather than lighter. So you can either calculate the disabled icons programmatically or you can provide a set of disabled icons as well. I opted for the former.

Assuming your icons are set up as resources under :/icons/dark and :/icons/light you can do something like this:

QString getResourceName( const QString& iconName, bool dark )
{
    return QString( ":/icons/%1/%2" ).arg( dark ? "dark" : "light" ).arg( iconName );
}

QPixmap getPixmapResource( const QString& iconName, bool dark )
{
    QString resourceName = getResourceName( iconName, dark );
    QPixmap pixmap = QPixmap( resourceName );
    Q_ASSERT( !pixmap.isNull() );
    return pixmap;
}

QIcon getIconResource( const QString& iconName, bool dark )
{
    QIcon icon;
    QPixmap pixmap = getPixmapResource( iconName, dark );
    icon.addPixmap( pixmap );
    if ( dark )
    {
        // automatic disabled icon is no good for dark
        // paint transparent black to get disabled look
        QPainter p( &pixmap );
        p.fillRect( pixmap.rect(), QColor( 48, 47, 47, 128 ) );
        icon.addPixmap( pixmap, QIcon::Disabled );
    }
    return icon;
}

Then you can reset the icon for the appropriate theme with:

bool isDark()
{
#ifdef Q_OS_MACX
   return macIsInDarkTheme();
#else
   return windowsIsInDarkTheme();
#endif
}
...
myButton->setIcon( getIconResource( "my_icon.png", isDark() ) );
...

You may also be able to update icons through QIcon::setThemeName(). But I didn’t explore this in any detail.

Note that you probably don’t want the enabled icons to be pure white, as it is a bit too visually jarring against a dark theme.

Running Qt apps on M1 ARM Macs

Apple is switching the processor architecture of it’s Macs. Again (I transitioned PerfectTablePlan from PowerPC to Intel some hears ago). This time to their own M1 ARM chips. Reports so far have been very positive about speed and battery life of the new processors. Obviously most current Mac software has been written for Intel Macs, so they are using the Rosetta2 emulation layer to run apps compiled for Intel Macs on the ARM chips. I’m not sure how much of a performance hit this causes, but clearly it would be better to run native ARM binaries on an ARM machine. Also Apple, being Apple, want to move everyone to ARM as quickly as possible. Tough luck if you just spent big bucks on a shiny new Intel Mac.

One of my customers emailed me that the latest version of my Hyper Plan visual planner, built with Qt 5.13.1, didn’t run on an new M1 Mac. I don’t currently have an M1 Mac to test it on. But my Easy Data Transform software , built with Qt 5.15.2, apparently works fine on an M1 Mac. So I recompiled Hyper Plan using Qt 5.15.2, and was told it now works. I have found a couple of minor differences in behaviour between Qt 5.13.1 and 5.15.2, but they are too obscure to go into here. Some Qt apps may still have issues on ARM.

Currently Qt is only available as Intel binaries. Efforts are in progress to be able to build Qt as M1 (ARM) binaries. When that is complete it should be possible to ship Qt applications as a ‘fat binary’ with both Intel and ARM executables, as I did with the PowerPC to Intel transition. I’m not sure if this is going to be supported on Qt 5 and 6 or just Qt 6.

** Update Dec-2021 **

Qt 6.2 supports building M1 ARM and Intel binaries. There is no official support for M1 Arm binaries for Qt 5.

** Update Apr-2022 **

Evan of ModernCSV alterted me to an article on deploying a ‘fat binary’ from Qt 5.

Upgrading to MacOS 11.0 (Big Sur)

It is always a bit of fraught process upgrading a computer OS, especially for a development machine with loads of tools and libraries installed. So I try to do it as infrequently as I can get away with. On Windows I generally buy a new PC rather than upgrade OS. However glitches had been reported in Easy Data Transform on macOS 11.0 (Big Sur) and I wasn’t ready to abandon my 2017 iMac, so I decided to bite the bullet and upgrade it from macOS 10.13 to 11.0.

The initial upgrade of OS was straightforward enough. But when I tried to run Qt Creator the CPU shot to 99% and stayed there, making the machine unusable. A glance at Activity Monitor showed that several XCode related processes were going crazy. After a bit a Googling I managed to find this magic incantation to type into the terminal on a forum post:

defaults write com.apple.dt.Xcode DVTDisableMainThreadChecker 1

I was then able to rebuild my Qt-based products: Easy Data Transform, PerfectTablePlan and Hyper Plan using the existing installs of Qt 5.13.1 and Qt Creator 4.8.0.

I had to update some of the software I use:

  • DropDMG
  • Beyond Compare
  • SnagIt

Annoyingly, I had to buy an upgrade of SnagIt as the 2018 version doesn’t work on Big Sur. Even more annoyingly the upgrade costs nearly as much as a new licence, which feels predatory.

The Subversion command line no longer worked from the terminal, but that was easily fixed by adding /Applications/XCode.app/Developer/usr/bin to PATH in my .profile.

So far I haven’t been able to get the following to work:

  • XCode
  • Hammer4Mac

XCode 10.1 falls over if I try to start it. It says that it requires additional components and then fails to install them. I may upgrade XCode at some point. But I only use the compiler from the command line via QtCreator, so it doesn’t really matter at present.

Hammer4Mac is a static website builder I use to build the PerfectTablePlan website and a couple of other mini sites. I upgraded to the latest version. It starts, but returns ‘Build failed’ for all 3 websites. No clue as to why. I Tweeted the creator, but got no reply. It appears to be abandonware. If so they should really take down the Hammer4Mac website. I guess I will use it from my macOS 10.14 laptop and then eventually do the tedious job of porting those websites to Jekyll.

Hopefully I won’t have to do another major upgrade of macOS any time soon (I may buy a new Mac next time).

How to notarize your software on macOS

** Please note: WordPress keeps mangling my code examples by changing double dash to single dash. I tried to fix it. But it changed them all back again! If anyone knows how to get around this, please put something in the comments. **

Apple now wants you to ‘notarize’ your software. This is a process where you upload your software to Apple’s server so it can be scanned and certified malware free. This will probably become compulsory at some point, even (especially?) if your software isn’t in the Apple app store. Apple says:

Give users even more confidence in your software by submitting it to Apple to be notarized. The service automatically scans your Developer ID-signed software and performs security checks. When it’s ready to export for distribution, a ticket is attached to your software to let Gatekeeper know it’s been notarized.

When users on macOS Mojave first open a notarized app, installer package, or disk image, they’ll see a more streamlined Gatekeeper dialog and have confidence that it is not known malware.

Note that in an upcoming release of macOS, Gatekeeper will require Developer ID signed software to be notarized by Apple.

Documentation on notarization is a bit thin on the ground, especially if you want to notarize software that wasn’t built using XCode (I build my software using QtCreator). So I am writing up my experiences here.

First you need to ensure you have macOS 10.14 and XCode 10 installed (with command line tools) and you need a current Apple developer account.

Codesign your app with ‘hardened runtime’ using –options runtime :

codesign –deep –force –verify –verbose –sign “Developer ID Application:<developer id>” –options runtime <app file>

E.g.:

codesign –deep –force –verify –verbose –sign “Developer ID Application: Acme Ltd” –options runtime myApp.app

A ‘hardened runtime’ limits the data and resourced an application can access. I’m not sure what the exact ramification of this are. But it doesn’t seem to have restrict my software from doing anything it could do previously.

You can check the signing with:

codesign –verify –verbose=4 <app file>

E.g.:

codesign –verify –verbose=4 myApp.app

Now package your app into a .dmg (e.g. using DropDMG). Then upload the .dmg to Apple’s servers:

xcrun altool -t osx -f <dmg file> –primary-bundle-id <bundle id> –notarize-app –username <username>

E.g.:

xcrun altool -t osx -f myApp.dmg –primary-bundle-id com.acme.myapp –notarize-app –username me@acme.com

You will be prompted for your Apple developer password (or you can include it on the command line).

You now have to wait a few minutes. If the upload is successful “No errors uploading ” will be shown and a unique ID will be returned. You then have to use this to request your upload be scanned:

xcrun altool –notarization-info <notarize ID> -u <username>

E.g.:

xcrun altool –notarization-info xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx -u me@acme.com

You will be prompted for your Apple developer password (or you can include it on the command line).

Hopefully you will see “Status Message: Package Approved”. If the notarization fails, you should be sent a link to an online log file describing the issue. If the notarization completes successfully you need to ‘staple’ the results to your .dmg:

xcrun stapler staple -v <dmg file>

E.g.:

xcrun stapler staple -v myApp.dmg

The stapler outputs a log including some odd phrases. Mine included: “Humanity must endure”, “Let’s see how that works out. “, “Adding 1 blobs to superblob. What about Blob?” and “Enjoy”. Weird. Hopefully it will end with “The staple and validate action worked!”.

Finally you can unpack your .dmg into a .app and verify it with:

spctl -a -v <app file>

E.g.

spctl -a -v /Applications/myApp.app

On macOS 10.14 (but not earlier OSs) it should say “source=Notarized Developer ID”. Your software should now run on 10.14 without a warning dialog. Congratulations!

It all seems rather clumsy. As you have to wait asynchronously for the unique ID to be returned from step 1 before you can complete step 2, it is not easy to fully automate in a script. This is a major pain the arse. If anyone works out a way to automate it the whole process, please let me know.

Here are some links to the various posts that I gleaned this information from:

https://cycling74.com/forums/apple-notarizing-for-mojave-10-14-and-beyond
https://www.mbsplugins.de/archive/2018-11-02/Notarize_apps_for_MacOS
https://forum.xojo.com/50655-how-to-codesign-and-notarise-your-app-for-macos-10-14-and-highe
https://forum.xojo.com/49408-10-14-hardened-runtime-and-app-notarization/11
https://stackoverflow.com/questions/53112078/how-to-upload-dmg-file-for-notarization-in-xcode
https://lapcatsoftware.com/articles/debugging-mojave.html

Signing Qt applications for Mac OS X 10.9.5 and 10.10

I have written previously about signing Qt applications for Mac OS X. It all worked fine until I upgraded to Mac OS X 10.9.5, which broke my signing script. Those Apple chaps do love to break stuff. Grrr.

The problem appears to be that the directory structure of the app bundle has changed and the Qt4 macdeployqt command does not conform to the new layout (I believe this is also the case for Qt5). Oh joy. I managed to work out how to get it working again after a bit of digging around. The good news is that Apple have also made the codesign command easier with a --deep option to traverse and sign the whole bundle in a single command. About time.

So here is the basic process to build and sign your Qt .app on the latest versions of Mac OS X:

# deploy Qt frameworks into .app bundle
$QTDIR/bin/macdeployqt <your_app>.app -verbose=1
# optionally delete unwanted framework and plugin folders, e.g.:
# rm -f -r <your_app>.app/Contents/Frameworks/QtDeclarative.framework
# rm -f -r <your_app>.app/Contents/PlugIns/sqldrivers
# correct .app bundle structure
python rebundle.py $QTDIR <your_app>.app
# sign .app bundle (including frameworks and plugins)
codesign --deep --force --verify --verbose --sign "Developer ID Application: <your developer id>" <your_app>.app
# the 2 lines below are just for verification/diagnostics
otool -L <your_app>.app/Contents/MacOS/<your_app>
codesign --verify --verbose=4 <your_app>.app

(Sorry about the small font, but I wanted to avoid confusing line wraps).

I then invoke DropDmg to create a .dmg image file complete with licence and background image. This is all stuck it all in a bash script, which I can pretty much forget about it (until Apple break something else).

In the above rebundle.py is a Python script  written by some public spirited individual that can be downloaded from github (thank you, ‘kingcheez’). Note that you can just find and replace all the ‘5’ characters in the script by ‘4’ if you are still using Qt4.

The first time I ran my script I ended up with a whopping 50MB .app file. It turns out that the cp -r commands in my script don’t preserve symbolic links. So you end up with 3 copies of each framework library. You can avoid this by using cp -R instead.

On the subject of signing for Mac, Apple recently sent out an email stating:

Signatures created with OS X Mountain Lion 10.8.5 or earlier (v1 signatures) will be obsoleted and Gatekeeper will no longer recognize them. Users may receive a Gatekeeper warning and will need to exempt your app to continue using it. To ensure your apps will run without warning on updated versions of OS X, they must be signed on OS X Mavericks 10.9 or later (v2 signatures). … Apps signed with v2 signatures will work on older versions of OS X.

So you are going to have to start signing using 10.9, whether you like it or not.

First impressions of the Retina 13″ Macbook Pro

macbook pro retinaMy table planner software runs on Windows and Mac. Previously I took a Windows laptop with me when I was out of the office or on holiday, so that I could provide technical support to my customers. But it isn’t (legally) possible to run Mac OS X on Windows, so this made it hard to give Mac customers the best possible technical support. For example I couldn’t send them Mac screenshots or replicate Mac-only bugs from a Windows laptop. However it is legally possible to run both Mac OS X and Windows on a Mac. So I decided to buy a 13″ Retina Macbook Pro for my new laptop, so that I could have access to both OSs when out of the office. I was also attracted by the screen and design of the new Retina Macbook Pro. I choose the 13″ model, rather than than the 15″ model, simply because it is more portable (e.g. more likely to fit in a hotel safe). I also paid to upgrade the SSD from 128GB to 256GB to have room for both Mac OS X and Windows setups. I have now had my Macbook Pro for a few weeks, so I thought I would share my initial impressions.

The good points:

  • The 2560 x 1600 Retina screen is gorgeous, both in terms of sharpness and colour. It makes the display on my old Toshiba Windows laptop look very tired.
  • With a 2.5 GHz Core i5 processor, 8 GB of RAM and an SSD it is very responsive.
  • The aluminium chassis is beautifully designed. Despite being only 19mm thick and 1.6Kgs, it feels very sturdy. The power brick is quite small and light as well.
  • The keyboard is nice. Automatically backlighting the keys in low light is a nice touch.
  • The power cable attaches magnetically. This means it is easy to attach. But, more importantly, accidentally kicking the cable just pops the cable out, rather than the whole machine crashing onto the floor.
  • Gestures work very nicely on the touch pad. For example you can drag two fingers up and down to scroll or tap with 2 fingers to simulate right click.
  • I have Windows and Mac OS X  stored on separate partitions. I can access Window either by booting into Windows or from inside Mac OS X using Parallels (cost approx $80). Being able to access Windows from Mac OS X without a reboot is very useful.
  • The speakers are surprisingly good.

The not so good points:

  • The Macbook Pro is expensive compared to Windows ultrabooks with similar specs.
  • There are a limited number of ports:  2 USB, 2 Thunderbolt, 1 headphone, 1 HDMI and 1 unidentified (SD memory card?).
  • There is no Ethernet port. So if there is no Wifi, you are out of luck.
  • There is no Kensington slot, so you can’t physically lock it down. This is especially annoying given the price.
  • As someone who mainly uses Windows I’m still struggling to get used to the Mac keyboard. For example there is a Backspace key, but no Delete key. Also there is no Home or End key. Worst of all the cursor sometimes  jumps to a different line while I am typing. I have no idea why.
  • Parallels and Windows don’t do a brilliant job of handling the very high resolution of the Retina display. Fonts are sometimes shown very small or very large in Windows. Some applications, such as Keepass v1, looks very fuzzy. Hopefully this will improve with new versions of Parallels and Windows as Retina-like displays become  more common.
  • Not all applications support gestures. For example Firefox on Mac OS X doesn’t support pinch zoom. But I expect this will improve as new versions of applications are released.
  • Not having a built-in DVD drive is a pain. I was able to install Windows 7 by ripping a DVD to a USB stick using Infrarecorder (free). But this didn’t work for Photoshop Elements 11, so I had to download it from the app store, despite having it on DVD.
  • I couldn’t get Windows 8 to work. I installed it into a Bootcamp partition, but when I booted into Windows I just got a mouse pointer and  blue bar down the side of the screen. Apparently Windows 8 is not yet supported by Bootcamp.
  • I am told the graphics performance isn’t great. But I’m not intending to use it for games, so that doesn’t bother me much.

Overall it is an impressive machine and I’m pretty happy with it so far. In particular it is great to able to support Windows and Mac OS X on a single machine. But it does have some annoyances and I wouldn’t have purchased it to just to run Windows. No doubt PC ultrabook manufacturers will have copied its more innovative features fairly soon.

A couple of tips:

  • If you are  in the UK, consider purchasing from John Lewis. They will price match other ‘bricks and mortar’ vendors that have stock. But (at the time I purchased) they were offering 2 years additional warranty. I got them to price match PC World’s £100 off deal. I got £100 refunded and 2 years extra warranty. The service at John Lewis is usually also very good.
  • You probably want to get some form of case or sleeve to protect your lovely and expensive new Macbook. Beware that many of the existing cases are designed for the old Macbook Pros. Consequently they might not be a good fit for the thinner Retina models. I bought this Cool Bananas case. It is a good fit and quite well made. I just wish it had a bit more padding. No doubt more cases and sleeves will become available to fit the new models.

How to sign your Mac OS X App for Gatekeeper

If a prospective customer downloads your software onto Mac OS X 10.8 and it hasn’t been signed, they will see a scary warning:

Not good. To run unsigned software they need to go into Mac OS X Preferences>Security & Privacy>General and change Allow applications downloaded from Mac App store and identified developers to Anywhere:

Or they need to right/Ctrl click and see another scary warning. Double plus not good. This is the new Mac Gatekeeper system in action. Apple being Apple, Gatekeeper defaults to only allowing users to run software they have downloaded off the Internet if it has been signed. This could have a big effect on your conversion rate on Mac. So if you are shipping software for the Mac, you really need to sign it.

Apple fanboys will tell this is a sensible way for Apple to control software quality. A valid certificate shows that your software hasn’t been tampered with and, if it turns out to be malware, Apple can revoke your certificate. The more cynical might see it as a way for Apple to exert even greater control over Mac developers than it already does, while simultaneously extorting $99 per year from each and every one of them. Make your own mind up on that one.

I have now managed to sign my table planner software, ready for its next release. I should have done it months ago. But I expected the process to be so tedious that it has taken me this long to get around to it. And it was every bit as mind-numbingly tedious as I expected trying to find a few useful nuggets amongst the acres of Apple documentation. I found some useful stuff in blogs, but it was quite fragmented. So I have thrown together these notes in the hope that it saves someone else a few hours going round in circles. Note that I am not currently submitting my software to the Mac App Store, so I don’t cover that here. Also my software is developed in C++/Qt using Qt Creator, rather than Objective-C/Cocoa using XCode, and my approach reflects that.

1. Sign up for Apple Developer Connection ($99 per year). Doesn’t matter if you already paid through the nose for a Windows authenticode certificate. Gatekeeper only accepts Apple certificates, so you have no choice. On the plus side, you do get other benefits, including downloading new OS upgrades for free.

2. You need Mac OS X 10.8 so you can test that your signing works. If you have an Apple Developer Connection subscription, you can download 10.8 for free (get a code from the ADC downloads area and using it in the Mac App Store). I found the upgrade from 10.6 to 10.8 was surprisingly painless (Microsoft eat your heart out).

3. Request your Apple certificates and install them into your Keychain. You can do this from Xcode (instructions here). You may need to upgrade Xcode to a recent version.

4. Use the codesign command line tool to sign:

  • Every framework in your .app bundle
  • Every plugin in your .app bundle
  • Your .app file

I believe you can do this as part of your Xcode build. But I prefer a shell script. For example:

echo --sign frameworks --
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Frameworks/QtCore.framework/Versions/4/QtCore
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Frameworks/QtGui.framework/Versions/4/QtGui
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Frameworks/QtNetwork.framework/Versions/4/QtNetwork
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Frameworks/QtSql.framework/Versions/4/QtSql
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Frameworks/QtXml.framework/Versions/4/QtXml
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Frameworks/Qt3Support.framework/Versions/4/Qt3Support

echo --sign plugins--
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Plugins/accessible/libqtaccessiblecompatwidgets.dylib
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Plugins/accessible/libqtaccessiblewidgets.dylib
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Plugins/bearer/libqcorewlanbearer.dylib
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Plugins/bearer/libqgenericbearer.dylib
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Plugins/codecs/libqcncodecs.dylib
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Plugins/codecs/libqjpcodecs.dylib
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Plugins/codecs/libqkrcodecs.dylib
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Plugins/codecs/libqtwcodecs.dylib
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Plugins/graphicssystems/libqtracegraphicssystem.dylib
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app/Contents/Plugins/imageformats/libqjpeg.dylib

echo --sign app--
codesign --force --verify --verbose --sign "Developer ID Application: <yourID>" <yourApp>.app

I do this in a build shell script that automates the whole process of creating a .dmg for download. I’m not sure if the order you sign the components in is important.

Note that:

  • <yourID> is the ID on your certificate (in my case “Oryx Digital Ltd”).
  • For frameworks you sign the folder, not the file.
  • Any changes to the .app bundle after signing may invalidate the signature (that is kind of the point).

5. Verify the  signing of the .app file. For example:

codesign -vvv -d <yourApp>.app

6. Package your .app into a .dmg, .zip, .pkg or whatever other format you use to install it (I believe .pkg files might require additional signing with a different certificate).

7. Make sure your Mac OS X 10.8 machine is set to the default Gatekeeper setting.

8. Download your software onto Mac OS X 10.8 and check if the scary warning has gone away.

9. Pray that Apple doesn’t decide to revoke your certificate at some point for an infraction, real or imagined.

Until you have released a signed version you can put up a warning with some simple Javascript, for example:

Further reading:

http://www.hardcoded.net/devlogs/20120407

http://www.mactech.com/articles/mactech/Vol.24/24.11/CodeSigning-GetUsedtoIt!/index.html

http://www.macworld.co.uk/macsoftware/news/?newsid=3338078

http://support.apple.com/kb/HT5290

http://www.macworld.com/article/1165408/mountain_lion_hands_on_with_gatekeeper.html

http://developer.apple.com/library/mac/#documentation/ToolsLanguages/Conceptual/OSXWorkflowGuide/CodeSigning/CodeSigning.html

http://developer.apple.com/library/mac/#documentation/ToolsLanguages/Conceptual/OSXWorkflowGuide/DistributingApplicationsOutside/DistributingApplicationsOutside.html

Qt related:

http://lynxline.com/submiting-to-mac-app-store/

http://www.digia.com/en/Blogs/Qt-blog/Pasi_Matilainen/Dates/2012/4/How-to-Publish-Qt-Applications-in-the-Mac-App-Store/

http://comments.gmane.org/gmane.comp.lib.qt.user/637

Java related:

http://blogs.oracle.com/talkingjavadeployment/entry/java_applications_and_gatekeeper

http://www.ej-technologies.com/products/install4j/whatsnew51.html

Thanks to Jonathan of DeepTrawl and Stephane of LandlordMax for some useful pointers.

************** Update **************

Things have changed again for Mac OS X 10.9/10.10. See this post for an update.

Is it worth advertising Mac software on Google Adwords?

I learnt a long time ago that people will happily click on totally irrelevant pay per click ads. For example, if you bid on “seating plan” I can assure you that a significant percentage of people searching for “boeing 747 seating plan” will happily click on your ad titled “wedding seating plan”. They won’t buy anything, as they aren’t interested in wedding seating plans, but you still have to pay for each click. You can stop your ad showing to these searchers by adding “boeing” and “747” as negative keywords. Problem solved.

But what do you do if you are selling software that only runs on Mac OS X? The vast majority of searchers are running Windows. Indiscriminate clicks by them could quickly turn your Adwords ROI negative. In your Adwords campaign settings you can choose to only show ads on desktop computers and laptops. But you can’t choose the operating system.

As discussed above, putting “Mac” in the title is unlikely to be enough. You can’t use negative keywords, because the vast majority of Windows users searching for, say, backup software will type “backup software” not “Windows backup software”. You can just bid on searches containing keywords “Mac”, “Apple” or “OS X”, but will this be enough? My general advice to Mac only software vendors was to avoid Adwords, unless the ticket price of their software was in the hundreds of dollars. But, as my software runs on both Windows and Mac, I didn’t have any data to back this up.

Recently I got some data on Adwords clickthrough rates for a Mac only app (www.puzzlemakermac.com) by Hokua Software. They have kindly allowed me to share the data.

Initially they bid on generic keywords, such as “crossword maker” and ran ads such as the following with “Mac” displayed prominently in the title:

The results from analytics: 60% of the people clicking on the ads were on Windows and 40% on Mac.

Then Google banned them from the word “Mac” in their ads (it is possible to get this reversed with the express permission of Apple, but I don’t know how likely they are to grant this). So they switched to “OS X” in the ad, which hasn’t been blocked (yet).

The results from analytics: 73% of the people clicking on the ads were on Windows and 27% on Mac.

Then they restricted their bids to Mac targeted keywords such as “mac crossword maker”.

The results from analytics: 23% of the people clicking on the ads were on Windows and 73% on Mac. But there was a big drop in the number of impressions.

I think it is going to be almost impossible for anyone to get a return from Adwords when the majority of their clicks have no chance of generating a sale. So only bidding on Mac specific keywords seems to be the way to go. But there will still be a significant number of wasted clicks from Windows users. Also any Mac users who don’t use the appropriate keywords won’t see your ad. Consequently the return on time and money invested is likely to be a lot lower than Windows, cross-platform and web developers can expect. If you have a Mac only product with: a high ticket price product, well-defined keywords and limited competition, it might be worth trying Adwords. But otherwise it is probably better to wait and see if Google release OS targeting.

Of course, you could always use one of the free Adwords vouchers that Google are handing out like confetti (I get one every month in my PC Pro magazine) and try for yourself. This is how Hokua software got the results above. If you do, I would be interested to know how your results compare.