Slide 1

Slide 1 text

From Xcode plugin to Xcode extension

Slide 2

Slide 2 text

About Khoa Pham github.com/onmyway133 github.com/hyperoslo medium.com/@onmyway133

Slide 3

Slide 3 text

It takes 2 iOS developers to start complaining about Xcode

Slide 4

Slide 4 text

XcodeWay

Slide 5

Slide 5 text

Xcode plugin

Slide 6

Slide 6 text

Alcatraz

Slide 7

Slide 7 text

XVim

Slide 8

Slide 8 text

SCXcodeMiniMap

Slide 9

Slide 9 text

FuzzyAutocompletePlugin

Slide 10

Slide 10 text

ColorSense-for-Xcode

Slide 11

Slide 11 text

Techniques • Private frameworks • Objective C Runtime • LLDB • Swizzling

Slide 12

Slide 12 text

class-dump • IDEKit • DVTKit • Xcode.app/Contents/SharedFrameworks/DVTKit.framework

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

DVTBezelAlertPanel class func swizzleMethods() { guard let originalClass = NSClassFromString("DVTBezelAlertPanel") as? NSObject.Type else { return } do { try originalClass.jr_swizzleMethod("initWithIcon:message:parentWindow:duration:", withMethod: "xmas_initWithIcon:message:parentWindow:duration:") } catch { Swift.print("Swizzling failed") } }

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

DVTSourceTextView func listenNotification() { NSNotificationCenter.defaultCenter().addObserver( self, selector: #selector(handleSelectionChange(_:)), name: NSTextViewDidChangeSelectionNotification, object: nil) } func handleSelectionChange(note: NSNotification) { guard let DVTSourceTextView = NSClassFromString("DVTSourceTextView") as? NSObject.Type, object = note.object where object.isKindOfClass(DVTSourceTextView.self), let textView = object as? NSTextView else { return } self.textView = textView }

Slide 17

Slide 17 text

IDEWorkspaceWindowController self.IDEWorkspaceWindowControllerClass = objc_getClass("IDEWorkspaceWindowController"); NSArray *workspaceWindowControllers = [self.IDEWorkspaceWindowControllerClass valueForKey:@"workspaceWindowControllers"];

Slide 18

Slide 18 text

XcodeGhost

Slide 19

Slide 19 text

Xcode Source Editor extension • Modify contents • Modify current text selection • Seperated process protocol XCSourceEditorCommand { func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void) }

Slide 20

Slide 20 text

App Extension • Share • Photo Editing • Today • Finder Sync • Custom Keyboard • File Provider • Document Provider

Slide 21

Slide 21 text

Resign codesign

Slide 22

Slide 22 text

XcodeColorSense extension ? • No Notification • No UI modification

Slide 23

Slide 23 text

Color literal ! #colorLiteral

Slide 24

Slide 24 text

XcodeWay extension ? • No NSTask • No NSWorkspace • No swizzling

Slide 25

Slide 25 text

AppleScript !

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

• NSUserAppleScriptTask • NSAppleEventDescriptor • ProcessSerialNumber on myOpenFolder(myPath) tell application "Finder" activate open myPath as POSIX file end tell end myOpenFolder

Slide 28

Slide 28 text

App Sandbox

Slide 29

Slide 29 text

Scripts Directory NSApplicationScriptsDirectory

Slide 30

Slide 30 text

macOS Mojave • WWDC 2018 - Your Apps and the Future of macOS Security • NSAppleEventsUsageDescription

Slide 31

Slide 31 text

• https://github.com/onmyway133/XcodeWay • https://github.com/onmyway133/XcodeColorSense2 • https://github.com/theswiftdev/awesome-xcode-extensions

Slide 32

Slide 32 text

Thanks May your code continue to compile