A secure, simple, and efficient Swift/Objective-C hook library that dynamically modifies the methods of a specific object or all objects of a class. It supports both Swift and Objective-C and has excellent compatibility with Key-Value Observing (KVO).
It’s based on Objective-C runtime and libffi.
class TestObject { // No need to inherit from NSObject.
// Use `@objc` to make this method accessible from Objective-C
// Using `dynamic` tells Swift to always refer to Objective-C dynamic dispatch
@objc dynamic func testMethod() {
print("Executing `testMethod`")
}
}
let obj = TestObject()
let token = try hookBefore(object: obj, selector: #selector(TestObject.testMethod)) {
print("Before executing `testMethod`")
}
obj.testMethod()
token.cancelHook() // cancel the hook
class TestObject {
@objc dynamic func testMethod(_ parameter: String) {
print("Executing `testMethod` with parameter: \(parameter)")
}
}
let obj = TestObject()
let token = try hookAfter(object: obj, selector: #selector(TestObject.testMethod(_:)), closure: { obj, sel, parameter in
print("After executing `testMethod` with parameter: \(parameter)")
} as @convention(block) ( // Using `@convention(block)` to declares a Swift closure as an Objective-C block
AnyObject, // `obj` Instance
Selector, // `testMethod` Selector
String // first parameter
) -> Void // return value
)
obj.testMethod("ABC")
token.cancelHook() // cancel the hook
class Math {
@objc dynamic func double(_ number: Int) -> Int {
let result = number * 2
print("Executing `double` with \(number), result is \(result)")
return result
}
}
let math = Math()
try hookInstead(object: math, selector: #selector(Math.double(_:)), closure: { original, obj, sel, number in
print("Before executing `double`")
let originalResult = original(obj, sel, number)
print("After executing `double`, got result \(originalResult)")
print("Triple the number!")
return number * 3
} as @convention(block) (
(AnyObject, Selector, Int) -> Int, // original method block
AnyObject, // `math` Instance
Selector, // `sum` Selector
Int // number
) -> Int // return value
)
let number = 3
let result = math.double(number)
print("Double \(number), got \(result)")
class TestObject {
@objc dynamic func testMethod() {
print("Executing `testMethod`")
}
}
let token = try hookBefore(targetClass: TestObject.self, selector: #selector(TestObject.testMethod)) {
print("Before executing `testMethod`")
}
let obj = TestObject()
obj.testMethod()
token.cancelHook() // cancel the hook
class TestObject {
@objc dynamic class func testClassMethod() {
print("Executing `testClassMethod`")
}
@objc dynamic static func testStaticMethod() {
print("Executing `testStaticMethod`")
}
}
try hookClassMethodBefore(targetClass: TestObject.self, selector: #selector(TestObject.testClassMethod)) {
print("Before executing `testClassMethod`")
}
TestObject.testClassMethod()
try hookClassMethodBefore(targetClass: TestObject.self, selector: #selector(TestObject.testStaticMethod)) {
print("Before executing `testStaticMethod`")
}
TestObject.testStaticMethod()
SwiftHook can be integrated by cocoapods.
pod 'EasySwiftHook'
Or use Swift Package Manager. SPM is supported from 3.2.0. Make sure your Xcode is greater than 12.5, otherwise it compiles error.
Comparing with Aspects (respect to Aspects).
SwiftHook is full compatible with KVO from 3.0.0 version. For more test cases: Here
BTW, Respect to Aspects!
link |
Stars: 286 |
Last commit: 5 weeks ago |
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics