Upgrade to Pro — share decks privately, control downloads, hide ads and more …

未知のファイル形式をCodableで読み書きするのに役立つテクニック 『Apple Watchの文字盤ファイル』 / Codable techniques on analyzing undocumented file format - Apple Watch watchface file -

9bda8755a689204677a198ee85c0eb07?s=47 banjun
PRO
September 18, 2021

未知のファイル形式をCodableで読み書きするのに役立つテクニック 『Apple Watchの文字盤ファイル』 / Codable techniques on analyzing undocumented file format - Apple Watch watchface file -

9bda8755a689204677a198ee85c0eb07?s=128

banjun
PRO

September 18, 2021
Tweet

Transcript

  1. ະ஌ͷϑΝΠϧܗࣜΛ
 CodableͰಡΈॻ͖͢Δͷʹ໾ཱͭςΫχοΫ iOSDC Japan 2021 גࣜձࣾZOZOςΫϊϩδʔζ ςοΫϦʔυ ͹Μ͡ΎΜ🍓 / @banjun

    Copyright © ZOZO Technologies, Inc. ʰApple Watchͷจࣈ൫ϑΝΠϧʱ ⌚
  2. © ZOZO Technologies, Inc. גࣜձࣾZOZOςΫϊϩδʔζ ςοΫϦʔυ ZOZOTOWN iOS ͹Μ͡ΎΜ🍓 /

    @banjun 2 -PWF-JWFS NBD04 $SFBUF-JWF1IPUPTGSPN.PWJFT 'MJDL4,, J04 +BQBOFTF$VTUPN,FZCPBSE&YUFOTJPO ݸਓϓϩδΣΫτɾ1PEDBTU ͖ͷ͜ΔΤϑΤϜX!USFCZ͖ͷ͜Δ
  3. © ZOZO Technologies, Inc. https://zozo.jp/ • ೔ຊ࠷େڃͷϑΝογϣϯ௨ൢαΠτ • 1,400Ҏ্ͷγϣοϓɺ8,200Ҏ্ͷϒϥϯυͷऔΓѻ͍ʢͱ΋ʹ 2021೥3݄຤࣌఺ʣ

    • ৗ࣌83ສ఺Ҏ্ͷ঎඼ΞΠςϜ਺ͱຖ೔ฏۉ2,900఺Ҏ্ͷ৽ண ঎඼Λܝࡌ • ίεϝઐ໳ϞʔϧʮZOZOCOSMEʯ΍ۺͷઐ໳Ϟʔϧ ʮZOZOSHOESʯɺϥάδϡΞϦʔˍσβΠφʔζκʔϯ ʮZOZOVILLAʯΛల։ • ଈ೔഑ૹαʔϏε • ΪϑτϥοϐϯάαʔϏε • πέ෷͍ ͳͲ 3
  4. © ZOZO Technologies, Inc. 4

  5. © ZOZO Technologies, Inc. 5 ͸͡Ίʹ

  6. © ZOZO Technologies, Inc. 6 ະ஌ͷϑΝΠϧܗࣜΛ ʰApple Watchͷจࣈ൫ϑΝΠϧʱ ⌚ 


    CodableͰಡΈॻ͖͢Δͷʹ໾ཱͭςΫχοΫ ࠓճͷ͓͸ͳ͠
  7. © ZOZO Technologies, Inc. 7 ʰApple Watchͷจࣈ൫ϑΝΠϧʱ ⌚ ະ஌ͷϑΝΠϧܗࣜΛ 


    CodableͰ ख๏ɾ࣮૷ɾςΫχοΫ ର৅ (ղੳର৅) ۩ମࣄྫ ࠓճͷ͓͸ͳ͠
  8. © ZOZO Technologies, Inc. 8 ◆ Codableͱ͸ʁʰApple Watchͷจࣈ൫ʱͱ͸ʁ ◆ ͳͥͦΕΛղੳ͢Δͷ͔ʁ

    ◆ ݁Ռͳʹ͕Ͱ͖͔ͨʁ ... banjun/WatchFaceDumper ◆ Ͳ͏΍ͬͨͷ͔ʁ ◆ CodableΛͲ͏࢖͏ͱྑ͔͔ͬͨʁ ࣄྫͱରॲ ࠓճͷ͓͸ͳ͠
  9. © ZOZO Technologies, Inc. 9 Codable

  10. © ZOZO Technologies, Inc. 10 Codable - Έͳ͞Μ͝ଘ஌ͷΞϨɾɾɾͰ͕͢ ✅ API௨৴ͰJSONΛѻ͏ͷ͕ఆ൪ͷ࢖ΘΕ͔ͨɻએݴతͰಡΈ΍͍͢ɻ

    📝 Swiftͷ֎ͷੈքͷදݱܗࣜΛSwiftͰදݱ͢Δܕ ❗ API௨৴ͷࣗಈੜ੒ͳΒͱ΋͔͘ ͦΕҎ֎ͷ࢖͍ํͰ͸ɼର৅ͷղੳɾཧղ͕ඞཁෆՄܽ
  11. © ZOZO Technologies, Inc. 11 Codable - Έͳ͞Μ͝ଘ஌ͷΞϨɾɾɾͰ͕͢ ղੳ (࠶ܝ)

  12. © ZOZO Technologies, Inc. 12 Apple Watchͷจࣈ൫

  13. © ZOZO Technologies, Inc. 13 Apple Watchͷจࣈ൫ ⌚ ࣌ࠁΛදࣔ͢Δجຊతͳը໘ͷ͜ͱ ⚙

    ͍ΖΜͳछྨ͕͋Δ͏͑ʹΧελϜͰ͖Δ 🙋 Έͳ͞Μ͸ͲΜͳจࣈ൫Λ࢖͍ͬͯ·͔͢ʁ 
 WWDC21ʹΑΕ͹ࣸਅจࣈ൫͕ਓؾΒ͍͠
  14. © ZOZO Technologies, Inc. 14 จࣈ൫ Λ۷ΓԼ͛Α͏

  15. © ZOZO Technologies, Inc. 15 จࣈ൫͸࡞ΕΔʁ࡞Εͳ͍ʁ Developerͱͯ͠ؾʹͳΔ͜ͱ watchOSΞϓϦͱ͸ҧ͍ɼจࣈ൫ͦͷ΋ͷΛΞϓϦͷΑ͏ ʹ࡞Δ͜ͱ͸Ͱ͖ͳ͍ Ϣʔβʔ͕Ͱ͖Δ͜ͱ

    ϏϧτΠϯͷจࣈ൫ͷΧελϜઃఆ ΞϓϦ͕ఏڙ͢Δύʔπ(Complications)ͷ഑ஔ ࢓૊Έ͸͚ͬ͜͏ൿີײ͕͋Δ https://developer.apple.com/design/human-interface-guidelines/watchos/overview/complications/
  16. © ZOZO Technologies, Inc. 16 ʰจࣈ൫ϑΝΠϧʱ͸ଘࡏ͢Δ watchOS 7͔Β͸ଞͷਓͱจࣈ൫Λ ڞ༗Ͱ͖ΔΑ͏ʹͳͬͨ ͭ·Γɼจࣈ൫ϑΝΠϧ͕σόΠεΛ

    ཭Εͯଘࡏ͢Δ͸ͣ https://www.apple.com/jp/watchos/watchos-7/
  17. © ZOZO Technologies, Inc. 17 ʰจࣈ൫ϑΝΠϧʱ͸ଘࡏ͢Δ

  18. © ZOZO Technologies, Inc. 18 ͳͥจࣈ൫Λ 
 ղੳ͢Δͷ͔

  19. © ZOZO Technologies, Inc. 19 ͳͥจࣈ൫Λղੳ͢Δͷ͔ ◆໾ʹཱͭ (࣮ར) ϥΠϒϑΥτ࠶ੜ৚݅ͷ࣮ݧ͕ḿΔྫ ◆৽نੑʂͩΕ΋΍ͬͯͳ͍ʂ

    githubͷapple watchface repoݕࡧௐ΂ ◆ָ͍͠ʂղੳͨͷ͍͠ʂ Ԡ༻ࣄྫ͸noteʹ͋ΔΑ
  20. © ZOZO Technologies, Inc. 20 จࣈ൫ ߏ଄ཧղ ͱ͸͍͑…

  21. © ZOZO Technologies, Inc. 21 ͋·Γʹ΋ 
 ׳Ε͍ͯͳͯ͘෼͔ΓͮΒ͍ର৅ ͩͱࢥ͏ͷͰ

  22. © ZOZO Technologies, Inc. 22 ͩΜͩΜղੳ͍ͯ͘͠ ͱ͍͏ΑΓ͸ ౴͑ͷ෼͔͍ͬͯΔେ࿮͔Β 
 આ໌͠·͢

  23. © ZOZO Technologies, Inc. 23 จࣈ൫ϑΝΠϧ(.watchface)֓ཁ iPhone͔ΒAirDropͰऔΓग़ͨ͠จࣈ ൫͸zip͞Ε͍ͯΔͷͰ·ͣunzipͯ͠ த਎ΛΈΔ unzip

  24. © ZOZO Technologies, Inc. 24 จࣈ൫ϑΝΠϧ(.watchface)֓ཁ ϑΥϧμߏ଄(υΩϡϝϯτύοέʔδ) ෳ਺ͷjson, plist, Ϧιʔε(png,

    jpg, mov)ΛؚΉ ࠶zip͢Ε͹iPhoneʹૹΓฦͤΔ
  25. © ZOZO Technologies, Inc. 25 จࣈ൫ϑΝΠϧ(.watchface)֓ཁ complicationData … ίϯϓϦέʔγϣϯͰ࢖͏Ϧιʔε face.json

    … จࣈ൫ͷछྨɾΧελϜઃఆ஋ metadata.json … ίϯϓϦέʔγϣϯͷ໊લ΍Ґஔ Resources … ը૾ɾಈըϑΝΠϧ Resources/Images.plist … ͦͷը૾ɾಈըͷϝλσʔλ
  26. © ZOZO Technologies, Inc. jsonͱplist … ͦΕͧΕCodableͰಡΈॻ͖ ϑΥϧμߏ଄ͱ͔ͦͷதͷϑΝΠϧ … ↑ͷ

    Codableʹ߹ΘͤͯಡΈॻ͖ ͦΕҎ֎ͷݻఆͷϑΝΠϧ … ୯ʹಡΈॻ͖ 26 ղੳͯ͠CodableͰ࣮૷͍ͨ͠
  27. © ZOZO Technologies, Inc. 27 ղੳͯ͠CodableͰ࣮૷͍ͨ͠… jsonͱplist … ͦΕͧΕCodableͰಡΈॻ͖ ϑΥϧμߏ଄ͱ͔ͦͷதͷϑΝΠϧ

    … ↑ͷ Codableʹ߹ΘͤͯಡΈॻ͖ ͦΕҎ֎ͷݻఆͷϑΝΠϧ … ୯ʹಡΈॻ͖ struct Watchface: Codable
  28. © ZOZO Technologies, Inc. 28 ղੳͯ͠CodableͰ࣮૷͍ͨ͠…ͦ͏͍͑͹CfP… jsonͱplist … ͦΕͧΕCodableͰಡΈॻ͖ ϑΥϧμߏ଄ͱ͔ͦͷதͷϑΝΠϧ

    … ↑ͷ Codableʹ߹ΘͤͯಡΈॻ͖ ͦΕҎ֎ͷݻఆͷϑΝΠϧ … ୯ʹಡΈॻ͖ struct Watchface: Codable CfPͰ͸͜ͷCodableΛ͢Δͱॻ͍͍ͯΔͷ͕ͩ
  29. © ZOZO Technologies, Inc. 29 ղੳͯ͠CodableͰ࣮૷͍ͨ͠… jsonͱplist … ͦΕͧΕCodableͰಡΈॻ͖ ϑΥϧμߏ଄ͱ͔ͦͷதͷϑΝΠϧ

    … ↑ͷ Codableʹ߹ΘͤͯಡΈॻ͖ ͦΕҎ֎ͷݻఆͷϑΝΠϧ … ୯ʹಡΈॻ͖ struct Watchface: Codable CfPͰ͸͜ͷCodableΛ͢Δͱॻ͍͍ͯΔͷ͕ͩ ʰ1ݸͷCodableʱ͸΍Ίͯɼ͜ͷ໾ׂ͸ผʹಀ͕͠·͢🙇
  30. © ZOZO Technologies, Inc. 30 ղੳͯ͠Codable + NSFileWrapperͰ࣮૷ jsonͱplist …

    ͦΕͧΕCodableͰಡΈॻ͖ ϑΥϧμߏ଄ͱ͔ͦͷதͷϑΝΠϧ … ↑ͷ Codableʹ߹Θͤͯอ࣋ ͦΕҎ֎ͷݻఆͷϑΝΠϧ … ୯ʹอ࣋ struct Watchface NSFileWrapper υΩϡϝϯτ ύοέʔδ Ϛοϐϯά https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/DocumentPackages/DocumentPackages.html init(…) init(…)
  31. © ZOZO Technologies, Inc. 31 ղੳͯ͠Codable + NSFileWrapperͰ࣮૷ jsonͱplist …

    ͦΕͧΕCodableͰಡΈॻ͖ ϑΥϧμߏ଄ͱ͔ͦͷதͷϑΝΠϧ … ↑ͷ Codableʹ߹Θͤͯอ࣋ ͦΕҎ֎ͷݻఆͷϑΝΠϧ … ୯ʹอ࣋ struct Watchface NSFileWrapper Ϛοϐϯά zip/unzip υΩϡϝϯτ ύοέʔδ
  32. © ZOZO Technologies, Inc. 32 ৄࡉߏ଄͸ৄ͘͠͸ղઆ͠·ͤΜ͕ ͦΕ΄ͲෳࡶͰ͸ͳ͍ͱ͍͏ ײ֮Λ͔ͭΜͰ΄͍͠ͷͰ ͬ͟ͱݟ͍͖ͯ·͢ (6ϖʔδ)

  33. © ZOZO Technologies, Inc. 33 τοϓϨϕϧ struct Watchface struct Watchface

    { var face: Face var metadata: Metadata var snapshot: Data var no_borders_snapshot: Data var resources: Resources? typealias ComplicationData 
 = Metadata.ComplicationPositionDictionary<[String: Data]> var complicationData: ComplicationData? = nil } ✅ FileWrapper͕͋ΔલఏͩͱɼDataͱCodable structΛϑΥϧμߏ଄Ͳ͓Γฒ΂Δ͚ͩ
  34. © ZOZO Technologies, Inc. 34 Watchface.Face extension Watchface { struct

    Face: Codable { var version: Int = 4 var face_type: FaceType var resource_directory: Bool? = true var customization: Customization var complications: Complications? } } ✅ face.jsonʹ͸ɼจࣈ൫ͷ छྨ͕͋Δ ࣸਅɾສ՚ڸɾΠϯϑΥά ϥϑͳͲ ৽͍͠จࣈ൫Λղੳ͢Δͱ ௥Ճ͢Δ͜ͱʹͳΔ ✅ ίϯϓϦέʔγϣϯͷ UserActivity͕͋Δͱ͖͸͜ ͜ʹೖΔ enum FaceType: String, Codable { /// has [top, bottom] case photos /// has [top-left, top-right, bottom-center] case kaleidoscope /// aka infograph case whistler_analog = "whistler-analog" }
  35. © ZOZO Technologies, Inc. 35 Watchface.Metadata struct Metadata: Codable {

    var version: Int = 2 var device_size = 2 // 38mm, 42mm? var complication_sample_templates: ComplicationPositionDictionary<ComplicationTemplate> var complications_names: ComplicationPositionDictionary<String> var complications_item_ids: ComplicationPositionDictionary<Int> var complications_bundle_ids: ComplicationPositionDictionary<String>? } ✅ metadata.jsonʹ͸ίϯϓϦέʔγϣϯ͕͋ΔɻͦͷBundle ID͸com.apple.HeartRate ͳͲ͕ೖΔ {"top": … , "bottom-left": …} ͳͲɼ഑ஔ͢ΔҐஔΛΩʔͱͯ͠هड़͞Ε͍ͯΔ
  36. © ZOZO Technologies, Inc. 36 Watchface.Metadata.ComplicationTemplate enum ComplicationTemplate: Codable {

    case utilitarianSmallFlat(CLKComplicationTemplateUtilitarianSmallFlat) case utilitarianLargeFlat(CLKComplicationTemplateUtilitarianLargeFlat) case circularSmallSimpleText(CLKComplicationTemplateCircularSmallSimpleText) : ✅ ίϯϓϦέʔγϣϯʹ͸͞·͟·ͳλΠϓ͕͋ΓҰ࿈ͷΫϥεͰදݱ͞Ε͍ͯΔ ໨ʹݟ͑Δ෦෼ͷछྨ͸ɼςΩετɾΠϝʔδɾήʔδͷproviderͱͯ͠ग़ݱ͢Δ struct CLKComplicationTemplateUtilitarianSmallFlat: Codable { static let `class` = "CLKComplicationTemplateUtilitarianSmallFlat" var `class`: String = Self.class var version: Int = 30000 var creationDate: Double = Date().timeIntervalSince1970 var textProvider: CLKTextProvider = .date(.init()) }
  37. © ZOZO Technologies, Inc. 37 Watchface.Metadata.CLKTextProvider enum CLKTextProvider: Codable {

    case simple(CLKSimpleTextProvider) case date(CLKDateTextProvider) case time(CLKTimeTextProvider) case compound(CLKCompoundTextProvider) case relativeDate(CLKRelativeDateTextProvider) } ✅ ςΩετͷදࣔʹ΋छྨ͕͋ͬͯɼγϯϓϧͳςΩετࢦఆͷ΄͔ɾ೔෇ɾ࣌ؒΛ࣋ ͭ΋ͷ΍ɼͦΕΒΛෳ߹ͯ͠υοτܨ͗͢ΔͳͲͷϑΥʔϚοτ͕Ͱ͖ΔΑ͏Ͱ͢
  38. © ZOZO Technologies, Inc. 38 Watchface.Resources struct Resources { var

    images: Metadata var files: [String: Data] // filename -> content } ✅ Resources͸ϑΥϧμߏ଄ɻResources.Metadata.Item͕ը૾ϑΝΠϧ͝ͱͷϝλσʔ λɻϝλσʔλʹ͸ΫϩοϓɾΤϑΣΫτɾϥΠϒϑΥτͷ࠶ੜҐஔؚ͕·Ε͍ͯΔɻ f ilesͰͷϑΝΠϧͷϚοϐϯάʹ͸FileWrapperΛ࢖͏ (ʮϦιʔεϑΝΠϧࢀরʯͰޙड़) struct Metadata: Codable { var imageList: [Item] var version: Int = 1 }
  39. © ZOZO Technologies, Inc. 39 Ͷʁ ͜Ε͕ެࣜAPIͰఏڙ͞ΕͯͨΒ ؆୯ͦ͏ʹݟ͑Δ͘Β͍ Ͱ͠ΐ͏ʁ

  40. © ZOZO Technologies, Inc. 40 ղੳͯ͠structʹ࣮૷͍ͯ͘͠ ͷ΋Α͍͕ ΋͏ͻͱͭ ΍ͬͨ΄͏͕ྑ͍͜ͱ͕͋Δ

  41. © ZOZO Technologies, Inc. 41 MacΞϓϦͰ 
 ViewerΛͭ͘Δ

  42. © ZOZO Technologies, Inc. 42 ղੳ࡞ۀͷޮ཰Խͱه࿥ ⌚ 📱 unzip zip

    Θͨ͠
  43. © ZOZO Technologies, Inc. 43 ղੳ࡞ۀͷޮ཰Խͱه࿥ ⌚ 📱 unzip zip

    Θͨ͠
  44. © ZOZO Technologies, Inc. 44 ղੳ࡞ۀͷޮ཰Խͱه࿥ ⌚ 📱 unzip zip

    Θͨ͠ ղੳͯ͠ಡΈॻ͖
  45. © ZOZO Technologies, Inc. 45 ղੳ࡞ۀͷޮ཰Խͱه࿥ ⌚ 📱 unzip zip

    Θͨ͠ ֬ೝ ղੳͯ͠ಡΈॻ͖ ⚠Τϥʔग़ͯΔʂ ϊ΢ϋ΢
 ϝϞ ίʔυ
 ɾ ΞϓϦ
  46. © ZOZO Technologies, Inc. 46 MacΞϓϦ WatchFaceDumper.app ·ͩجຊతʹViewer watchfaceϑΝΠϧΛಡΈࠐΜͰද ࣔ͢Δ͜ͱͰɼCodableͷσίʔυ

    ࣮૷͕ਖ਼͍͜͠ͱ͕෼͔Δ ը૾Ϧιʔε෦෼͸EditͰ͖Δ ϥΠϒϑΥτ࡞੒ʹ΋ରԠ
  47. © ZOZO Technologies, Inc. 47 MacΞϓϦ WatchFaceDumper.app

  48. © ZOZO Technologies, Inc. 48 MacΞϓϦ WatchFaceDumper.app

  49. © ZOZO Technologies, Inc. 49 MacΞϓϦ WatchFaceDumper.app MacΞϓϦ͔ΒAirDropͰ௚઀iOSʹૹ৴ͯ֬͠ೝ (Watch SimulatorͰ͸ಈ͔ͳ͍)

  50. © ZOZO Technologies, Inc. 50 Document-BasedΞϓϦ Document-BasedͰॻ͍͓ͯ ͘ͱ෼͔Γ΍͍͢ NewɾOpenɾSaveɾ ResumeͳͲMacͷࣗવͳ

    ػೳʹରԠ͠΍͍͢ NSDocumentʹWatchfaceΛ ࣋ͨͤɼ1΢Πϯυ΢ 1watchfaceʹ͢Δ
  51. © ZOZO Technologies, Inc. 51 Document-BasedΞϓϦ jsonͱplist … ͦΕͧΕCodableͰಡΈॻ͖ ϑΥϧμߏ଄ͱ͔ͦͷதͷϑΝΠϧ

    … ↑ͷ Codableʹ߹Θͤͯอ࣋ ͦΕҎ֎ͷݻఆͷϑΝΠϧ … ୯ʹอ࣋ struct Watchface NSFileWrapper Ϛοϐϯά zip/unzip υΩϡϝϯτ ύοέʔδ
  52. © ZOZO Technologies, Inc. 52 Document-BasedΞϓϦ jsonͱplist … ͦΕͧΕCodableͰಡΈॻ͖ ϑΥϧμߏ଄ͱ͔ͦͷதͷϑΝΠϧ

    … ↑ͷ Codableʹ߹Θͤͯอ࣋ ͦΕҎ֎ͷݻఆͷϑΝΠϧ … ୯ʹอ࣋ struct Watchface NSFileWrapper Ϛοϐϯά zip/unzip υΩϡϝϯτ ύοέʔδ NSDocument ViewController WindowController App
  53. © ZOZO Technologies, Inc. 53 MacΞϓϦ͕͋ΔղੳαΠΫϧ ViewerΛ௨ͯ͠ݟΔ App struct Watchface

    ɾɾɾɾɾɾ unzip ղੳͨ͠಺༰Λ࣮૷௥Ճ͢Δ ະ஌ͷܗࣜΛղੳ͢Δ Θͨ͠
  54. © ZOZO Technologies, Inc. 54 ͜ͷΑ͏ʹͯ͠ ࣸਅจࣈ൫ ͱ ΠϯϑΥάϥϑจࣈ൫ ͷجຊߏ଄Λղੳͨ͠

  55. © ZOZO Technologies, Inc. 55 Apple Watchʹ͸ଟ࠼ͳจࣈ൫͕༻ҙ ͞Ε͓ͯΓɺͦͷ΄ͱΜͲ͸ΧελϚΠζͰ͖·͢ 
 —

    Apple WatchϢʔβΨΠυ https://support.apple.com/ja-jp/guide/watch/apde9218b440/watchos
  56. © ZOZO Technologies, Inc. 56 ͋ͱ40छྨ͔ͳ… 
 — ͹Μ͡ΎΜ

  57. © ZOZO Technologies, Inc. 57 CodableΛͲ͏࢖͏ͱྑ͔͔ͬͨʁ ࣄྫͱରॲ

  58. © ZOZO Technologies, Inc. 58 ʮ;ͭ͏ͷCodableʯ͡Όͳ͍watchface 😈 JSONΩʔ໊(Ξϯεί۠੾ΓɾϋΠϑϯ۠੾Γɾεϖʔε۠੾Γ) 😈 `class`໊Ͱߏ଄෼ذ

    😈 ϦιʔεϑΝΠϧࢀর 😈 ͙ۙ͘͢ʹ͋Δ1970λΠϜελϯϓͱ2001λΠϜελϯϓ 😈 JSONʹNSKeyedArchiver 😈 ࣗ༝ܗࣜʹΈ͑Δ͕[String: V]΄Ͳࣗ༝Ͱ΋ͳ͍ࣙॻ
  59. © ZOZO Technologies, Inc. 59 JSONΩʔ໊ (Ξϯεί۠੾ΓɾϋΠϑϯ۠੾Γɾεϖʔε۠੾Γ) 😈 watchfaceʹొ৔͢Δ୯ޠ۠੾Γܗࣜ͸͞·͟· "face

    type": "whistler-analog", "complications": { "slot 1": { "slot1": { "creationDate": 1601048354 "imageProvider": { "bezel": "ΧϨϯμʔ", "top-left": "ఱؾ", "top-right": "৺ഥ਺", "device_size": 2, "complications_bundle_ids": { camelCase Ξϯεί۠੾Γ ϋΠϑϯ۠੾Γ εϖʔε۠੾Γ
  60. © ZOZO Technologies, Inc. 60 JSONΩʔ໊ (Ξϯεί۠੾ΓɾϋΠϑϯ۠੾Γɾεϖʔε۠੾Γ) ✅ ݸผʹCodingKeysͰखͰࢦఆ͍ͯ͘͠ͷ͕࣮͔֬ͭ୯७ private

    enum CodingKeys: String, CodingKey { case version case customization case complications case face_type = "face type" case resource_directory = "resource directory" } "face type": "whistler-analog", "complications": { "slot 1": {
  61. © ZOZO Technologies, Inc. 61 `class`໊Ͱߏ଄෼ذ 😈 OpenAPIͰ͍͏ͱ͜ΖͷoneOfΈ͍ͨͳߏ଄͕ͩɼͦͷ෼ذ͸த਎ͷ`class`Ωʔͷ஋ ʹΑͬͯߦͳΘΕΔ API࢓༷Ͱ΋ͨ·ʹݟ͔͚Δ

    … Έͳ͞Μ͸Ͳ͏ͯ͠·͔͢ʁ "textProvider": { "date": 496285770, "class": "CLKDateTextProvider", "_uppercase": true, "calendarUnits": 528 }, "textProvider": { "class": "CLKSimpleTextProvider", "text": "ϤΨ" }, ೔෇ΛϑΥʔϚοτͯ͠දࣔ จࣈྻͦͷ··දࣔ
  62. © ZOZO Technologies, Inc. 62 `class`໊Ͱߏ଄෼ذ enum CLKTextProvider: Codable {

    case date(CLKDateTextProvider) case time(CLKTimeTextProvider) case compound(CLKCompoundTextProvider) case simple(CLKSimpleTextProvider) case relativeDate(CLKRelativeDateTextProvider) init(from decoder: Decoder) throws { let anyProvider = try CLKTextProviderAny(from: decoder) switch anyProvider.class { case CLKDateTextProvider.class: self = .date(try .init(from: decoder)) case CLKTimeTextProvider.class: self = .time(try .init(from: decoder)) : default: DecodingError.dataCorrupted(…) } } private struct CLKTextProviderAny: Codable { var `class`: String } ✅ ڞ௨ߏ଄ͷ͋ΔoneOf…ͱ͍͏͜ͱͰڞ௨ͷAnyͰ`class`ΛઌಡΈͯ͠෼ذ ະ஌ύλʔϯ͕ग़ͯ΋ػցతʹ(޻෉ͳ͘࡞ۀతʹ)௥ՃͰ͖Δͱخ͍͠ʂ
  63. © ZOZO Technologies, Inc. 63 ϦιʔεϑΝΠϧࢀর 😈 plistʹϑΝΠϧ໊͚ͩॻ͔Ε͍࣮ͯͯσʔλ͸plistͷྡʹ͋Δύλʔϯ ෼͔Γ΍͍͢͠ฤू͠΍͍͢ͱ΋͍͑Δͷ͕ͩ…

  64. © ZOZO Technologies, Inc. 64 ϦιʔεϑΝΠϧࢀর ✅ ϑΥϧμ֊૚ΛstructͰڬΜͰ͓͘ɻ͜͜Ͱ͸ϑΥϧμ໊͕ResourcesͳͷͰͦͷ··࠾༻ Codableର৅ϑΝΠϧ͸Codableɼ୯ͳΔϦιʔε͸ϑΝΠϧ໊ͱίϯςϯπͷࣙॻͰ࣋ͭ 🤷

    Codable͚ͩͰॲཧ͢ΔͱෳࡶʹͳΓͦ͏… extension Watchface { struct Resources { var images: Metadata var files: [String: Data] struct Metadata: Codable { var imageList: [Item] plistͷCodable images.plist [ϑΝΠϧ໊: ίϯςϯπ] mapValues {FileWrapper(regularFileWithContents: $0)} NSFileWrapperʹ
 ܨ͗΍͘͢
  65. © ZOZO Technologies, Inc. 65 1970λΠϜελϯϓͱ2001λΠϜελϯϓ 😈 ೋͭͷdateλΠϜελϯϓ͸ى఺͕ҟͳΔ ͓෼͔Γ͍͚ͨͩͨͩΖ͏͔… "complication_sample_templates":

    { "top": { "creationDate": 1623277757.787668, "textProvider": { "date": 496285770, "class": "CLKDateTextProvider", "_uppercase": true, "calendarUnits": 528 }, "class": "CLKComplicationTemplateUtilitarianSmallFlat", "version": 30000 } }, λΠϜελϯϓ ͜Ε΋λΠϜελϯϓ
  66. © ZOZO Technologies, Inc. 66 1970λΠϜελϯϓͱ2001λΠϜελϯϓ 📝 NSDateͷى఺͸ೋछྨ UNIXతͳ1970೥ͷଞʹɼreference dateͱ͍͏2001೥͕͋Δ

    Core DataͰ͸2001೥ى఺ͷอଘ͕ߦͳΘΕ͍ͯΔͷͰݟ͔͚ͨਓ΋͍Δ͸ͣ CodableσϑΥϧτͰ਺஋ΛNSDateʹ͢Δͱ͖͸2001೥ى఺
  67. © ZOZO Technologies, Inc. 67 1970λΠϜελϯϓͱ2001λΠϜελϯϓ ✅ ଞʹܾΊख͕ͳ͍ͱ͖͸CodableσϑΥϧτΛ࠾༻ 1970೥ͷ΄͏͸Doubleͱ͠Codable૚ͷม׵ͳ͠ͱ͢Δ ΑΓ໌ࣔతʹ͚ͨ͠Ε͹ɼ1970೥ͷΠϯλʔϑΣʔε͔࣋ͨ͠ͳ͍ઐ༻ͷܕΛஔ͘

    struct CLKComplicationTemplateUtilitarianSmallFlat: Codable { : var creationDate: Double = Date().timeIntervalSince1970 var textProvider: CLKTextProvider = .date(.init()) } struct CLKDateTextProvider: Codable { : var date: Date = .init() : } ͬͪ͜͸1970೥ ͬͪ͜͸2001೥
  68. © ZOZO Technologies, Inc. 68 JSONʹNSKeyedArchiver 😈 NSKeyedArchiverͰarchiveͯ͠base64EncodedStringͨ͠΋ͷ͕ೖͬ ͍ͯΔέʔε΋ɻ࠷৽൛Ͱ͸ݮ͕ͬͨUAUserActivity(ະղੳ)͕͋Γͦ͏ɻ "complication_sample_templates":

    { "top": "YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9ia mVj\r\ndHM... bplist00... Base64Ͱσίʔυ ͭ·Γplist
  69. © ZOZO Technologies, Inc. 69 JSONʹNSKeyedArchiver ✅ ಉ໊ͷobjcΫϥεΛ࡞ͬͯ NSCodingͰಡΉ ✅

    Ϋϥε໊΍Ωʔ໊͸plistΛ ಡΈղ͘ @objc(CLKComplicationTemplate) class CLKComplicationTemplate: NSObject, NSCoding { override init() {super.init()} required init?(coder: NSCoder) {} func encode(with coder: NSCoder) {} } @objc(CLKComplicationTemplateUtilitarianSmallFlat) final class CLKComplicationTemplateUtilitarianSmallFlat: CLKComplicationTemplate { : var textProvider: CLKTextProvider? = .init() : override init() {super.init()} required init?(coder: NSCoder) { : self.textProvider = coder.decodeObject(forKey: "textProvider") as? CLKTextProvider super.init(coder: coder) } override func encode(with coder: NSCoder) { :
  70. © ZOZO Technologies, Inc. 70 ࣗ༝ܗࣜʹΈ͑Δ͕[String: V]΄Ͳࣗ༝Ͱ΋ͳ͍ࣙॻ "complications_names": { "slot3":

    "ఱؾ", "bottom-right": "ΞΫςΟϏςΟ", "slot2": "Ξετϩϊϛʔ", "bezel": "ΧϨϯμʔ", "top-left": "ఱؾ", "top-right": "৺ഥ਺", "bottom-left": "ϛϡʔδοΫ" }, 😈 ίϯϓϦέʔγϣϯͷҐஔʹ͸ݻ༗ͷ໊લ͕෇͍͍ͯΔΑ͏͕ͩɼࣗ༝ͳײ͕͋͡ Δɻจࣈ൫ͷछྨ͕มΘΔͱ৽͍͠Ωʔ΋ݟ͔ͭΔ͔΋ʁ
  71. © ZOZO Technologies, Inc. 71 ࣗ༝ܗࣜʹΈ͑Δ͕[String: V]΄Ͳࣗ༝Ͱ΋ͳ͍ࣙॻ 🚫 String enumΛΩʔͱ͢Δࣙॻ͸CodableͰύʔεෆՄ

    https://bugs.swift.org/browse/SR-7788 ͱͯ͠ط஌ͷ੍໿ struct Metadata: Codable { var complications_names: [Position: String] enum Position: String, Codable { case top, bottom, top_left, top_right case slot1, slot2, slot3 } } try JSONDecoder().decode(Metadata.self, from: "{\"complications_names\": {\"top\": \"τοϓ\"}}".data(using: .utf8)!) 💥 "Expected to decode Array<Any> but found a dictionary instead." ࣙॻͷΩʔΛenumʹ͕ͨ͠…?
  72. © ZOZO Technologies, Inc. 72 ࣗ༝ܗࣜʹΈ͑Δ͕[String: V]΄Ͳࣗ༝Ͱ΋ͳ͍ࣙॻ ✅ ۪௚ʹɼϝϯόͷܕ͕શ෦ಉ͡structΛ࡞Δ 👍

    WatchFaceDumperͰ͸ɼ͞ΒʹGenericsʹ͍ͯ͠Δ struct ComplicationPositionDictionary<Value: Codable>: Codable struct Metadata: Codable { var complications_names: Position struct Position: Codable { var top: String? var bottom: String? var top_left: String? var top_right: String? var slot1: String? var slot2: String? var slot3: String? } } 💡 CodableͰ্ख͍͔͘ͳ͍ͱ͖͸1ஈ্ ͷ֊૚ΛΈΔͱղܾͰ͖Δ͔΋ ࣙॻͷΩʔͰ͸ͳࣙ͘ॻͦͷ΋ͷ 💡 ͦ΋ͦ΋ࣙॻ͸શϝϯόͷܕ͕ಉ͡Ͱ Optionalʹͳ͍ͬͯΔstructͱྨࣅͷߏ଄
  73. © ZOZO Technologies, Inc. 73 .watchface 
 Codable + FileWrapper

    
 ϥΠϒϥϦ
  74. © ZOZO Technologies, Inc. 74 watchfaceͷCodableϥΠϒϥϦ banjun/WatchFaceDumperͷCodableͱFileWrapperͷ෦෼͸ϥΠϒϥϦʹͨ͠ 🍫 pod "WatchFace"

    structΛϥΠϒϥϦʹ͢Δͱ͖ɼpublic memberwise init͕ཉ͍͠ ⚗ ͜ͷinit͸ra1028/swift-modͰίʔυੜ੒ σϑΥϧτ஋෇͚͓ͯ͘ͱݺͼଆ͔Βଟগ࢖͍΍͍͢ ΄Μͱ͸structͱ͸ผϑΝΠϧͷ΄͏͕ಡΈ΍͍͔͢΋…
  75. © ZOZO Technologies, Inc. 75 ͓ΘΓʹ

  76. © ZOZO Technologies, Inc. 76 ͓ΘΓʹ 🥳 ະ஌ϑΝΠϧΛղੳָ͍ͯ͜͠͠ͱΛ͠·͠ΐ͏ 📝 ղੳͨ͜͠ͱΛ࣮૷ͱͯ͠ه࿥͓ͯ͘͠ͷʹCodable͕΂ΜΓ

    Ͱ͢ɻςΫ͸ࢥΘ͵ͱ͜ΖͰ໾ʹཱ͔ͭ΋ʁ ⌚ ʰApple Watchͷจࣈ൫ϑΝΠϧʱ͕ͲΜͳܗ͔ࣜ஌͍ͬͯ ΔϨΞͳਓʹͳΕ·ͨ͠Ͷʂ 🌈 banjun/WatchFaceDumper͕ະղੳͷจࣈ൫λΠϓ͕ͨ͘͞ Μ͋Γ·͢ɻղੳ݁ՌΛఏڙͯ͘͠ΕͨΒ͏Ε͍͠Ͱ͢ʂ ശೣϚοΫε͘Μ / ZOZO
  77. 77