How to Create Apple Watchos5 Complication

How to create apple watchOS5 complication?

Here's an example by Apple of how to communicate with the apple watch app. You need to painstakingly read the readme about 25 times to get all the app group identifiers changed in that project.

  • Your main phone app assets are not visible to the watch app
  • Your watch storyboard assets go in WatchKit target
  • Your programmatically accessed assets go into the watch extension target

Original answers:

  • Can I provide one style of complication only (large horizontal -
    modular large) - YES
  • Do I need to provide any iPhone app content beyond
    managing the complication logic, or can I get away without having a
    view controller? YES - watch apps have computation limits imposed on them
  • Do I control the appearance of my complication by
    adding something to the assets folder (it has a bunch of graphic
    slots)? See below - it's both assets folder and placeholders

Modify the example above to create a placeholder image displayed on the watch (when you are selecting a complication while modifying the screen layout)

func getPlaceholderTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
// Pass the template to ClockKit.
if complication.family == .graphicRectangular {

// Display a random number string on the body.
let template = CLKComplicationTemplateGraphicRectangularLargeImage()
template.textProvider = CLKSimpleTextProvider(text: "---")
let image = UIImage(named: "imageFromWatchExtensionAssets") ?? UIImage()
template.imageProvider = CLKFullColorImageProvider(fullColorImage: image)

// Pass the entry to ClockKit.
handler(template)
}else {
handler(nil);
return
}

}

sending small packets to the watch (will not send images!)

func updateHeartRate(with sample: HKQuantitySample){

let context: [String: Any] = ["title": "String from phone"]
do {
try WCSession.default.updateApplicationContext(context)
} catch {
print("Failed to transmit app context")
}
}

Transferring images and files:

func uploadImage(_ image: UIImage, name: String, title: String = "") {

let data: Data? = UIImagePNGRepresentation(image)

do {
let fileManager = FileManager.default
let documentDirectory = try fileManager.url(for: .cachesDirectory,
in: .userDomainMask,
appropriateFor:nil,
create:true)
let fileURL = try FileManager.fileURL("\(name).png")

if fileManager.fileExists(atPath: fileURL.path) {
try fileManager.removeItem(at: fileURL)
try data?.write(to: fileURL, options: Data.WritingOptions.atomic)
} else {
try data?.write(to: fileURL, options: Data.WritingOptions.atomic)
}

if WCSession.default.activationState != .activated {
print("session not activated")
}
fileTransfer = WCSession.default.transferFile(fileURL, metadata: ["name":name, "title": title])

}
catch {
print(error)
}
print("Completed transfer \(name)")
}

How to provide Apple Watch Complication Asset for 45mm?

The issue is that the size of the image in the asset catalog is smaller than it really should be according to the Apple Human Interface Guidelines. Thus this causes the images not to be filled. As there's no option to drop the 45mm version you need to calculate and resize the image yourself.

This article is the solution!

http://www.glimsoft.com/02/18/watchos-complications/?utm_campaign=iOS%2BDev%2BWeekly&utm_medium=web&utm_source=iOS%2BDev%2BWeekly%2BIssue%2B547

ComplicationController+Ext.swift

