16

We know that there are two screen sizes for Apple Watch: 38mm and 42mm. The WKInterfaceDevice class provides a readable property named screenBounds. I wrote an extension for WKInterfaceDevice, trying to add a method to detect current device type.

import WatchKit

enum WatchResolution {

    case Watch38mm, Watch42mm
}

extension WKInterfaceDevice {

    class func currentResolution() -> WatchResolution {

        let watch38mmRect = CGRectMake(0.0, 0.0, 136.0, 170.0)
        let watch42mmRect = CGRectMake(0.0, 0.0, 156.0, 195.0)

        let currentBounds = WKInterfaceDevice.currentDevice().screenBounds

        if CGRectEqualToRect(currentBounds, watch38mmRect) {

            return WatchResolution.Watch38mm
        } else {

            return WatchResolution.Watch42mm
        }
    }
}

Is that the correct method to detect Apple Watch size? Is there another method I am missing in the Apple docs?

tounaobun
  • 14,570
  • 9
  • 53
  • 75

11 Answers11

25

Your code looks good, but has a few minor issues:

  • You don't have a case for an "unknown" screen size (possibly released in the future)
  • You're using CGRectMake but in Swift you should use a CGRect initializer
  • You're using CGRectEqualToRect but in Swift you can just use == or switch
  • You're explicitly returning WatchResolution enums, but you don't need to be explicit - Swift will figure it out from your method signature
  • You're declaring watch42mmRect but not using it for anything

I would rewrite it like this:

enum WatchResolution {
    case Watch38mm, Watch42mm, Unknown
}

extension WKInterfaceDevice {
    class func currentResolution() -> WatchResolution {
        let watch38mmRect = CGRect(x: 0, y: 0, width: 136, height: 170)
        let watch42mmRect = CGRect(x: 0, y: 0, width: 156, height: 195)

        let currentBounds = WKInterfaceDevice.currentDevice().screenBounds

        switch currentBounds {
        case watch38mmRect:
            return .Watch38mm
        case watch42mmRect:
            return .Watch42mm
        default:
            return .Unknown
        }
    }
}
Aaron Brager
  • 65,323
  • 19
  • 161
  • 287
8

Update Swift 4:

It includes new launch of Watch resolutions:

enum WatchResolution {
    case Watch38mm, Watch40mm,Watch42mm,Watch44mm, Unknown  
}

extension WKInterfaceDevice {
class func currentResolution() -> WatchResolution {
    let watch38mmRect = CGRect(x: 0, y: 0, width: 136, height: 170)
    let watch40mmRect = CGRect(x: 0, y: 0, width: 162, height: 197)
    let watch42mmRect = CGRect(x: 0, y: 0, width: 156, height: 195)
    let watch44mmRect = CGRect(x: 0, y: 0, width: 184, height: 224)

    let currentBounds = WKInterfaceDevice.current().screenBounds

    switch currentBounds {
    case watch38mmRect:
        return .Watch38mm
    case watch40mmRect:
        return .Watch40mm
    case watch42mmRect:
        return .Watch42mm
    case watch44mmRect:
        return .Watch44mm
    default:
        return .Unknown
    }
  } 
}

Usage

let resol = WKInterfaceDevice.currentResolution()
    switch resol {
    case .Watch38mm, .Watch42mm:
        // Do Something
    case .Watch40mm, .Watch44mm:
        // Do Something
    default:
        // Do Something
    }

Reference Link: Apple Developer Watch Interface Link

Hope that helps....

Thanks

Harjot Singh
  • 6,767
  • 2
  • 38
  • 34
4

This is what I am doing:

enum WatchModel {
    case w38, w40, w42, w44, unknown
}

extension WKInterfaceDevice {

    static var currentWatchModel: WatchModel {
        switch WKInterfaceDevice.current().screenBounds.size {
        case CGSize(width: 136, height: 170):
            return .w38
        case CGSize(width: 162, height: 197):
            return .w40
        case CGSize(width: 156, height: 195):
            return .w42
        case CGSize(width: 184, height: 224):
            return .w44
        default:
            return .unknown
    }
  }
}
Juan Sagasti
  • 326
  • 2
  • 5
3

