Усложнение WatchOS3, которое запускает приложение

Я хотел бы создать усложнение для watchOS 3, которое просто запустит мое приложение. Я использовал XCode для создания ComplicationController:

class ComplicationController: NSObject, CLKComplicationDataSource
{

    // MARK: - Timeline Configuration

    func getSupportedTimeTravelDirections(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimeTravelDirections) -> Void) {
        handler([.forward, .backward])
    }

    func getTimelineStartDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
        handler(nil)
    }

    func getTimelineEndDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
        handler(nil)
    }

    func getPrivacyBehavior(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationPrivacyBehavior) -> Void) {
        handler(.showOnLockScreen)
    }

    // MARK: - Timeline Population

    func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
        // Call the handler with the current timeline entry
        handler(nil)
    }

    func getTimelineEntries(for complication: CLKComplication, before date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
        // Call the handler with the timeline entries prior to the given date
        handler(nil)
    }

    func getTimelineEntries(for complication: CLKComplication, after date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
        // Call the handler with the timeline entries after to the given date
        handler(nil)
    }

    // MARK: - Placeholder Templates

    func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
        // This method will be called once per supported complication, and the results will be cached
        handler(nil)
    }

}

и добавлены изображения для круговых, модульных и утилитарных активов. Но когда я запускаю приложение для часов, я не могу выбрать расширения для циферблата. Что мне еще нужно сделать?

Спасибо

Грег


person Greg Robertson    schedule 26.09.2016    source источник


Ответы (3)


Эти изменения кода необходимы:

func getSupportedTimeTravelDirections(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimeTravelDirections) -> Void)
{
    handler([])
}


func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void)
{
    if complication.family == .circularSmall
    {

        let template = CLKComplicationTemplateCircularSmallRingImage()
        template.imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "Circular")!)
        let timelineEntry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template)
        handler(timelineEntry)

    } else if complication.family == .utilitarianSmall
    {

        let template = CLKComplicationTemplateUtilitarianSmallRingImage()
        template.imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "Utilitarian")!)
        let timelineEntry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template)
        handler(timelineEntry)

    } else if complication.family == .modularSmall
    {

        let template = CLKComplicationTemplateModularSmallRingImage()
        template.imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "Modular")!)
        let timelineEntry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template)
        handler(timelineEntry)

    } else {

        handler(nil)

    }

}


func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void)
{        
    switch complication.family
    {
        case .circularSmall:
            let image: UIImage = UIImage(named: "Circular")!
            let template = CLKComplicationTemplateCircularSmallSimpleImage()
            template.imageProvider = CLKImageProvider(onePieceImage: image)
            handler(template)
        case .utilitarianSmall:
            let image: UIImage = UIImage(named: "Utilitarian")!
            let template = CLKComplicationTemplateUtilitarianSmallSquare()
            template.imageProvider = CLKImageProvider(onePieceImage: image)
            handler(template)
        case .modularSmall:
            let image: UIImage = UIImage(named: "Modular")!
            let template = CLKComplicationTemplateModularSmallSimpleImage()
            template.imageProvider = CLKImageProvider(onePieceImage: image)
            handler(template)
        default:
            handler(nil)
    }
}

Кроме того, вам необходимо предоставить изображения в качестве активов в расширении.

person Greg Robertson    schedule 26.09.2016
comment
Можете ли вы дать некоторые пояснения, а также. Это будет более полезно для понимания решения :) - person Abhishek Thapliyal; 26.07.2018
comment
Также вы можете сделать снимок экрана, как вы добавили, как я добавил в ту же папку с осложнениями, но я получаю сбой на UIimage - person Abhishek Thapliyal; 26.07.2018
comment
@AbhishekThapliyal По умолчанию ваши изображения осложнений находятся в папке Complications, поэтому в этом случае правильная ссылка на изображения будет let image = UIImage(named: "Complication/Utilitarian")! - person Nace; 26.12.2018
comment
@WebMajstr: Спасибо за информацию :) - person Abhishek Thapliyal; 26.12.2018

Новые графические усложнения Apple Watch 4 выглядят так:

func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
    // Call the handler with the current timeline entry
    switch complication.family {
    case .graphicCorner:
        if #available(watchOSApplicationExtension 5.0, *) {
            let template = CLKComplicationTemplateGraphicCornerCircularImage()
            let image = UIImage(named: "Complication/Graphic Corner")!
            template.imageProvider = CLKFullColorImageProvider(fullColorImage: image)
            let timelineEntry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template)
            handler(timelineEntry)
        } else {
            handler(nil)
        }
    case .graphicCircular:
        if #available(watchOSApplicationExtension 5.0, *) {
            let template = CLKComplicationTemplateGraphicCircularImage()
            let image = UIImage(named: "Complication/Graphic Circular")!
            template.imageProvider = CLKFullColorImageProvider(fullColorImage: image)
            let timelineEntry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template)
            handler(timelineEntry)
        } else {
            handler(nil)
        }
    default:
        handler(nil)
    }
}

func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
    // This method will be called once per supported complication, and the results will be cached
    switch complication.family {
    case .graphicCorner:
        if #available(watchOSApplicationExtension 5.0, *) {
            let template = CLKComplicationTemplateGraphicCornerCircularImage()
            let image = UIImage(named: "Complication/Graphic Corner")!
            template.imageProvider = CLKFullColorImageProvider(fullColorImage: image)
            handler(template)
        } else {
            handler(nil)
        }
    case .graphicCircular:
        if #available(watchOSApplicationExtension 5.0, *) {
            let template = CLKComplicationTemplateGraphicCircularImage()
            let image = UIImage(named: "Complication/Graphic Circular")!
            template.imageProvider = CLKFullColorImageProvider(fullColorImage: image)
            handler(template)
        } else {
            handler(nil)
        }
    default:
        handler(nil)
    }
}
person Zoltan Vinkler    schedule 26.08.2019

