14.5. Releasing CamCOPS

First build the client for all appropriate platforms (see Building the CamCOPS client).

If the client or server core has changed, remember to ensure appropriate strings are internationalized (see Internationalization).

Releasing a new client and server involves the following steps:

14.5.1. Code and documentation

14.5.2. Android client

14.5.2.1. Google Play Store settings

  • Developer URL is https://play.google.com/apps/publish ‣ pick your application ‣ e.g. Release management ‣ App releases

  • App category: “Utility/other”.

  • Content rating: by Google’s definitions, CamCOPS hits criteria for references to illegal drugs (e.g. Deakin1HealthReview, and when strings are available, the various drug abuse scoring scales). Did not meet Google Play’s criteria for sex, violence, etc.

  • Note that “Pending publication” means you’re waiting for Google Play to sort itself out, not that you have to do anything.

  • Note re versions:

    • As above, the AndroidManifest.xml has an INTEGER version, so we may as well use consecutive numbers. See the release history below.

    The Google Developer site will check the version codes. Failed uploads can sometimes block that version number.

  • You upload a new version with [Release] Production ‣ Create Release.

  • Note also that if you try to install the .apk directly to a device that’s had an installation from Google Play Store, you’ll get the error INSTALL_FAILED_UPDATE_INCOMPATIBLE (I think). Or if you mix debug/release versions.

  • Finally, note that there can be a significant delay between uploading a new release and client devices seeing it on Google Play (or even being able to see it at https://play.google.com/store, or via the direct link at https://play.google.com/store/apps/details?id=org.camcops.camcops). Perhaps 10 minutes to the main web site?

14.5.2.2. Google Play Store release history

Google Play Store release name

AndroidManifest.xml version code

AndroidManifest.xml name

To Play Store on

Minimum Android API

Target Android API

2.0.1 (beta)

2

2.0.1

2017-08-04

16

23

2.0.4 (beta)

3

2.0.4

2017-10-22

16

23

2.2.3 (beta)

5

2.2.3

2018-06-25

16

26

2.2.4 (beta)

6

2.2.4

2018-07-18

23

26

2.2.6 (beta)

7

2.2.6

2018-07-31

23

26

2.2.7

8

2.2.7

2018-08-19

23

26

2.2.8 to 2.3.0

N/A, internal only

N/A, internal only

N/A, internal only

23

26

2.3.1

9

2.3.1

2019-03-24

23

26

2.3.2

10

2.3.2

2019-04-05

23

26

2.3.3

11

2.3.3

2019-06-15

23

26

2.3.4

12

2.3.4

2019-06-21

23

26

2.4.1

15 (32-bit ARM); 16 (64-bit ARM)

2.4.1

2021-02-10

23

29

2.4.2

N/A, identical to 2.4.3

N/A

N/A

23

29

2.4.3

17 (32-bit ARM); 18 (64-bit ARM)

2.4.3

2021-03-30

23

29

2.4.4

N/A, server only

N/A

N/A

23

29

2.4.5

N/A, macOS only

N/A

N/A

23

29

2.4.6

19 (32-bit ARM); 20 (64-bit ARM)

2.4.6

2021-05-08

23

29

2.4.7

N/A, server only

N/A

N/A

23

29

2.4.8

21 (32-bit ARM); 22 (64-bit ARM)

2.4.8

2021-07-15

23

29

2.4.9

23 (32-bit ARM); 24 (64-bit ARM)

2.4.9

2021-08-10

23

29

2.4.10

N/A, server only

N/A

N/A

23

29

2.4.11

25 (32-bit ARM); 26 (64-bit ARM)

2.4.11

2021-10-08

23

29

Note: target API of 30 required as of Nov 2021: https://android-developers.googleblog.com/2020/11/new-android-app-bundle-and-target-api.html

14.5.3. iOS client

To deploy to the Apple Store:

  • Up the version numbers in Info.plist

  • Build the project first in QtCreator for iOS (arm64) device, release

  • Start Xcode

  • Load the xcodeproj file for this build into Xcode

  • Set the Active scheme to be Any iOS Device (arm64)

  • Archive the project (Product -> Archive)

  • Open the Organizer (Window -> Organizer)

  • Select the Archive and then Distribute App to App Store Connect, accepting all the defaults

The progress bar shows 100% throughout the upload but you can watch the java process on the Network tab of the Activity Monitor.

Validate App does not run the same set of tests as the App Store does. Even if after half an hour your package is successfully uploaded to App Store Connect there may still be problems, of which you will be notified by email several minutes later.

If you want to debug the .ipa file sent to App Store Connect, choose the “Export” option. It’s a zip file.

The archive process will result in a broken symlink when you next build the project in QtCreator (error message mkdir failed). You can just delete it.

14.5.4. MacOS client

Build in QtCreator as usual then sign for distribution outside the Apple Store as a dmg file:

codesign --verify --verbose --timestamp --sign "Developer ID Application: UNIVERSITY OF CAMBRIDGE DEPARTMENT OF PSYCHIATRY (XXXXXXXXXX)" --options runtime camcops.app
/path/to/macos/qt/install/bin/macdeployqt camcops.app -verbose=3 -dmg -no-strip

This should sign with a valid Developer ID certificate, include a secure timestamp and have the hardened runtime enabled. macdeployqt can also do code signing but doesn’t support all the required options, so we do it separately.

To notarize the app with Apple (to prevent malicious software warnings), you need to know the app-specific password for altool which was generated at https://appleid.apple.com/ and then:

xcrun altool -t osx -f camcops.dmg --primary-bundle-id "uk.ac.cam.psychiatry.camcops.dmg" --notarize-app -u <ACCOUNT OWNER APPLE ID>

You will be prompted to enter the app-specific password generated by the account owner.

You can watch the upload progress in the Activity Monitor app (Network tab, look out for java process after a few minutes).

After the upload has finished, you should see something like:

No errors uploading 'camcops.dmg'
RequestUUID = 12345678-9abc-def0-1234-56789abcdef0

You can check progress with:

xcrun altool --notarization-info 12345678-9abc-def0-1234-56789abcdef0 -u <ACCOUNT OWNER APPLE ID>

Again use the app-specific password.

If notarization failed, follow the link to the log file in a browser to see what the problem was.

If it passed, run this command:

xcrun stapler staple -v camcops.dmg

camcops.dmg can now be uploaded to the GitHub release assets.

14.5.5. Windows client

The client will be packaged automatically by the camcops_windows_innosetup.iss script, which runs under Inno Setup.

Warning

Under Windows, be particularly careful that both the 32-bit and 64-bit versions are fresh. Sometimes Build ‣ Clean All doesn’t seem to delete all the old executables – just delete the whole build tree manually if need be. Check from the development root directory with dir camcops.exe /s.

Upload to https://github.com/RudolfCardinal/camcops/releases with a tag named v<VERSION_NUMBER>.

14.5.6. Server

  • Create the Debian (.deb) and CentOS (.rpm) editions using the server/tools/MAKE_LINUX_PACKAGES.py script. Binaries will end up in server/packagebuild/. Upload to https://github.com/RudolfCardinal/camcops/releases with a tag named v<VERSION_NUMBER>.

  • The step above will also create a Python distibution in server/dist/. (If you want to run that step by itself, use server/MAKE_PYTHON_PACKAGE.sh.) Upload it to PyPI via twine upload dist/camcops_server-VERSION.tar.gz.