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 -

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

ばんじゅん🍓

September 18, 2021
Tweet

More Decks by ばんじゅん🍓

Other Decks in Programming

Transcript

  1. © ZOZO Technologies, Inc. גࣜձࣾZOZOςΫϊϩδʔζ ςοΫϦʔυ ZOZOTOWN iOS ͹Μ͡ΎΜ🍓 /

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

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


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


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

    ◆ ݁Ռͳʹ͕Ͱ͖͔ͨʁ ... banjun/WatchFaceDumper ◆ Ͳ͏΍ͬͨͷ͔ʁ ◆ CodableΛͲ͏࢖͏ͱྑ͔͔ͬͨʁ ࣄྫͱରॲ ࠓճͷ͓͸ͳ͠
  6. © ZOZO Technologies, Inc. 10 Codable - Έͳ͞Μ͝ଘ஌ͷΞϨɾɾɾͰ͕͢ ✅ API௨৴ͰJSONΛѻ͏ͷ͕ఆ൪ͷ࢖ΘΕ͔ͨɻએݴతͰಡΈ΍͍͢ɻ

    📝 Swiftͷ֎ͷੈքͷදݱܗࣜΛSwiftͰදݱ͢Δܕ ❗ API௨৴ͷࣗಈੜ੒ͳΒͱ΋͔͘ ͦΕҎ֎ͷ࢖͍ํͰ͸ɼର৅ͷղੳɾཧղ͕ඞཁෆՄܽ
  7. © ZOZO Technologies, Inc. 13 Apple Watchͷจࣈ൫ ⌚ ࣌ࠁΛදࣔ͢Δجຊతͳը໘ͷ͜ͱ ⚙

    ͍ΖΜͳछྨ͕͋Δ͏͑ʹΧελϜͰ͖Δ 🙋 Έͳ͞Μ͸ͲΜͳจࣈ൫Λ࢖͍ͬͯ·͔͢ʁ 
 WWDC21ʹΑΕ͹ࣸਅจࣈ൫͕ਓؾΒ͍͠
  8. © ZOZO Technologies, Inc. 15 จࣈ൫͸࡞ΕΔʁ࡞Εͳ͍ʁ Developerͱͯ͠ؾʹͳΔ͜ͱ watchOSΞϓϦͱ͸ҧ͍ɼจࣈ൫ͦͷ΋ͷΛΞϓϦͷΑ͏ ʹ࡞Δ͜ͱ͸Ͱ͖ͳ͍ Ϣʔβʔ͕Ͱ͖Δ͜ͱ

    ϏϧτΠϯͷจࣈ൫ͷΧελϜઃఆ ΞϓϦ͕ఏڙ͢Δύʔπ(Complications)ͷ഑ஔ ࢓૊Έ͸͚ͬ͜͏ൿີײ͕͋Δ https://developer.apple.com/design/human-interface-guidelines/watchos/overview/complications/
  9. © ZOZO Technologies, Inc. 25 จࣈ൫ϑΝΠϧ(.watchface)֓ཁ complicationData … ίϯϓϦέʔγϣϯͰ࢖͏Ϧιʔε face.json

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

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

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

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

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

    ͦΕͧΕCodableͰಡΈॻ͖ ϑΥϧμߏ଄ͱ͔ͦͷதͷϑΝΠϧ … ↑ͷ Codableʹ߹Θͤͯอ࣋ ͦΕҎ֎ͷݻఆͷϑΝΠϧ … ୯ʹอ࣋ struct Watchface NSFileWrapper Ϛοϐϯά zip/unzip υΩϡϝϯτ ύοέʔδ
  16. © 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ΛϑΥϧμߏ଄Ͳ͓Γฒ΂Δ͚ͩ
  17. © 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" }
  18. © 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": …} ͳͲɼ഑ஔ͢ΔҐஔΛΩʔͱͯ͠هड़͞Ε͍ͯΔ
  19. © 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()) }
  20. © 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) } ✅ ςΩετͷදࣔʹ΋छྨ͕͋ͬͯɼγϯϓϧͳςΩετࢦఆͷ΄͔ɾ೔෇ɾ࣌ؒΛ࣋ ͭ΋ͷ΍ɼͦΕΒΛෳ߹ͯ͠υοτܨ͗͢ΔͳͲͷϑΥʔϚοτ͕Ͱ͖ΔΑ͏Ͱ͢
  21. © 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 }
  22. © ZOZO Technologies, Inc. 45 ղੳ࡞ۀͷޮ཰Խͱه࿥ ⌚ 📱 unzip zip

    Θͨ͠ ֬ೝ ղੳͯ͠ಡΈॻ͖ ⚠Τϥʔग़ͯΔʂ ϊ΢ϋ΢
 ϝϞ ίʔυ
 ɾ ΞϓϦ
  23. © ZOZO Technologies, Inc. 51 Document-BasedΞϓϦ jsonͱplist … ͦΕͧΕCodableͰಡΈॻ͖ ϑΥϧμߏ଄ͱ͔ͦͷதͷϑΝΠϧ

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

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

    ɾɾɾɾɾɾ unzip ղੳͨ͠಺༰Λ࣮૷௥Ճ͢Δ ະ஌ͷܗࣜΛղੳ͢Δ Θͨ͠
  26. © ZOZO Technologies, Inc. 55 Apple Watchʹ͸ଟ࠼ͳจࣈ൫͕༻ҙ ͞Ε͓ͯΓɺͦͷ΄ͱΜͲ͸ΧελϚΠζͰ͖·͢ 
 —

    Apple WatchϢʔβΨΠυ https://support.apple.com/ja-jp/guide/watch/apde9218b440/watchos
  27. © ZOZO Technologies, Inc. 58 ʮ;ͭ͏ͷCodableʯ͡Όͳ͍watchface 😈 JSONΩʔ໊(Ξϯεί۠੾ΓɾϋΠϑϯ۠੾Γɾεϖʔε۠੾Γ) 😈 `class`໊Ͱߏ଄෼ذ

    😈 ϦιʔεϑΝΠϧࢀর 😈 ͙ۙ͘͢ʹ͋Δ1970λΠϜελϯϓͱ2001λΠϜελϯϓ 😈 JSONʹNSKeyedArchiver 😈 ࣗ༝ܗࣜʹΈ͑Δ͕[String: V]΄Ͳࣗ༝Ͱ΋ͳ͍ࣙॻ
  28. © 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 Ξϯεί۠੾Γ ϋΠϑϯ۠੾Γ εϖʔε۠੾Γ
  29. © 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": {
  30. © ZOZO Technologies, Inc. 61 `class`໊Ͱߏ଄෼ذ 😈 OpenAPIͰ͍͏ͱ͜ΖͷoneOfΈ͍ͨͳߏ଄͕ͩɼͦͷ෼ذ͸த਎ͷ`class`Ωʔͷ஋ ʹΑͬͯߦͳΘΕΔ API࢓༷Ͱ΋ͨ·ʹݟ͔͚Δ

    … Έͳ͞Μ͸Ͳ͏ͯ͠·͔͢ʁ "textProvider": { "date": 496285770, "class": "CLKDateTextProvider", "_uppercase": true, "calendarUnits": 528 }, "textProvider": { "class": "CLKSimpleTextProvider", "text": "ϤΨ" }, ೔෇ΛϑΥʔϚοτͯ͠දࣔ จࣈྻͦͷ··දࣔ
  31. © 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`ΛઌಡΈͯ͠෼ذ ະ஌ύλʔϯ͕ग़ͯ΋ػցతʹ(޻෉ͳ͘࡞ۀతʹ)௥ՃͰ͖Δͱخ͍͠ʂ
  32. © 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ʹ
 ܨ͗΍͘͢
  33. © 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 } }, λΠϜελϯϓ ͜Ε΋λΠϜελϯϓ
  34. © ZOZO Technologies, Inc. 66 1970λΠϜελϯϓͱ2001λΠϜελϯϓ 📝 NSDateͷى఺͸ೋछྨ UNIXతͳ1970೥ͷଞʹɼreference dateͱ͍͏2001೥͕͋Δ

    Core DataͰ͸2001೥ى఺ͷอଘ͕ߦͳΘΕ͍ͯΔͷͰݟ͔͚ͨਓ΋͍Δ͸ͣ CodableσϑΥϧτͰ਺஋ΛNSDateʹ͢Δͱ͖͸2001೥ى఺
  35. © 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೥
  36. © 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) { :
  37. © ZOZO Technologies, Inc. 70 ࣗ༝ܗࣜʹΈ͑Δ͕[String: V]΄Ͳࣗ༝Ͱ΋ͳ͍ࣙॻ "complications_names": { "slot3":

    "ఱؾ", "bottom-right": "ΞΫςΟϏςΟ", "slot2": "Ξετϩϊϛʔ", "bezel": "ΧϨϯμʔ", "top-left": "ఱؾ", "top-right": "৺ഥ਺", "bottom-left": "ϛϡʔδοΫ" }, 😈 ίϯϓϦέʔγϣϯͷҐஔʹ͸ݻ༗ͷ໊લ͕෇͍͍ͯΔΑ͏͕ͩɼࣗ༝ͳײ͕͋͡ Δɻจࣈ൫ͷछྨ͕มΘΔͱ৽͍͠Ωʔ΋ݟ͔ͭΔ͔΋ʁ
  38. © 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ʹ͕ͨ͠…?
  39. © 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ͱྨࣅͷߏ଄
  40. © ZOZO Technologies, Inc. 74 watchfaceͷCodableϥΠϒϥϦ banjun/WatchFaceDumperͷCodableͱFileWrapperͷ෦෼͸ϥΠϒϥϦʹͨ͠ 🍫 pod "WatchFace"

    structΛϥΠϒϥϦʹ͢Δͱ͖ɼpublic memberwise init͕ཉ͍͠ ⚗ ͜ͷinit͸ra1028/swift-modͰίʔυੜ੒ σϑΥϧτ஋෇͚͓ͯ͘ͱݺͼଆ͔Βଟগ࢖͍΍͍͢ ΄Μͱ͸structͱ͸ผϑΝΠϧͷ΄͏͕ಡΈ΍͍͔͢΋…
  41. © ZOZO Technologies, Inc. 76 ͓ΘΓʹ 🥳 ະ஌ϑΝΠϧΛղੳָ͍ͯ͜͠͠ͱΛ͠·͠ΐ͏ 📝 ղੳͨ͜͠ͱΛ࣮૷ͱͯ͠ه࿥͓ͯ͘͠ͷʹCodable͕΂ΜΓ

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