Your method looks fine and nothing is wrong with it. Another solution is to use contentFrame property of the WKInterfaceController. If the width is 312(156) pixels then its 42mm else is 38mm.

enter image description here

Ashraf Tawfeeq
  • 3,036
  • 1
  • 20
  • 34
3
CGRect rect = [WKInterfaceDevice currentDevice].screenBounds;
if (rect.size.height == 195.0) {
    // Apple Watch 42mm
}else if (rect.size.height == 170.0){
    // Apple Watch 38mm 
}
3

Modified answer based on others from here. Think that looks more proper, plus including new Watch Series 7:

#if os(watchOS)
import WatchKit

public enum WatchCase {
    case watch38mm
    case watch40mm
    case watch41mm
    case watch42mm
    case watch44mm
    case watch45mm
    case unknown
}

extension WKInterfaceDevice {
    public var screenCase: WatchCase {
        switch WKInterfaceDevice.current().screenBounds.size {
        case CGSize(width: 136, height: 170):
            return .watch38mm
        case CGSize(width: 162, height: 197):
            return .watch40mm
        case CGSize(width: 176, height: 215):
            return .watch41mm
        case CGSize(width: 156, height: 195):
            return .watch42mm
        case CGSize(width: 184, height: 224):
            return .watch44mm
        case CGSize(width: 198, height: 242):
            return .watch45mm
        default:
            return .unknown
        }
    }
}
#endif

USAGE:

WKInterfaceDevice.current().screenCase
Serj Rubens
  • 621
  • 8
  • 12
2

Checking screenBounds seems not working anymore on xCode 7 with iOS 9 with a real device, the watch size returned by Watch 38mm is always 156x195.

My (bad) alternative is to check the viewcontroller contentFrame width or height depending of the view structure

Beninho85
  • 3,273
  • 27
  • 22
1

All the above solutions works fine. Along with screenBounds ([[WKInterfaceDevice currentDevice] screenBounds]), it will be good to check the screenScale ([[WKInterfaceDevice currentDevice] screenScale]) as well. Actual size will be screenBounds * screenScale in that sense.

More reference: https://developer.apple.com/watch/human-interface-guidelines/specifications/

1

For a Swift 4 shorter example:

enum WatchType {
    case watch38mm, watch42mm
}

extension WKInterfaceDevice {

    class var currentResolution: WatchType {
        // Apple Watch 38mm 136x170 - 42mm 156x195
        return WKInterfaceDevice.current().screenBounds.width == 136 ? .watch38mm : .watch42mm
    }

}
RichAppz
  • 1,520
  • 2
  • 14
  • 27
1

Swift 5 version of @Aaron Brager answer(+ support for new Apple Watches).

enum WatchResolution {
case Watch38mm, Watch40mm, Watch42mm, Watch44mm, Unknown
}

extension WKInterfaceDevice {

class func currentResolution() -> WatchResolution {

    let watch38mmRect = CGRect(x: 0, y: 0, width: 136, height: 170)
    let watch40mmRect = CGRect(x: 0, y: 0, width: 162, height: 197)
    let watch42mmRect = CGRect(x: 0, y: 0, width: 156, height: 195)
    let watch44mmRect = CGRect(x: 0, y: 0, width: 184, height: 224)

    let currentBounds = WKInterfaceDevice.current().screenBounds

    switch currentBounds {
    case watch38mmRect:
        return .Watch38mm
    case watch40mmRect:
        return .Watch40mm
    case watch42mmRect:
        return .Watch42mm
    case watch44mmRect:
        return .Watch44mm
    default:
        return .Unknown
    }
}
}


/*
 all resolutions
 40mm: 394×324
 44mm: 448×368
 38mm: 340×272
 42mm: 390×312
 */
Ahmadreza
  • 6,950
  • 5
  • 50
  • 69
1

I do this to avoid depending too much on current sizes and future proof myself

public enum WatchSizeClass {
    case small, regular
}

public extension WKInterfaceDevice {
    static var currentWatchSizeClass: WatchSizeClass {
        if WKInterfaceDevice.current().screenBounds.size.width < 150 {
            return .small
        } else {
            return .regular
        }
    }
}

Right now, .small is only returned for 38mm.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192