Getting Started
This walks through a tweak that does nothing but prove it loaded. Once that works, everything else is detail.
Before you start
TweakInject requires System Integrity Protection to be disabled, which greatly reduces your Mac's security. See Installation.
The tweak
#import <Foundation/Foundation.h>
__attribute__((constructor))
static void init(void) {
NSLog(@"[MyTweak] loaded into %@",
[[NSProcessInfo processInfo] processName]);
}
A constructor runs when the library is loaded, which is the moment the loader has put you inside the host process.
The filter
Without one, your tweak loads into nothing. This targets the Dock:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Bundles</key>
<array><string>com.apple.dock</string></array>
</dict>
</plist>
Building
clang -dynamiclib -arch arm64e \
-isysroot "$(xcrun --show-sdk-path --sdk macosx)" \
-framework Foundation \
-install_name /Library/TweakInject/Tweaks/DynamicLibraries/MyTweak.dylib \
-o MyTweak.dylib MyTweak.m
codesign -f -s - MyTweak.dylib
The signature is ad-hoc. Library validation is disabled system-wide, which is the only reason anything not signed by Apple loads into these processes at all.
Installing it
Drag the .dylib and its .plist onto the Installed
Tweaks page, or package them as a .deb and install that. See
Packaging.
Restart the Dock and watch the log. Tweaks are injected at process start, so anything already running has to be restarted before it picks one up.
Next
- Filters, to target something more precisely.
- Preferences, to make it configurable.
- Safe Mode, for when a tweak breaks something.