{"id":15500892,"url":"https://github.com/yulingtianxia/blockhook","last_synced_at":"2025-10-08T04:51:12.684Z","repository":{"id":56903802,"uuid":"123141601","full_name":"yulingtianxia/BlockHook","owner":"yulingtianxia","description":"Hook Objective-C blocks. A powerful AOP tool. ","archived":false,"fork":false,"pushed_at":"2024-02-06T08:22:37.000Z","size":1144,"stargazers_count":849,"open_issues_count":2,"forks_count":82,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-04-12T16:56:30.730Z","etag":null,"topics":["aop","blockhook","carthage","cocoapods","hookblock","hooks","interceptor","ios","libffi","macos","objective-c"],"latest_commit_sha":null,"homepage":"http://yulingtianxia.com/blog/2018/02/28/Hook-Objective-C-Block-with-Libffi/","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yulingtianxia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-02-27T14:35:47.000Z","updated_at":"2025-02-14T07:24:20.000Z","dependencies_parsed_at":"2024-06-18T20:05:30.153Z","dependency_job_id":"bdf9de08-167e-41c2-ac3f-9d973df780a8","html_url":"https://github.com/yulingtianxia/BlockHook","commit_stats":{"total_commits":191,"total_committers":3,"mean_commits":"63.666666666666664","dds":"0.010471204188481686","last_synced_commit":"4d2e80dbf937d76f11968f8f7199a00c3b84932b"},"previous_names":[],"tags_count":52,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yulingtianxia%2FBlockHook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yulingtianxia%2FBlockHook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yulingtianxia%2FBlockHook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yulingtianxia%2FBlockHook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yulingtianxia","download_url":"https://codeload.github.com/yulingtianxia/BlockHook/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254582905,"owners_count":22095518,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aop","blockhook","carthage","cocoapods","hookblock","hooks","interceptor","ios","libffi","macos","objective-c"],"created_at":"2024-10-02T09:01:31.537Z","updated_at":"2025-10-08T04:51:07.662Z","avatar_url":"https://github.com/yulingtianxia.png","language":"C","readme":"\u003cp align=\"center\"\u003e\n\u003ca href=\"https://github.com/yulingtianxia/BlockHook\"\u003e\n\u003cimg src=\"Assets/logo.png\" alt=\"BlockHook\" /\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n[![Platform](https://img.shields.io/cocoapods/p/BlockHook.svg?style=flat)](http://cocoapods.org/pods/BlockHook)\n[![CI Status](http://img.shields.io/travis/yulingtianxia/BlockHook.svg?style=flat)](https://travis-ci.org/yulingtianxia/BlockHook)\n[![Version](https://img.shields.io/cocoapods/v/BlockHook.svg?style=flat)](http://cocoapods.org/pods/BlockHook)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![codecov](https://codecov.io/gh/yulingtianxia/BlockHook/branch/master/graph/badge.svg)](https://codecov.io/gh/yulingtianxia/BlockHook)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/5ba94898dd8146a6beb7b4a6cc46e3fd)](https://app.codacy.com/app/yulingtianxia/BlockHook?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=yulingtianxia/BlockHook\u0026utm_campaign=Badge_Grade_Dashboard)\n[![GitHub release](https://img.shields.io/github/release/yulingtianxia/blockhook.svg)](https://github.com/yulingtianxia/BlockHook/releases)\n[![Twitter Follow](https://img.shields.io/twitter/follow/yulingtianxia.svg?style=social\u0026label=Follow)](https://twitter.com/yulingtianxia)\n\n# BlockHook\n\nHook Objective-C blocks with libffi. It's a powerful AOP tool for blocks. BlockHook can run your code before/instead/after invoking a block. BlockHook can even notify you when a block dealloc. You can trace the whole lifecycle of a block using BlockHook!\n\n**Want to hook blocks passing to methods? Try [BlockTracker](https://github.com/yulingtianxia/BlockTracker)!**\n\n## 🌟 Features\n\n- [x] Easy to use. Keep your code clear.\n- [x] Support 4 hook modes: Before, Instead, After and Dead.\n- [x] Let you modify return value and arguments.\n- [x] Support invoking original implementation.\n- [x] Remove hook at any time.\n- [x] Traverse all hook tokens of block.\n- [x] Provide block mangle name.\n- [x] Self-managed tokens.\n- [x] Support custom struct.\n- [x] Support Carthage \u0026 CocoaPods.\n\n## 🔮 Example\n\nBlockHook needs libffi, which supports iOS, tvOS and macOS.\nYou can run `BlockHookSample iOS`, `BlockHookSample tvOS` or `BlockHookSample macOS` target.\n\n## 🐒 How to use\n\n### Just Hook\n\nYou can hook a block using 4 modes (before/instead/after/dead). This method returns a `BHToken` instance for more control. You can `remove` a `BHToken`, or set custom return value to its `retValue` property. Calling `invokeOriginalBlock` method will invoke original implementation of the block.\n\n```objc\n- (BHToken *)block_hookWithMode:(BlockHookMode)mode\n                     usingBlock:(id)block\n```\n\nBlockHook is easy to use. Its APIs take example by Aspects. [Here](https://github.com/yulingtianxia/BlockHook/blob/master/BlockHookSampleTests/BlockHookSampleTests.m) is a full set of usage of BlockHook.\n\nThis is an example for hooking block in all modes. You can change block return value from 8 to 15. Then remove some hook and check if it is successful. Finally we get callback when block dealloc. \n\n```objc\nNSObject *z = NSObject.new;\nint(^block)(int x, int y) = ^int(int x, int y) {\n    int result = x + y;\n    NSLog(@\"%d + %d = %d, z is a NSObject: %@\", x, y, result, z);\n    return result;\n};\n    \nBHToken *token = [block block_hookWithMode:BlockHookModeDead|BlockHookModeBefore|BlockHookModeInstead|BlockHookModeAfter usingBlock:^(BHInvocation *invocation, int x, int y) {\n    int ret = 0;\n    [invocation getReturnValue:\u0026ret];\n    switch (invocation.mode) {\n        case BlockHookModeBefore:\n            // BHInvocation has to be the first arg.\n            NSLog(@\"hook before block! invocation:%@\", invocation);\n            break;\n        case BlockHookModeInstead:\n            [invocation invokeOriginalBlock];\n            NSLog(@\"let me see original result: %d\", ret);\n            // change the block imp and result\n            ret = x * y;\n            [invocation setReturnValue:\u0026ret];\n            NSLog(@\"hook instead: '+' -\u003e '*'\");\n            break;\n        case BlockHookModeAfter:\n            // print args and result\n            NSLog(@\"hook after block! %d * %d = %d\", x, y, ret);\n            break;\n        case BlockHookModeDead:\n            // BHInvocation is the only arg.\n            NSLog(@\"block dead! token:%@\", invocation.token);\n            break;\n        default:\n            break;\n    }\n}];\n    \nNSLog(@\"hooked block\");\nint ret = block(3, 5);\nNSLog(@\"hooked result:%d\", ret);\n// remove token.\n[token remove];\nNSLog(@\"remove tokens, original block\");\nret = block(3, 5);\nNSLog(@\"original result:%d\", ret);\n```\n\nHere is the log:\n\n```\nhooked block\nhook before block! invocation:\u003cBHInvocation: 0x60b00003c370\u003e\n3 + 5 = 8, z is a NSObject: \u003cNSObject: 0x6020000279d0\u003e\nlet me see original result: 0\nhook instead: '+' -\u003e '*'\nhook after block! 3 * 5 = 15\nhooked result:15\nblock dead! token:\u003cBHToken: 0x60d000004bd0\u003e\nremove tokens, original block\n3 + 5 = 8, z is a NSObject: \u003cNSObject: 0x6020000279d0\u003e\noriginal result:8\n```\n\n### Block Interceptor\n\nSometimes you want user login first before routing to other components. To intercept a block without hacking into code of routers, you can use block interceptor.\n\n```objc\nNSObject *testArg = [NSObject new];\nNSObject *testArg1 = [NSObject new];\n    \nNSObject *(^testblock)(NSObject *) = ^(NSObject *a) {\n    return [NSObject new];\n};\n    \n[testblock block_interceptor:^(BHInvocation *invocation, IntercepterCompletion  _Nonnull completion) {\n    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{\n        NSObject * __unsafe_unretained arg;\n        [invocation getArgument:\u0026arg atIndex:1];\n        NSLog(@\"Original argument:%@\", arg);\n        [invocation setArgument:(void *)\u0026testArg1 atIndex:1];\n        completion();\n    });\n}];\n    \ntestblock(testArg);\n```\n\n## 📲 Installation\n\n### CocoaPods\n\n[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command:\n\n```bash\n$ gem install cocoapods\n```\n\nTo integrate BlockHook into your Xcode project using CocoaPods, specify it in your `Podfile`:\n\n\n```\nsource 'https://github.com/CocoaPods/Specs.git'\nplatform :ios, '8.0'\nuse_frameworks!\ntarget 'MyApp' do\n\tpod 'BlockHook'\nend\n```\n\nYou need replace \"MyApp\" with your project's name.\n\nThen, run the following command:\n\n```bash\n$ pod install\n```\n\n### Carthage\n\n[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.\n\nYou can install Carthage with [Homebrew](http://brew.sh/) using the following command:\n\n```bash\n$ brew update\n$ brew install carthage\n```\n\nTo integrate BlockHook into your Xcode project using Carthage, specify it in your `Cartfile`:\n\n```ogdl\ngithub \"yulingtianxia/BlockHook\"\n```\n\nRun `carthage update` to build the framework and drag the built `BlockHook.framework` into your Xcode project.\n\n### Manual\n\nAfter importing libffi, just add the two files `BlockHook.h/m` to your project.\n\n## ❤️ Contributed\n\n- If you **need help** or you'd like to **ask a general question**, open an issue.\n- If you **found a bug**, open an issue.\n- If you **have a feature request**, open an issue.\n- If you **want to contribute**, submit a pull request.\n\n## 📚 Article\n\n- [Hook Objective-C Block with Libffi](http://yulingtianxia.com/blog/2018/02/28/Hook-Objective-C-Block-with-Libffi/)\n- [BlockHook with Struct](http://yulingtianxia.com/blog/2019/04/27/BlockHook-with-Struct/)\n- [BlockHook with Revocation](http://yulingtianxia.com/blog/2019/05/26/BlockHook-with-Revocation/)\n- [BlockHook with Private Data](http://yulingtianxia.com/blog/2019/06/19/BlockHook-with-Private-Data/)\n- [BlockHook with Invocation(1)](http://yulingtianxia.com/blog/2019/07/27/BlockHook-with-Invocation/)\n- [BlockHook with Invocation(2)](http://yulingtianxia.com/blog/2019/08/11/BlockHook-with-Invocation-2/)\n- [BlockHook and Memory Safety](http://yulingtianxia.com/blog/2020/05/30/BlockHook-and-Memory-Safety/)\n\n## 👨🏻‍💻 Author\n\nyulingtianxia, yulingtianxia@gmail.com\n\n## 👮🏻 License\n\nBlockHook is available under the MIT license. See the LICENSE file for more info.\n\nThanks to MABlockClosure and Aspects!\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyulingtianxia%2Fblockhook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyulingtianxia%2Fblockhook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyulingtianxia%2Fblockhook/lists"}