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

Hacking Xcode Behaviors / macOS native symposium #08

Hacking Xcode Behaviors / macOS native symposium #08

プロジェクトのBuild PhasesにRun Scriptを追加することでターゲットのビルド時に特定の処理を挟み込むことができますが、Xcode Behaviorsはプロジェクト単位ではなくXcode全般でのイベントに処理を挟み込むことができます。そんなBehaviorsをハックして、ビルドやテストのイベントを別アプリから監視する仕組みを実現するまでの試行錯誤について紹介します。

Kyome (Takuto Nakamura)

August 27, 2022
Tweet

More Decks by Kyome (Takuto Nakamura)

Other Decks in Programming

Transcript

  1. Kyome macOS native Symposium #08 2022/08/27 (Sat) Hacking Xcode Behaviors

  2. ࣗݾ঺հ IUUQTLZPNFJP ,ZPNF ,ZPNFTVLF macOS޲͚ͷϢʔςΟϦςΟΞϓϦ։ൃऀʢझຯ݉෭ۀʣ ϝχϡʔόʔৗறܕΞϓϦɺApp Extension ͕ಘҙ෼໺ OSSϓϩδΣΫτӡӦʹνϟϨϯδத

  3. ࣗݾ঺հ RunCat activity indicator HandyPalette color picker ScreenPointer presentation tool

    ShiftWindow window organizer
  4. Xcode Behaviors

  5. Xcode Behaviors Build PhasesͷRun ScriptsͰ͸ TARGETͷϏϧυ࣌ʹShell ScriptͰ ॲཧΛڬΈࠐΉ͜ͱ͕Մೳ Linter΍FormatterΛ࣮ߦͨ͠Γɺ
 Ϧιʔε༻ͷSwiftίʔυΛੜ੒ͨ͠

    ΓɺϏϧυલͷԼॲཧʹར༻Մೳ ϓϩδΣΫτ͝ͱʹݸผʹࢦఆ͢Δ ΋ͷ Run Scripts
  6. Xcode Behaviors Behaviors͸ϓϩδΣΫτ୯ҐͰ͸
 ͳ͘ɺXcodeͰ։͘͢΂ͯͷϓϩ δΣΫτʹରͯ͠ɺ֤छΠϕϯτΛ
 τϦΨʔͱ༷ͨ͠ʑͳઃఆ͕Մೳ RunʹShell ScriptΛొ࿥͢Δ͜ͱ ͰɺΠϕϯτͷ։࢝ɾ੒ޭɾࣦഊɾ ग़ྗͳͲͷλΠϛϯάʹ೚ҙͷॲཧ

    Λ࣮ߦՄೳ Behaviors 😀
  7. Xcode Behaviors ݱঢ়ҎԼͷΠϕϯτΛαϙʔτ #VJME 5FTUJOH 3VOOJOH (16'SBNF$BQUVSF 4FBSDI 9DPEF4FSWFS 9DPEFͰαϙʔτऴྃʁ

     $* 9DPEF$MPVE  'JMF 6OMPDL  1MBZHSPVOET $PSF.- 9DPEF͔Β 
 Behaviors
  8. Xcode Behaviors Swift Package Managerʹؔ͢Δ
 Πϕϯτ͸αϙʔτ͞Ε͍ͯͳ͍
 ͷ͕࢒೦ Reset Package Caches

    Resolve Package Versions Update to Latest Package Versions
 Behaviors 🫤
  9. Xcode Behaviors Behaviors 🤔 Կ͔ʹ࢖͑ͦ͏

  10. XCHook & XCMonitor

  11. XCHook & XCMonitor XCHook͸Xcode BehaviorsͷBuildͱTestingΛϑοΫͯ͠ɺ
 ֎෦ΞϓϦʹ௨஌Λૹ৴Ͱ͖ΔΑ͏ʹ͢ΔSwift Package੡ϥΠϒϥϦ Swift Packageͱͯ͠ར༻Մೳɿhttps://github.com/kyome22/XCHook 􀐛

    XcodeͷPreferencesΛॻ͖׵͑ͯɺBehaviorsΠϕϯτʹScriptΛࢦఆ ΠϕϯτΛղऍͯ͠৘ใ੔ܗˍ֎෦ΞϓϦʹ޲͚ͯ௨஌ૹ৴ ௨஌ͷड৴पΓΛ؆୯ʹ͢Δ֎෦ΞϓϦ޲͚ͷAPI
  12. XCHook & XCMonitor XCMonitor͸XcodeͷϏϧυͱςετͷΠϕϯτΛ؂ࢹͯ͠
 ϩάΛऩूͰ͖Δϝχϡʔόʔৗறܕπʔϧ GitHub͔ΒΞϓϦΛΠϯετʔϧՄೳɿhttps://github.com/kyome22/XCMonitor 􁓵 ɹ ঢ়ଶΛϦΞϧλΠϜʹ൓ө

  13. XCHook & XCMonitor ऴ͓ྃͯ͘͠ 􀐛 XCHook XCMonitor Xcode XcodeͷPreferencesΛ্ॻ͖ͯ͠
 ScriptΛ֤ΠϕϯτͷRun߲໨ʹࢦఆ͢Δ

    ؀ڥઃఆ͔ΒXCHookΛ༗ޮʹ͢Δ ಋೖฤ Scriptͷ࣮ߦʹඞཁͳԼ४උΛ͢Δ
  14. XCHook & XCMonitor BehaviorsͷΠϕϯτൃՐ 􀐛 XCHook XCMonitor Xcode Script͕ΠϕϯτΛղऍͯ͠৘ใΛ੔ܗ ৘ใΛ֎෦ΞϓϦʹ௨஌ͱͯ͠ૹ৴

    Xcodeͷىಈঢ়ଶΛ؂ࢹͭͭ͠ɺ௨஌Λৗ࣌଴ػ ड৴࣍ୈɺදࣔΛߋ৽ˍΠϕϯτͷϩάΛஷΊΔ ར༻ฤ
  15. vs App Sandboxͷน

  16. vs App Sandboxͷน XCMonitor Xcode 􀙦 App Sandbox App Sandbox͸ɺΞϓϦ͕ΞΫηεՄೳͳྖҬΛ੍ݶ͢Δ͜ͱͰɺ


    γεςϜͷϦιʔεͱϢʔβʔͷσʔλΛอޢ͢ΔͨΊͷ΋ͷ ֎෦ΞϓϦΛૢ࡞ͨ͠Γঢ়ଶΛऔಘ͢Δ͜ͱ͸௨ৗෆՄೳ ࣗ࡞ΞϓϦͷ৔߹ɺApp Sandboxͷ༗ޮ/ແޮ͸։ൃऀʹҕͶΒΕ͍ͯΔ Xcode͸App Sandboxʹอޢ͞Ε͍ͯΔͨΊɺ֎෦͔ΒΞΫηεͰ͖ͳ͍
  17. vs App Sandboxͷน Xcodeଆ͔Β֎෦ΞϓϦʹ޲͚ͯ߹๏తʹσʔλΛૹ৴͢Δ࢓૊Έ͕ඞཁ BehaviorsͷRun ScriptͰShell ScriptΛ࣮ߦ ͞ΒʹShell Script಺ͰSwiftͷεΫϦϓτΛ࣮ߦ͠
 DistributedNoti

    fi cationCenterͰ֎෦ΞϓϦʹ޲͚৘ใΛൃ৴ XCMonitor Xcode 􀙦 App Sandbox 􀐕 Behaviors >_ Shell Script Swift Script 􀫊
  18. vs App Sandboxͷน XCMonitor Xcode 􀙦 App Sandbox 􀐕 Behaviors

    >_ Shell Script Swift Script 􀫊 ~/.xchook BehaviorsͷRun ScriptͰεΫϦϓτΛಈ͔͢৔߹ɺ
 Shell ScriptͱSwiftͷεΫϦϓτʹ͸࣮ߦݖݶΛ෇༩͢Δ chmod 744 ͜ΕΒͷεΫϦϓτ͸ϗʔϜσΟϨΫτϦ௚Լʹ .xchook σΟϨΫτϦΛ
 ࡞੒ͯͦ͜͠ʹ഑ஔ
  19. vs App Sandboxͷน XCMonitor Xcode 􀙦 App Sandbox Plist App

    Sandbox 􀞡 ಋೖϋʔυϧΛԼ͛ΔͨΊɺBehaviorsͷRun ScriptΛࣗಈͰࢦఆ͢Δ
 ࢓૊Έ͕ཉ͍͠ Preferencesͷ಺༰͸ ~/Library/Preferences/com.apple.dt.Xcode.plist 
 ʹอଘ͞ΕΔ App SandboxΛແޮʹ͢Ε͹ɺ֎෦ΞϓϦ͔ΒϑΝΠϧΛಡΈॻ͖Մೳ
  20. vs App Sandboxͷน ಋೖϋʔυϧΛԼ͛ΔͨΊɺBehaviorsͷRun ScriptΛࣗಈͰࢦఆ͢Δ
 ࢓૊Έ͕ཉ͍͠ Preferencesͷ಺༰͸ ~/Library/Preferences/com.apple.dt.Xcode.plist 
 ʹอଘ͞ΕΔ

    App SandboxΛແޮʹ͢Ε͹ɺ֎෦ΞϓϦ͔ΒϑΝΠϧΛಡΈॻ͖Մೳ XCMonitor Xcode 􀙦 App Sandbox Plist App Sandbox 􀞡 Full Access
  21. ϓϩδΣΫτύεͷऔಘ

  22. ϓϩδΣΫτύεͷऔಘ ϓϩδΣΫτ໊ͱύεΛޙͰར༻͢ΔͨΊɺRun ScriptͷதͰऔಘ͍ͨ͠ XcodeͰ։͘ϓϩδΣΫτܗࣜʹ͸ɺXcode Projectʢ .xcodeproj ʣͱ
 Xcode Workspaceʢ .xcworkspace

    ʣͱ Swift Package ͷ̏छྨ͕͋Δ Run ScriptͷதͰར༻Մೳͳ؀ڥม਺Λ׆༻ͯ͠ύεΛղੳ
  23. ϓϩδΣΫτύεͷऔಘ Run ScriptΛ࣮ߦͨ͠ࡍͷ؀ڥม਺ Xcode Projectͷ৔߹ ؀ڥม਺ ஋ XcodeProject PROJECT_NAME.xcodeproj XcodeProjectPath

    PROJECT_ROOT/PROJECT_NAME.xcodeproj XcodeWorkspacePath PROJECT_ROOT/PROJECT_NAME.xcodeproj/project.xcworkspace PWD PROJECT_ROOT * PROJECT_ROOT = ϓϩδΣΫτͷϧʔτͷઈରύε * PROJECT_NAME = ϓϩδΣΫτ໊
  24. ϓϩδΣΫτύεͷऔಘ Run ScriptΛ࣮ߦͨ͠ࡍͷ؀ڥม਺ Xcode Workspaceͷ৔߹ʢCocoaPodsΛ࢖͍ͬͯΔͳͲʣ ؀ڥม਺ ஋ XcodeWorkspace PROJECT_NAME.xcworkspace XcodeWorkspacePath

    PROJECT_ROOT/PROJECT_NAME.xcworkspace PWD PROJECT_ROOT * PROJECT_ROOT = ϓϩδΣΫτͷϧʔτͷઈରύε * PROJECT_NAME = ϓϩδΣΫτ໊
  25. ϓϩδΣΫτύεͷऔಘ Run ScriptΛ࣮ߦͨ͠ࡍͷ؀ڥม਺ Swift Packageܗࣜͷ৔߹ ؀ڥม਺ ஋ XcodeWorkspace package.xcworkspace XcodeWorkspacePath

    PROJECT_ROOT/.swiftpm/xcode/package.xcworkspace PWD PROJECT_ROOT/.swiftpm/xcode * PROJECT_ROOT = ϓϩδΣΫτͷϧʔτͷઈରύε
  26. ϓϩδΣΫτύεͷऔಘ if (؀ڥม਺XcodeProject͕औಘՄೳ) { Xcode Project } else if (xcworkspaceϑΝΠϧͷ໊લ͕package.xcworkspace)

    { Swift Package } else { Xcode Workspace } Run ScriptΛ࣮ߦͨ͠ࡍͷ؀ڥม਺ͷಛ௃ ؀ڥม਺ XcodeProject ͕औಘͰ͖Δͷ͸Xcode Projectܗࣜͷ৔߹ͷΈ Swift Packageܗࣜͷ৔߹ɺxcworkspaceϑΝΠϧͷ໊લ͸
 package.xcworkspace Ͱݻఆ
  27. ϓϩδΣΫτύεͷऔಘ ҎԼͷShell ScriptͰϓϩδΣΫτ໊ͱύε͕औಘͰ͖Δ #!/bin/sh - if [ "$XcodeProject" ]; then

    # Normal Xcode Project PROJECT_NAME=`basename "$XcodeProject" .xcodeproj` PROJECT_PATH=$XcodeProjectPath elif [ "$XcodeWorkspace" = "package.xcworkspace" ]; then # Swift Package Library PROJECT_NAME=`basename $(dirname "$XcodeWorkspacePath" | sed -r "s/\.swiftpm.+//")` PROJECT_PATH=$XcodeWorkspacePath else # XCWorkspace (Probably using CocoaPods.) PROJECT_NAME=`basename "$XcodeWorkspace" .xcworkspace` PROJECT_PATH=$XcodeWorkspacePath fi ࢀরɿhttps://github.com/Kyome22/XCHook/blob/main/Sources/XCHook/run_scripts/build_start.sh
  28. XcodeͷPreferencesΛ ॻ͖׵͑Δ

  29. XcodeͷPreferencesΛॻ͖׵͑Δ Preferencesͷσʔλ͸ ~/Library/Preferences/com.apple.dt.Xcode.plist ʹ
 อଘ͞Ε͓ͯΓɺ͜ΕʹखΛՃ͑Ε͹ྑ͍ BinaryܗࣜͷProperty ListͷͨΊɺςΩετΤσΟλͰ։͍ͯ΋ಡΊͳ͍ XcodeͰ։͘ͱಡΈॻ͖͕Ͱ͖Δ͕ɺ਺ेඵʹҰ౓ͷස౓ͰϦϩʔυ͞Ε
 දࣔߏ଄͕มΘΔͷͰखಈͰฤू͢Δͷ͸ࠔ೉
 ʢࣙॻܕ͸ॱংΛอূ͠ͳ͍ͨΊϩʔυͷͨͼʹॱং͕มΘΓಘΔʣ

  30. XcodeͷPreferencesΛॻ͖׵͑Δ { "Xcode.AlertEvents.4_1": { "Xcode.AlertEvents.BuildStart": { "Xcode.Alert.RunScript": { "enabled": boolean,

    "path": "Shell Scriptͷύε" } }, "Xcode.AlertEvents.TestingSucceeds": { "Xcode.Alert.RunScript": { "enabled": boolean, "path": "Shell Scriptͷύε" } } } } Plist ͷ಺༰ΛJSONܗࣜͰൈਮͨ͠΋ͷ BehaviorsʹRun ScriptΛઃఆ͢Δʹ͸ɺ Xcode.AlertEvents ͱ Xcode.AlertEvents.4_1 ͷ಺༰Λॻ͖׵͑Ε͹ྑ͍ ྫ͑͹ɺXcode.AlertEvent.BuildStart ͷத ͷ Xcode.Alert.RunScript ʹ࣮ߦ͍ͨ͠
 Shell ScriptͷύεΛॻ͖ࠐΉ
  31. XcodeͷPreferencesΛॻ͖׵͑Δ { "Xcode.AlertEvents.4_1": { "Xcode.AlertEvents.BuildStart": { "Xcode.Alert.RunScript": { "enabled": boolean,

    "path": "Shell Scriptͷύε" } }, "Xcode.AlertEvents.TestingSucceeds": { "Xcode.Alert.RunScript": { "enabled": boolean, "path": "Shell Scriptͷύε" } } } } Plist ͷ಺༰ΛJSONܗࣜͰൈਮͨ͠΋ͷ BehaviorsʹRun ScriptΛઃఆ͢Δʹ͸ɺ Xcode.AlertEvents ͱ Xcode.AlertEvents.4_1 ͷ಺༰Λॻ͖׵͑Ε͹ྑ͍ ྫ͑͹ɺXcode.AlertEvent.BuildStart ͷத ͷ Xcode.Alert.RunScript ʹ࣮ߦ͍ͨ͠
 Shell ScriptͷύεΛॻ͖ࠐΉ ֊૚ߏ଄ͷਂ͍෦෼ͷॻ͖׵͕͑ඞཁ ଞͷ෦෼͸ͦͷ··อ͍ͪͨ
  32. XcodeͷPreferencesΛॻ͖׵͑Δ 4_1 ͬͯͳΜͩʁ 🧐 Xcode.AlertEvents ͱ Xcode.AlertEvents.4_1 ͸΄΅ಉ͡σʔλߏ଄͕ͩɺ
 ͓ͦΒ͘໾ׂ͕ҧ͏ Xcode.AlertEvents.4_1

    ͸Ϣʔβʔ͕ࢦఆͨ͠શͯͷઃఆ͕ೖΔͷͰຊମ Xcode.AlertEvents ͸4_1ͷόοΫΞοϓʁʢҰ෦ͷઃఆ͚͕ͩೖΔʣ
  33. XcodeͷPreferencesΛॻ͖׵͑Δ Command LineͰProperty ListΛॻ͖׵͑Δ৔߹ɺplutil ΍ PlistBuddy Λ
 ࢖༻͢Δ͜ͱ͕ଟ͍ plutil ͸̍֊૚໨·Ͱ͔͠௚઀ૢ࡞Ͱ͖ͳ͍

    😩 → ࿦֎ PlistBuddy ͸̎֊૚Ҏ্͋ͬͯ΋ૢ࡞͕Մೳ 😃 อଘܗ͕ࣜXMLʹͳͬͯ͠·͏ ☹ ্ॻ͖͍ͨ͠ՕॴͷΈΛॻ͖׵͑ΔΑ͏ͳϚʔδ͕Ͱ͖ͳ͍ 🤯
 ʢ߲̍໨ͣͭͷॻ͖׵͑ͱ·ͩଘࡏ͍ͯ͠ͳ͍σʔλͷ௥Ճ͸Ͱ͖Δʣ
  34. ্ॻ͖͍ͨ͠ՕॴͷΈΛॻ͖׵͑ΔΑ͏ͳϚʔδ͕Ͱ͖ͳ͍ͷҙຯ XcodeͷPreferencesΛॻ͖׵͑Δ { "Apple": { "Price": 100, "Color": "Green" },

    "Banana": { "Price": 100, "Color": "Yellow" }, "Cherry": { "Price": 100, "Color": "Red" } } { "Apple": { "Price": 150 }, "Banana": { "Price": 150 }, "Cherry": { "Price": 150 } } { "Apple": { "Price": 150, "Color": "Green" }, "Banana": { "Price": 150, "Color": "Yellow" }, "Cherry": { "Price": 150, "Color": "Red" } } ΦϦδφϧ ॻ͖׵͍͑ͨ಺༰ ཧ૝ͷϚʔδ݁Ռ
  35. ্ॻ͖͍ͨ͠ՕॴͷΈΛॻ͖׵͑ΔΑ͏ͳϚʔδ͕Ͱ͖ͳ͍ͷҙຯ XcodeͷPreferencesΛॻ͖׵͑Δ { "Apple": { "Price": 100, "Color": "Green" },

    "Banana": { "Price": 100, "Color": "Yellow" }, "Cherry": { "Price": 100, "Color": "Red" } } { "Apple": { "Price": 150 }, "Banana": { "Price": 150 }, "Cherry": { "Price": 150 } } ΦϦδφϧ ॻ͖׵͍͑ͨ಺༰ طʹಉ໊ͷΩʔ͕ଘࡏͯ͠
 ͍Δ৔߹Ϛʔδ͕Ͱ͖ͳ͍ PlistBuddyͰͷϚʔδ݁Ռ
  36. XcodeͷPreferencesΛॻ͖׵͑Δ let saveURL = URL(fileURLWithPath: "sample.plist") var dict: [String: Any]

    = [:] // dictΛฤूʢதུʣ let data = try! PropertyListSerialization.data(fromPropertyList: dict, format: .binary, options: .zero) try! data.write(to: saveURL, options: .atomic) طଘͷCommand LineπʔϧΛ࢖ΘͣSwiftͰࣗલ࣮૷͢Δ SwiftͰProperty ListΛॻ͖׵͑Δ৔߹ɺPropertyListSerialization Λ࢖͑͹
 BinaryܗࣜͷProperty ListΛฤूՄೳ
  37. ҆શͷͨΊɺProperty Listͷॻ͖׵͑͸Xcodeඇىಈ࣌ʹߦ͏ Xcodeͷىಈதʹॻ͖׵͑ͯ΋ଈ࣌൓ө͞Εͳ͍ Ұ౓ऴྃͯ͠࠶ىಈ͢Δͱ൓ө͞ΕΔ XcodeͷPreferencesΛॻ͖׵͑Δ

  38. ΠϕϯτͷώετϦʔΛ 
 ਖ਼͍͠ॱংͰऔಘ͢Δ

  39. ΠϕϯτͷώετϦʔΛਖ਼͍͠ॱংͰऔಘ͢Δ ͍͟ɺXcodeͷΠϕϯτΛ؂ࢹͯ͠ϩάΛऩूͯ͠ΈΔͱɺ
 ͨ·ʹΠϕϯτͷಧ͘ॱং͕લޙͯ͠͠·͏͜ͱʹؾ͍ͮͨ 􀙄 􀊄 Ϗϧυ։࢝ 􀙄 Ϗϧυ੒ޭ 􁁛 ςετ੒ޭ

    􀙄 􀊄 Ϗϧυ։࢝ 􀙄 Ϗϧυ੒ޭ 􁁛 ςετ੒ޭ ٯॱʹͳ͍ͬͯΔ😫 ςετ։࢝ 􁁚 􀊄 ςετ։࢝ 􁁚 􀊄
  40. ςετ։࢝ 􁁚 􀊄 ΠϕϯτͷώετϦʔΛਖ਼͍͠ॱংͰऔಘ͢Δ Run Scriptͷ࣮ߦ͸ΠϕϯτͷൃՐ࣌Ͱ͸͋Δ͕ɺஞ࣍ॲཧͰ͸ͳ͘ฒྻॲཧ ͞ΕΔͨΊɺRun Scriptͷ࣮ߦ׬ྃΛ଴ͨͣʹΠϕϯτ͕ਐΉ 􀙄 􀊄

    Ϗϧυ։࢝ ஞ࣍ॲཧͷΠϝʔδ 􀙄 Ϗϧυ੒ޭ 􀙄 Ϗϧυ Run Script A >_ Run Script B >_
  41. ΠϕϯτͷώετϦʔΛਖ਼͍͠ॱংͰऔಘ͢Δ Run Scriptͷ࣮ߦ͸ΠϕϯτͷൃՐ࣌Ͱ͸͋Δ͕ɺஞ࣍ॲཧͰ͸ͳ͘ฒྻॲཧ ͞ΕΔͨΊɺRun Scriptͷ࣮ߦ׬ྃΛ଴ͨͣʹΠϕϯτ͕ਐΉ 􀙄 􀊄 Ϗϧυ։࢝ 􀙄 Ϗϧυ੒ޭ

    Run Script A ςετ։࢝ 􁁚 􀊄 􀙄 Ϗϧυ Run Script B ฒྻॲཧͷΠϝʔδ ࣍ͷॲཧʹॏͳ͍ͬͯΔ
  42. Run Scriptͷ࣮ߦ͸ΠϕϯτͷൃՐ࣌Ͱ͸͋Δ͕ɺஞ࣍ॲཧͰ͸ͳ͘ฒྻॲཧ ͞ΕΔͨΊɺRun Scriptͷ࣮ߦ׬ྃΛ଴ͨͣʹΠϕϯτ͕ਐΉ ͠͹͠͹Πϕϯτͷॱং͕લޙ͢Δݱ৅͕ى͖ಘΔ
 ʢApple Silicon MacͷϏϧυ͕ߴ଎͗ͯ͢௨஌ॲཧͷํ͕ෛ͚Δʁʣ ΠϕϯτͷώετϦʔΛਖ਼͍͠ॱংͰऔಘ͢Δ 􀙄

    􀊄 Ϗϧυ։࢝ 􀙄 Ϗϧυ੒ޭ Run Script A ςετ։࢝ 􁁚 􀊄 􀙄 Ϗϧυ Run Script B ॲཧͷ׬͕ྃٯస
  43. ΠϕϯτͷώετϦʔΛਖ਼͍͠ॱংͰऔಘ͢Δ Πϕϯτͷ௨஌ॱংΛอূ͢ΔͨΊɺಧ͍ͨॱ͸৴༻ͤͣɺ
 λΠϜελϯϓΛجʹ౎౓ฒͼସ͑Δ ࣮ߦ͢ΔShell Scriptͷ๯಄Ͱ date ίϚϯυΛ࢖ͬͯλΠϜελϯϓΛ
 औಘͯ͠Έͨ

  44. ΠϕϯτͷώετϦʔΛਖ਼͍͠ॱংͰऔಘ͢Δ Πϕϯτͷ௨஌ॱংΛอূ͢ΔͨΊɺಧ͍ͨॱ͸৴༻ͤͣɺ
 λΠϜελϯϓΛجʹ౎౓ฒͼସ͑Δ ࣮ߦ͢ΔShell Scriptͷ๯಄Ͱ date ίϚϯυΛ࢖ͬͯλΠϜελϯϓΛ
 औಘͯ͠Έͨ ҰॠͰϏϧυ͕׬ྃ͢Δ৔߹ɺ໰୊ΛղফͰ͖ͳ͔ͬͨ 😧

    macOS ͷ date ίϚϯυ͸ϛϦඵϨϕϧ·ͰऔಘͰ͖ͳ͍͜ͱ͕൑໌
  45. ΠϕϯτͷώετϦʔΛਖ਼͍͠ॱংͰऔಘ͢Δ ϛϦඵϨϕϧͷλΠϜελϯϓΛऔಘ͍ͨ͠ 1. HomebrewͰcoreutilsΛΠϯετʔϧͯ͠ gdate ίϚϯυΛ࢖͏ XCHook͸Swift PackageϥΠϒϥϦͳͷͰHomebrewʹཔΓͨ͘ͳ͍ 🙅

  46. ϛϦඵϨϕϧͷλΠϜελϯϓΛऔಘ͍ͨ͠ 2. macOSʹϓϦΠϯετʔϧ͞Ε͍ͯΔPerlΛ࢖ͬͯϛϦඵ·Ͱग़ྗ͢Δ কདྷతʹPerlɺPythonɺRuby͕macOSͷϓϦΠϯετʔϧର৅͔Β
 ֎ΕΔͱ͍͏࿩͕͋ΔͷͰආ͚͍ͨ 🙅 ΠϕϯτͷώετϦʔΛਖ਼͍͠ॱংͰऔಘ͢Δ ࢀরɿhttps://developer.apple.com/documentation/macos-release-notes/macos-catalina-10_15-
 ɹɹɹrelease-notes#Scripting-Language-Runtims

  47. ϛϦඵϨϕϧͷλΠϜελϯϓΛऔಘ͍ͨ͠ 3. CݴޠͰϛϦඵ·Ͱग़ྗ͢ΔίʔυΛ༻ҙ͓͍ͯͯ͠ɺ
 ؀ڥ͝ͱʹϏϧυ͠ɺ࣮ߦϑΝΠϧΛར༻͢Δ CݴޠͳΒϓϦΠϯετʔϧ͔Β֎͞Εͳ͍ʢ͸ͣ ࣮֬ʹϛϦඵ·ͰऔಘͰ͖Δ ϓϩηοα͕ҟͳΔͱ࣮ߦϑΝΠϧ͕ಈ࡞͠ͳ͍ͨΊಋೖ࣌ʹϏϧυ͢Δ
 ʢApple Silicon MacͰϏϧυ࣮ͨ͠ߦϑΝΠϧ͸Intel

    MacͰಈ͔ͳ͍ʣ ΠϕϯτͷώετϦʔΛਖ਼͍͠ॱংͰऔಘ͢Δ 👌
  48. ΠϕϯτͷώετϦʔΛਖ਼͍͠ॱংͰऔಘ͢Δ func run(_ args: String...) { let task = Process()

    task.launchPath = "/bin/sh" task.arguments = ["-c", args.joined(separator: " ")] task.launch() task.waitUntilExit() } run("gcc", "timestamp.c", "-o", "ts") CݴޠͰϛϦඵϨϕϧͷλΠϜελϯϓΛऔಘ͢ΔʢϏϧυฤʣ Process() Λ࢖ͬͯSwift͔ΒShellΛୟ͘ ༻ҙ͓͍ͯͨ͠CݴޠͷίʔυΛ gcc ͰίϯύΠϧ͢Δ
  49. CݴޠͰϛϦඵϨϕϧͷλΠϜελϯϓΛऔಘ͢Δʢ࣮ߦฤʣ ίϯύΠϧ࣮ͨ͠ߦϑΝΠϧΛ ~/.xchook ʹஔ͍͓ͯ͘ Run Scriptͷ࣮ߦ࣌ʹShell Scriptͷ๯಄Ͱ࣮ߦϑΝΠϧΛ࢖͏ ΠϕϯτͷώετϦʔΛਖ਼͍͠ॱংͰऔಘ͢Δ XCMonitor Xcode

    􀙦 App Sandbox 􀐕 Behaviors >_ Shell Script Swift Script 􀫊 ~/.xchook $ C fi le &
  50. ೚ҙͷϓϩδΣΫτ΢Πϯυ΢Λ 
 ࠷લ໘ʹදࣔͤ͞Δ

  51. ೚ҙͷϓϩδΣΫτ΢Πϯυ΢Λ࠷લ໘ʹදࣔͤ͞Δ Ϗϧυ͕׬ྃͨ͜͠ͱ΍ςετ͕ऴΘͬͨ͜ͱΛXCMonitorͰ஌ͬͨޙʹ
 ͦͷϓϩδΣΫτͷ΢Πϯυ΢Λ࠷લ໘ʹදࣔͤ͞Δػೳ͕ཉ͘͠ͳͬͨ ֎෦ΞϓϦͷ΢Πϯυ΢͸؅׋֎ͷͨΊ௨ৗ͸੍ޚͰ͖ͳ͍
 ʢApp SandboxΛແޮʹͯ͠Accessibility APIΛ࢖ͬͯ΋ͳ͓೉͍͠ʣ

  52. ೚ҙͷϓϩδΣΫτ΢Πϯυ΢Λ࠷લ໘ʹදࣔͤ͞Δ Ϗϧυ͕׬ྃͨ͜͠ͱ΍ςετ͕ऴΘͬͨ͜ͱΛXCMonitorͰ஌ͬͨޙʹ
 ͦͷϓϩδΣΫτͷ΢Πϯυ΢Λ࠷લ໘ʹදࣔͤ͞Δػೳ͕ཉ͘͠ͳͬͨ ֎෦ΞϓϦͷ΢Πϯυ΢͸؅׋֎ͷͨΊ௨ৗ͸੍ޚͰ͖ͳ͍
 ʢApp SandboxΛແޮʹͯ͠Accessibility APIΛ࢖ͬͯ΋ͳ͓೉͍͠ʣ ൃ૝Λม͑ͯɺϓϩδΣΫτϑΝΠϧΛXcodeͰ։͘͜ͱͰ
 ࠷લ໘ʹ΢Πϯυ΢Λදࣔͤ͞Δ͜ͱʹͨ͠
 ʢ೚ҙͷϑΝΠϧΛ೚ҙͷΞϓϦͰ։͘ͷ͸App

    Sandbox؀ڥͰ΋Մೳ)
  53. ೚ҙͷϓϩδΣΫτ΢Πϯυ΢Λ࠷લ໘ʹදࣔͤ͞Δ ϓϩδΣΫτϑΝΠϧΛXcodeͰ։͘ NSWorkspace.shared.openApplication(at:con fi guration:) Ͱ͸
 XcodeΛ։͚ͩ͘Ͱ೚ҙͷϑΝΠϧ͸։͚ͳ͍ NSWorkspace.shared.open(_:withApplicationAt:con fi guration:)

    Ͱ
 ϑΝΠϧͷύεͱΞϓϦͷύε૒ํΛࢦఆͯ͠։͘ ͜ͷ࣌ͷͨΊʹRun ScriptͰϓϩδΣΫτϑΝΠϧͷύεΛऔಘ͍ͯͨ͠
  54. Run Scriptͷσόοάํ๏

  55. Run Scriptͷσόοάํ๏ BehaviorsͷRun Scriptʹ͓͍ͯඪ४ग़ྗ͸֬ೝͷํ๏͕ͳ͍
 cat ΍ echo ίϚϯυɺSwift.print() Λ࢖ͬͯ΋֬ೝͰ͖Δ৔ॴʹग़ྗ͞Εͳ͍ Console.appͰϩάϝοηʔδΛ֬ೝ͢Δ

    Shell ScriptͰ͸ logger -s Λ࢖͏ SwiftͷεΫϦϓτͰ͸ NSLog() Λ࢖͏ Console.app
  56. Run Scriptͷσόοάํ๏ Console.appͰϩάϝοηʔδΛ֬ೝ͢Δ ֆจࣈΛ࢖͏ͱߜΓࠐΈ΍͍͢😋

  57. ·ͱΊ XcodeͷϏϧυͱςετͷΠϕϯτΛϑοΫͯ͠௨஌͢Δ࢓૊ΈΛ
 Swift PackageͰ࡞ͬͨΑʙ 👆ͷσϞΞϓϦͱͯ͠ϏϧυͱςετͷϩάΛ؂ࢹ͢Δ
 ϝχϡʔόʔৗறܕΞϓϦΛ࡞ͬͯ഑෍͍ͯ͠ΔΑʙ App SandboxͷนΛճආͨ͠ΓɺProperty ListΛॻ͖׵͑ͨΓɺ
 ΠϕϯτऔಘͷॱংΛอূ͢ΔͷʹςΫχοΫ͕ඞཁͩͬͨΑʙ

    Thank you!