extension ComplicationController {
enum ComplicationImageType {
case graphicCircularImage
}

struct ComplicationImageSizeCollection {
var size38mm: CGFloat = 0
let size40mm: CGFloat
let size41mm: CGFloat
let size44mm: CGFloat
let size45mm: CGFloat

// The following sizes are taken directly from HIG: https://developer.apple.com/design/human-interface-guidelines/watchos/overview/complications/
static let graphicCircularImageSizes = ComplicationImageSizeCollection(size40mm: 42, size41mm: 44.5, size44mm: 47, size45mm: 50)

func sizeForCurrentWatchModel() -> CGFloat {
let screenHeight = WKInterfaceDevice.current().screenBounds.size.height
if screenHeight >= 242 {
// It's the 45mm version..
return self.size45mm
}
else if screenHeight >= 224 {
// It's the 44mm version..
return self.size44mm
}
else if screenHeight >= 215 {
// It's the 41mm version..
return self.size41mm
}
else if screenHeight >= 197 {
return self.size40mm
}
else if screenHeight >= 170 {
return self.size38mm
}
return self.size40mm // Fallback, just in case.
}

static func sizes(for type: ComplicationImageType) -> ComplicationImageSizeCollection {
switch type {
case .graphicCircularImage: return Self.graphicCircularImageSizes
}
}

static func getImage(for type: ComplicationImageType) -> UIImage {
let complicationImageSizes = ComplicationImageSizeCollection.sizes(for: .graphicCircularImage)
let width = complicationImageSizes.sizeForCurrentWatchModel()
let size = CGSize(width: width, height: width)

var filename: String!

switch type {
case .graphicCircularImage: filename = "gedenken_graphic_circular_pdf"
}

return renderPDFToImage(named: filename, outputSize: size)
}

static private func renderPDFToImage(named filename: String, outputSize size: CGSize) -> UIImage {

// Create a URL for the PDF file
let resourceName = filename.replacingOccurrences(of: ".pdf", with: "")
let path = Bundle.main.path(forResource: resourceName, ofType: "pdf")!
let url = URL(fileURLWithPath: path)

guard let document = CGPDFDocument(url as CFURL),
let page = document.page(at: 1) else {
fatalError("We couldn't find the document or the page")
}

let originalPageRect = page.getBoxRect(.mediaBox)

// With the multiplier, we bring the pdf from its original size to the desired output size.
let multiplier = size.width / originalPageRect.width

UIGraphicsBeginImageContextWithOptions(size, false, 0)
let context = UIGraphicsGetCurrentContext()!

// Translate the context
context.translateBy(x: 0, y: (originalPageRect.size.height * multiplier))

// Flip the context vertically because the Core Graphics coordinate system starts from the bottom.
context.scaleBy(x: multiplier * 1.0, y: -1.0 * multiplier)

// Draw the PDF page
context.drawPDFPage(page)

let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()

return image
}
}
}

ComplicationController.swift

func createGraphicCircularTemplate() -> CLKComplicationTemplate {
let template = CLKComplicationTemplateGraphicCircularImage()
let imageLogoProvider = CLKFullColorImageProvider()

imageLogoProvider.image = ComplicationImageSizeCollection.getImage(for: .graphicCircularImage)
template.imageProvider = imageLogoProvider

return template
}

iOS WatchOS5 - How to support more than one complication family for a watch app?

Turns out I was misled by Apple's documentation. I needed to use GraphicCircular complication(new in WatchOS5) type as opposed to modular (old watch faces)

func circularTemplate() -> CLKComplicationTemplateGraphicCircularOpenGaugeSimpleText{
let template = CLKComplicationTemplateGraphicCircularOpenGaugeSimpleText()
let gauge = CLKSimpleGaugeProvider(style: .ring, gaugeColor: UIColor.green), fillFraction: 0.3)
template.gaugeProvider = gauge

let random = arc4random() % 999

let middle = CLKSimpleTextProvider(text: "4.5", shortText: "4")
middle.tintColor = kRGBColorFromHex(0x657585)
template.tintColor = kRGBColorFromHex(0x657585)
template.centerTextProvider = middle

let bottom = CLKSimpleTextProvider(text: "-\(random)", shortText: "1..")
template.bottomTextProvider = bottom
return template
}

New style:

Sample Image

Old Style:
Sample Image

Creating Complications for Apple watch

I want to create complication like native Battery one (Circular Ring).

How can I fetch live data for the complications, maybe API call, or data from iPhone? -

  • Use WatchKit.framework to do this and use WCSession class to
    perform the session talking between the phone and the watch.

  • You could also use the background tasks API introuduced in WatchOS 3
    to make API calls in the background -
    https://developer.apple.com/library/content/releasenotes/General/WhatsNewInwatchOS/Articles/watchOS3.html

  • To update complications in watch OS 3 - https://developer.apple.com/reference/watchkit/wkapplicationrefreshbackgroundtask

Can I create more then one same complication type?

No you cannot, one app can have only one type of complication.



Related Topics



Leave a reply



Submit