Tweak-Tutorial

How Do You Create a Tweak?

Why should I create non-Logos tweaks?

A bit of history

Benefits

Preparation

Differences between Logos and Substrate

Converting from Logos to Substrate

Let’s say we have some easy tweak to set a view’s opacity to 50%, written in Logos.

@import UIKit;

@interface SomeView : UIView
@end

%hook SomeView

- (void)didMoveToSuperview {
    self.alpha = 0.5;
    %orig;
}

%end

First we need to import the Substrate framework.

@import UIKit;
#import <substrate.h>

@interface SomeView : UIView
@end

%hook SomeView

- (void)didMoveToSuperview {
    self.alpha = 0.5;
    %orig;
}

%end

Then we will add the wrapper for %ctor, a.k.a. __attribute__((constructor)) at the bottom.

You have to add that attribute before you create the initializing C function, so that it’ll act as an initializer for all the MSHookMessageEx messages you pass there.

@import UIKit;
#import <substrate.h>

@interface SomeView : UIView
@end

%hook SomeView

- (void)didMoveToSuperview {
    self.alpha = 0.5;
    %orig;
}

%end

__attribute__((constructor)) static void initialize() {

}

Then we would convert the %hook wrapper to MSHookMessageEx.

@import UIKit;
#import <substrate.h>

@interface SomeView : UIView
@end

%hook SomeView

- (void)didMoveToSuperview {
    self.alpha = 0.5;
    %orig;
}

%end

__attribute__((constructor)) static void initialize() {
    MSHookMessageEx(
        NSClassFromString(@"SomeView"),
        @selector(didMoveToSuperview),
        (IMP) &override_didMoveToSuperview,
        (IMP *) &orig_didMoveToSuperview
    );
}

Finally, we would have to “convert” the Objective-C method we are hooking to the C function that every Objective-C method gets “translated” to.

@import UIKit;
#import <substrate.h>

@interface SomeView : UIView
@end

static void (*orig_didMoveToSuperview)(SomeView *self, SEL _cmd);

static void override_didMoveToSuperview(SomeView *self, SEL _cmd) {
    self.alpha = 0.50;
    orig_didMoveToSuperview(self, _cmd);
}

__attribute__((constructor)) static void initialize() {
    MSHookMessageEx(
        NSClassFromString(@"SomeView"),
        @selector(didMoveToSuperview),
        (IMP) &override_didMoveToSuperview,
        (IMP *) &orig_didMoveToSuperview
    );
}

What is going on here?

“What about the MSHookMessageEx function?”

void MSHookMessageEx(Class _class, SEL message, IMP hook, IMP *old);
// let's say we're hooking SBDockView's method:

- (void)setBackgroundAlpha:(CGFloat)alpha;

// it would "become"

void setBackgroundAlpha(SBDockView *self, SEL _cmd, CGFloat alpha);

This is definitely not an all-inclusive overview of Substrate-hooking, but it is a great starting place.

If you’re wondering what or why are we using the static keyword before the function name, it allows for additional encapsulation, restricting the functions to this file only, which is good programming practice. Note that it can also mean something else for variables and it’s not necessarily the same as the static keyword in Swift.

More information about it can be found here and here, as well as here for method swizzling if you’re curious.

Previous Page (%subclass wrapper)

Next Page (Respringless Tweaks)