Добавьте новые графические расширения Apple Watch 4 (watchOS 5.0+) и предотвратите сбой на Apple Watch Series 1, 2 и 3.

Важно: код от Zoltan будет аварийно завершать работу на Apple Watch серии 3 или ниже.

Согласно документации Apple, для новых графических дополнений требуется watchOS 5.0 или выше и Watch Series 4 или новее:

Примечание Циферблаты, поддерживающие графические шаблоны, доступны только на Apple Watch Series 4 или новее.

Это означает, что Watch Series 3 с watchOS 5 или 6 (из-за if #available(watchOSApplicationExtension 5.0, *)) попытаются загрузить изображение сложности из каталога активов. Однако, поскольку истончение приложений включено по умолчанию, Watch Series 3 не не имеет изображения в двоичном виде, поэтому следующая строка приведет к краху приложения:

let image = UIImage(named: "Complication/Graphic Corner")!

Мы обнаружили это, когда нашли тысячи отчетов о сбоях в Xcode:

  1. Откройте Xcode
  2. Окно -> Органайзер
  3. Выберите вкладку Сбои
  4. Выберите версию App Store

Мы нашли отчет о сбое для каждого из двух поддерживаемых графических расширений, все они были с watchOS 5 или 6 и Watch Series 2 или 3, например:

введите здесь описание изображения

Решение

Встройте загрузку графического актива в оператор IF и верните nil в качестве шаблона, чтобы он не зависал на устройствах без актива.

пример выше от Zoltan будет таким:

case .graphicCorner:
        if #available(watchOSApplicationExtension 5.0, *) {
            let template = CLKComplicationTemplateGraphicCornerCircularImage()
            if let image = UIImage(named: "Complication/Graphic Corner") {
                template.imageProvider = CLKFullColorImageProvider(fullColorImage: image)
                let timelineEntry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template)
                handler(timelineEntry)
            } else {
                handler(nil)
            }
        } else {
            handler(nil)
        }

Для эффективного и удобного кода мы создали повторно используемую функцию templateForComplication(), которая используется во всех трех обязательных функциях делегата:

class ComplicationController: NSObject, CLKComplicationDataSource {
    
    // MARK: Mandatory Delegate Methods
    
    func getSupportedTimeTravelDirections(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimeTravelDirections) -> Void) {
        // Turn off time travelling:
        handler([])
    }
    
    func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
        let template = templateForComplication(complication: complication)
        let timelineEntry = CLKComplicationTimelineEntry(date: Date(), complicationTemplate: template!)
        handler(timelineEntry)
    }
    
    func getPlaceholderTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
        // This method will be called once per supported complication, and the results will be cached
        handler(templateForComplication(complication: complication))
    }
    
    func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
        handler(templateForComplication(complication: complication))
    }
    
    
    // MARK: Helper Methods
    
    private func templateForComplication(complication: CLKComplication) -> CLKComplicationTemplate? {
        // Init default output:
        var template: CLKComplicationTemplate? = nil
        
        // Graphic Complications are only availably since watchOS 5.0:
        if #available(watchOSApplicationExtension 5.0, *) {
            // NOTE: Watch faces that support graphic templates are available only on Apple Watch Series 4 or later. So the binary on older devices (e.g. Watch Series 3) will not contain the images.
            if complication.family == .graphicCircular {
                let imageTemplate = CLKComplicationTemplateGraphicCircularImage()
                // Check if asset exists, to prevent crash on non-supported devices:
                if let fullColorImage = UIImage(named: "Complication/Graphic Circular") {
                    let imageProvider = CLKFullColorImageProvider.init(fullColorImage: fullColorImage)
                    imageTemplate.imageProvider = imageProvider
                    template = imageTemplate
                }
            }
            else if complication.family == .graphicCorner {
                let imageTemplate = CLKComplicationTemplateGraphicCornerCircularImage()
                // Check if asset exists, to prevent crash on non-supported devices:
                if let fullColorImage = UIImage(named: "Complication/Graphic Corner") {
                    let imageProvider = CLKFullColorImageProvider.init(fullColorImage: fullColorImage)
                    imageTemplate.imageProvider = imageProvider
                    template = imageTemplate
                }
            }
        }
        
        // For all watchOS versions:
        if complication.family == .circularSmall {
            let imageTemplate = CLKComplicationTemplateCircularSmallSimpleImage()
            let imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "Complication/Circular")!)
            imageProvider.tintColor = UIColor.blue
            imageTemplate.imageProvider = imageProvider
            template = imageTemplate
        }
        else if complication.family == .modularSmall {
            let imageTemplate = CLKComplicationTemplateModularSmallSimpleImage()
            let imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "Complication/Modular")!)
            imageProvider.tintColor = UIColor.blue
            imageTemplate.imageProvider = imageProvider
            template = imageTemplate
        }
        else if complication.family == .utilitarianSmall {
            let imageTemplate = CLKComplicationTemplateUtilitarianSmallSquare()
            let imageProvider = CLKImageProvider(onePieceImage: UIImage(named: "Complication/Utilitarian")!)
            imageProvider.tintColor = UIColor.blue
            imageTemplate.imageProvider = imageProvider
            template = imageTemplate
        }
        
        return template
    }
}
person Martijn    schedule 03.09.2020