Domain Specific Language

Mapping iOS devices to their iOS version

  1. Encouraging users to update their phone (or tablet)
  2. Introducing ios-hw-to-os
  3. Some Wikipedia, some YAML, some JSON, some Rust, and some Swift
  4. Contributions welcome

I have an iOS app where I need to know what the latest available iOS version for a given iOS/iPadOS device is, but surprisingly I couldn't find any off-the-shelf solutions. I'm going to publish one myself. I will probably regret this.

Encouraging users to update their phone (or tablet)

At work, we are working on an iOS/iPadOS — or simply iOS, even if that is somewhat incorrect — app that has a lot of functionality, and some of our functionality is simply better (the underlying platform is more bug free) or we are accessing certain platform APIs that are only available on later versions. So we want to push users to upgrade to the latest iOS version.

For that we have a modal dialog that pops up whenever the user opens the app, but at most once every twenty-four hours.

Problem is, it's popping up even though some of the users are on the latest available version of iOS. We have a minimum iOS version of 15, but there are relatively recent devices that are stuck on iOS 16. iPhone10,6 (iPhone X) and iPad6,8 (iPad Pro 12.9-in. – 1st generation) are two models that are unreasonably stuck on iOS/iPadOS 16.

So we are asking users to upgrade to a later version of iOS than what's possible, and I'm sure that's at least a little annoying for them.

Introducing ios-hw-to-os

Now there exists both a (currently incomplete) JSON file in my ios-hw-to-os repository, and a simple Swift package called ios-hw-to-os-spm that makes it easy to use from your Swift or Swift-XCode application.

Here's an example of how to use the API

import IosHwToOs

func useAllMappings() {
    guard let mappings = IosHwToOsMappings.all() else {
        return
    }
    guard let device = mappings.devices.first(where: { $0.hardware == "iPhone10,1"}) else {
        return
    }
    // Prints IosHwToOsDevice(hardware: "iPhone10,1", version: "16.7.7")
    print("\(device)")
}

func useOneDevice() {
    guard let device = IosHwToOsDevice.get(hardware: "iPhone10,1") else {
        return
    }
    // Prints IosHwToOsDevice(hardware: "iPhone10,1", version: "16.7.7")
    print("\(device)")
}

Parsing the iOS version into a usable data structure / type is left as an exercise to the reader — we already have that at work — but it shouldn't be too hard and isn't strictly necessary from the point-of-view of the library.

Some Wikipedia, some YAML, some JSON, some Rust, and some Swift

I used Wikipedia as my source of information, specifically these pages — which are excellent:

I manually copied the information into a YAML file, because even though I don't particularly like whitespace-as-strucutre, it has some features that JSON sorely lacks – readabilty & comments. The file looks like this:

devices:
# Supported iPad versions
- type: iPad
  version: 17.4.1
  status: Supported
  hardware:
  - iPad13,18
  - iPad13,19
  # ...more
# Unsupported iPad versions
- type: iPad
  version: 16.7.7
  status: Unsupported
  hardware:
  - iPad6,11
  - iPad6,12
# ...more

I then use a very small Rust program to convert the YAML into JSON. The JSON file has a very different structure from the YAML file. The YAML file is structured to be easy to update, and is sectioned by type of device, while the JSON file is basically just an array of all the devices without any sectioning.

{
  "devices": [
    {
      "hardware": "iPad13,18",
      "version": "17.4.1"
    },
    {
      "hardware": "iPad13,19",
      "version": "17.4.1"
    },
...more

After creating the JSON file, that one is copied over to ios-hw-to-os-spm and packaged in a Swift package.

Contributions welcome

Want to expand ios-hw-to-os to cover Apple Watch? Maybe you need devices older than those that can run iOS 15? Do you want to add more fields or improve the Swift API? PRs are welcome, and I think I left reasonably clear instructions on how to manage the YAML / JSON structure.