1 // Copyright 2015-present 650 Industries. All rights reserved. 2 3 import Foundation 4 5 class EXDevLauncherUtils { 6 /** 7 Swizzles implementations of given selectors. 8 */ swizzlenull9 static func swizzle(selector selectorA: Selector, withSelector selectorB: Selector, forClass: AnyClass) { 10 if let methodA = class_getInstanceMethod(forClass, selectorA), 11 let methodB = class_getInstanceMethod(forClass, selectorB) { 12 let impA = method_getImplementation(methodA) 13 let argsTypeA = method_getTypeEncoding(methodA) 14 15 let impB = method_getImplementation(methodB) 16 let argsTypeB = method_getTypeEncoding(methodB) 17 18 if class_addMethod(forClass, selectorA, impB, argsTypeB) { 19 class_replaceMethod(forClass, selectorB, impA, argsTypeA) 20 } else { 21 method_exchangeImplementations(methodA, methodB) 22 } 23 } 24 } 25 26 /** 27 Swizzles implementations of given class method selectors. 28 This function will backup original selector implementation for `invokeOriginalClassMethod`. 29 */ swizzleClassMethodnull30 static func swizzleClassMethod(selector selectorA: Selector, withSelector selectorB: Selector, forClass: AnyClass) { 31 if let methodA = class_getClassMethod(forClass, selectorA), 32 let methodB = class_getClassMethod(forClass, selectorB) { 33 let impA = method_getImplementation(methodA) 34 let backupSelectorA = NSSelectorFromString("_" + NSStringFromSelector(selectorA)) 35 let metaClass = objc_getMetaClass(String(describing: forClass)) as? AnyClass 36 class_addMethod(metaClass, backupSelectorA, impA, method_getTypeEncoding(methodA)) 37 method_setImplementation(methodA, method_getImplementation(methodB)) 38 } 39 } 40 41 /** 42 Invokes the original implementation before swizzling for the given selector 43 */ invokeOriginalClassMethodnull44 static func invokeOriginalClassMethod(selector: Selector, forClass: AnyClass) throws -> Any? { 45 typealias ClassMethod = @convention(c) (AnyObject, Selector) -> Any 46 let imp = try getOriginalClassMethodImp(selector: selector, forClass: forClass) 47 return unsafeBitCast(imp, to: ClassMethod.self)(self, selector) 48 } 49 50 /** 51 Invokes the original implementation before swizzling for the given selector 52 */ invokeOriginalClassMethodnull53 static func invokeOriginalClassMethod(selector: Selector, forClass: AnyClass, A0: Any) throws -> Any? { 54 typealias ClassMethod = @convention(c) (AnyObject, Selector, Any) -> Any 55 let imp = try getOriginalClassMethodImp(selector: selector, forClass: forClass) 56 return unsafeBitCast(imp, to: ClassMethod.self)(self, selector, A0) 57 } 58 getOriginalClassMethodImpnull59 private static func getOriginalClassMethodImp(selector: Selector, forClass: AnyClass) throws -> IMP { 60 let backupSelector = NSSelectorFromString("_" + NSStringFromSelector(selector)) 61 guard let method = class_getClassMethod(forClass, backupSelector) else { 62 fatalError("Backup selector does not exist - forClass[\(forClass)] backupSelector[\(NSStringFromSelector(backupSelector))]") 63 } 64 return method_getImplementation(method) 65 } 66 resourcesBundlenull67 static func resourcesBundle() -> Bundle? { 68 let frameworkBundle = Bundle(for: EXDevLauncherUtils.self) 69 70 guard let resourcesBundleUrl = frameworkBundle.url(forResource: "EXDevLauncher", withExtension: "bundle") else { 71 return nil 72 } 73 return Bundle(url: resourcesBundleUrl) 74 } 75 } 76