- What we'll make is a simple tweak that adds a blur to the lock screen, with the option to change the its alpha/intensity on the fly. How can this happen without a respring? The Settings app will need to communicate with SpringBoard to notify that the blur value has been changed, so that it can refresh the UI. The
NSNotificationCenterFoundation API makes that really straightforward. You can explore theNSNotificationCenterAPI's documentation here
Open your terminal and create a tweak project, your Tweak.x should look like this:
#import "Tweak.h"
static CGFloat blurIntensity = 0.85f;
static void loadPrefs(void) {
NSUserDefaults *prefs = [[NSUserDefaults alloc] initWithSuiteName:@"com.example.respringlesstweakprefs"];
blurIntensity = [prefs objectForKey:@"blurIntensity"] ? [prefs floatForKey:@"blurIntensity"] : 0.85;
}
%hook CSCoverSheetViewController
%property (nonatomic, strong) _UIBackdropView *blurView;
%new
- (void)setupBlur {
_UIBackdropViewSettings *settings = [_UIBackdropViewSettings settingsForStyle:2];
if(!self.blurView) {
self.blurView = [[_UIBackdropView alloc] initWithFrame:CGRectZero autosizesToFitSuperview:YES settings:settings];
self.blurView.alpha = blurIntensity;
[self.view insertSubview:self.blurView atIndex:0];
}
}
%new
- (void)updateBlurIntensity {
loadPrefs();
self.blurView.alpha = blurIntensity;
}
- (void)viewDidLoad {
%orig;
[self setupBlur];
[NSDistributedNotificationCenter.defaultCenter addObserver:self selector:@selector(updateBlurIntensity) name:@"com.example.respringlesstweakprefs/DidUpdateBlurIntensityNotification" object: nil];
}
%end
%ctor {
loadPrefs();
}Then your Tweak.h should have:
@import UIKit;
@interface _UIBackdropViewSettings : NSObject
+ (id)settingsForStyle:(NSInteger)style;
@end
@interface _UIBackdropView : UIView
- (id)initWithFrame:(CGRect)frame autosizesToFitSuperview:(BOOL)autosizes settings:(_UIBackdropViewSettings *)settings;
@end
@interface CSCoverSheetViewController: UIViewController
@property (nonatomic, strong) _UIBackdropView *blurView;
- (void)setupBlur;
@end
@interface NSDistributedNotificationCenter: NSNotificationCenter
@end-
First we create the
void loadPrefs(void)function that will contain our prefs, adding theCGFloatkey for the blur intensity. -
We hook
- (void)viewDidLoadfromCSCoverSheetViewControllerwhere we call the original implementation and our custom method- (void)setupBlurwhere we create a_UIBackdropViewblur with custom settings, nothing crazy going on there. Finally the most important part: we create a notification observer by callingaddObserver:selector:name:object:onNSDistributedNotificationCenter. We're using the distributed variant because we need to communicate between two different processes (Preferences & SpringBoard). This observer,CSCoverSheetViewControllerwill be listening to notifications with the name ofcom.example.respringlesstweakprefs/DidUpdateBlurIntensityNotification, when one gets send, it'll callupdateBlurIntensity, which will update thealphavalue accordingly & reflect it on the UI.
Now we have to actually make the preferences, so create a preference bundle project, your root view controller should look like this:
#import "RTRootVC.h"
@implementation RTRootVC
- (NSArray *)specifiers {
if(!_specifiers) _specifiers = [self loadSpecifiersFromPlistName:@"Root" target:self];
return _specifiers;
}
- (void)setPreferenceValue:(id)value specifier:(PSSpecifier *)specifier {
NSUserDefaults *prefs = [[NSUserDefaults alloc] initWithSuiteName:@"com.example.respringlesstweakprefs"];
[prefs setObject:value forKey:specifier.properties[@"key"]];
[super setPreferenceValue:value specifier:specifier];
if(![specifier.properties[@"key"] isEqualToString: @"blurIntensity"]) return;
[NSDistributedNotificationCenter.defaultCenter postNotificationName:@"com.example.respringlesstweakprefs/DidUpdateBlurIntensityNotification" object:nil];
}
@endThen your RTRootVC.h:
@import Preferences.PSListController;
@import Preferences.PSSpecifier;
@interface RTRootVC : PSListController
@end
@interface NSDistributedNotificationCenter : NSNotificationCenter
@end-
The logic is simple. We implement
- (void)setPreferenceValue:(id)value specifier:(PSSpecifier *)specifierwhere we create an instance ofNSUserDefaultswith our suite name and set the float value for the given key, to finally post a notification when the slider value is modified, which in turn will be received byCSCoverSheetViewControllerwhich will update the UI accordingly. -
That's how a respringless tweak works, in this case every time you update the slider in the prefs panel, the method we implemented gets called which posts the notification, the observer listening for it receives it and calls the designated method. Now you have succesfully created your first respringless tweak!
-
If you want to try the project yourself it's available here
-
Here's how the blur looks ↓
