User:Uroboro: Difference between revisions

641 editsJoined 4 March 2013
(→‎Test Zone: Will Collapsibles work here?)
(Collaboration and cross-platform compilation)
Line 250: Line 250:
}
}
</source>
</source>
== Collaboration and cross-platform compilation ==
When doing group projects you might find that each contributor has a different platform and possibly a different Theos installation path. To prevent <tt>make</tt> errors caused by the theos symlink, some may consider blacklisting it from the revision control software (git or svn). It doesn't matter if you do or not, the threat of a missing or incorrect symlink still exists.
Having worked with other developers with an Apple computer, while myself working with my iPhone5,1, I found myself "fighting" this annoyance. After a couple iterations I've made this snippet to fix this "problem":
<source lang="text">
__SYMLINK := /$(if $(filter $(shell uname -s)-$(shell uname -p),Darwin-arm Darwin-arm64),var,opt)/theos
T := $(shell [[ "$(__SYMLINK)" != `readlink theos` ]] && { rm -f theos; ln -s $(__SYMLINK) theos; })
</source><!-- There's no makefile syntax highlight?! -->
To use it, place it anywhere before all <tt>include</tt>s, be it at the top of the Makefile or just before <code>include theos/makefiles/common.mk</code>.
[https://ghostbin.com/paste/nn4fo Previous iterations].


== Other Stuff ==
== Other Stuff ==

Revision as of 19:28, 3 February 2015

Find me on saurik's IRC server, Twitter, Reddit, Github, StackOverflow.

Made UnlockEvents and FlipNC.

If you are looking for notifications within a process, give NotificationExplorer a look.

Some NIC templates here.

And a repository there: uroboro.github.io/repo.

DISCLAIMER: All code written in this page is to be considered experimental and untested. The author shall not be held responsible or liable for any undesired consequences, including, but not limited to, data loss, property damage, time travel, the singularity, suffered by you as a result of any error in such code. You also agree that you will not use these code snippets for any purposes prohibited by United States law, including, without limitation, the development, design, manufacture, or production of nuclear, missile, or chemical or biological weapons.

"Interesting" links

How 2 prefs

As opposed to using NSDictionaries and [NSHomeDirectory() stringByAppendingFormat:@"/Library/Preferences/%s.plist", "com.your.tweak"], here's another alternative to handling preferences on tweaks.

To do: read [this] carefully and move all information regarding preferences to a more appropriate place.

Tweak.xm

@interface NSUserDefaults (Tweak_Category)
- (id)objectForKey:(NSString *)key inDomain:(NSString *)domain;
- (void)setObject:(id)value forKey:(NSString *)key inDomain:(NSString *)domain;
@end

static NSString *nsDomainString = @"com.your.tweak";
static NSString *nsNotificationString = @"com.your.tweak/preferences.changed";
static BOOL enabled;

static void notificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
    NSNumber *n = (NSNumber *)[[NSUserDefaults standardUserDefaults] objectForKey:@"enabled" inDomain:nsDomainString];
    enabled = (n)? [n boolValue]:YES;
}

%ctor {
// Set variables on start up
notificationCallback(NULL, NULL, NULL, NULL, NULL);

// Register for 'PostNotification' notifications
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, notificationCallback, (CFStringRef)nsNotificationString, NULL, CFNotificationSuspensionBehaviorCoalesce);

// Add any personal initializations
}

/*
 * From here onward, write your tweak.
 * To make your tweak actually do stuff when enabled:
if (!enabled) {
     // Do the original algorithm, either by calling:
     // %orig(); //if using logos for methods
     // _functionName(args); //if using MSHook() for functions
} else {
    ...
    // Optionally, do the original algorithm
}
 */

Preference plist

Choose any of the following:

Reduced style

Provides a switch on the root section of the preferences (like Airplane Mode). Recommended for configuration-less tweaks.

Saved in your tweak's folder as layout/Library/PreferenceLoader/Preferences/com.your.tweak.plist

{
    entry = {
        cell = PSSwitchCell;
        defaults = "com.your.tweak";
        label = "Your Tweak";
        key = enabled;
        default = 1;
        icon = "/Applications/Preferences.app/[email protected]";
        PostNotification = "com.your.tweak/preferences.changed";
    };
}

Extended Style

Provides a pane where other cells can appear (like Wi-Fi). Recommended for configuration-friendly tweaks.

Saved in your tweak's folder as layout/Library/PreferenceLoader/Preferences/com.your.tweak.plist

{
    title = "Your Tweak";
    entry = {
        cell = PSLinkCell;
        label = "Your Tweak";
        icon = "/Applications/Preferences.app/[email protected]";
    };
    items = (
        {
            cell = PSSwitchCell;
            defaults = "com.your.tweak";
            label = Enabled;
            key = enabled;
            default = 1;
            PostNotification = "com.your.tweak/preferences.changed";
        }
        // add more cells (dictionaries) here
    );
}

PreferenceLoader Style

Provides a static list of cells. Recommended for Preference Bundles of tweaks.

Saved in your tweak's Preference Bundle subproject folder as Resources/com.your.tweak.plist

{
    items = (
        {
            cell = PSSwitchCell;
            defaults = "com.your.tweak";
            label = Enabled;
            key = enabled;
            default = 1;
            PostNotification = "com.your.tweak/preferences.changed";
        }
        // add more cells (dictionaries) here
    );
}

Flipswitches

After using the Flipswitch NIC template, modify accordingly

Switch.x

#import "FSSwitchDataSource.h"
#import "FSSwitchPanel.h"

@interface NSUserDefaults (Tweak_Category)
- (id)objectForKey:(NSString *)key inDomain:(NSString *)domain;
- (void)setObject:(id)value forKey:(NSString *)key inDomain:(NSString *)domain;
@end

static NSString *nsDomainString = @"com.your.tweak";
static NSString *nsNotificationString = @"com.your.tweak/preferences.changed";

@interface YourTweakFlipswitchSwitch : NSObject <FSSwitchDataSource>
@end

@implementation YourTweakFlipswitchSwitch

- (NSString *)titleForSwitchIdentifier:(NSString *)switchIdentifier {
    return @"Your Tweak";
}

- (FSSwitchState)stateForSwitchIdentifier:(NSString *)switchIdentifier {
    NSNumber *n = (NSNumber *)[[NSUserDefaults standardUserDefaults] objectForKey:@"enabled" inDomain:nsDomainString];
    BOOL enabled = (n)? [n boolValue]:YES;
    return (enabled) ? FSSwitchStateOn : FSSwitchStateOff;
}

- (void)applyState:(FSSwitchState)newState forSwitchIdentifier:(NSString *)switchIdentifier {
    switch (newState) {
    case FSSwitchStateIndeterminate:
        break;
    case FSSwitchStateOn:
        [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:@"enabled" inDomain:nsDomainString];
        CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef)nsNotificationString, NULL, NULL, YES);
        break;
    case FSSwitchStateOff:
        [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:@"enabled" inDomain:nsDomainString];
        CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef)nsNotificationString, NULL, NULL, YES);
        break;
    }
    return;
}

@end

Late hooking

If you need to use UI elements, you have to wait until the application is ready.

...
- (void)didReceiveNotification:(NSNotification *)notification {
	// UI is available
}
...

%ctor {
	[[NSNotificationCenter defaultCenter] addObserver:[UFSSomeClass sharedInstance]
		selector:@selector(didReceiveNotification:)
		name:UIApplicationDidFinishLaunchingNotification
		object:nil];
}

Same applies if a class you want to hook is created or loaded dynamically.

...
- (void)didReceiveNotification:(NSNotification *)notification {
	if ([notification.userInfo[NSLoadedClasses] containsString:@"targetClass"]) {
		// Target class has been loaded
	}
}
...

%ctor {
	[[NSNotificationCenter defaultCenter] addObserver:[UFSSomeClass sharedInstance]
		selector:@selector(didReceiveNotification:)
		name:NSBundleDidLoadNotification
		object:nil];
}

If you have a function you need to call, the block API can help evade creating an object to handle the notification. The following snippet creates a similar usage of the CFNotificationCenterAddObserver API.

static void notificationCallback(NSNotificationCenter *center, id observer, NSString *name, id object, NSDictionary *userInfo) {
	if ([notification.userInfo[NSLoadedClasses] containsString:@"targetClass"]) {
		// Target class has been loaded
	}
}

static id observer;
%ctor {
	NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
	NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
	observer = [center addObserverForName:NSBundleDidLoadNotification object:nil queue:mainQueue
		usingBlock:^(NSNotification *notification) {
			notificationCallback(center, observer, [notification name], [notification object], [notification userInfo]);
	}];
}

//if a destructor existed or you don't need to track the notification anymore
%dtor {
	[[NSNotificationCenter defaultCenter] removeObserver:observer];
}

Collaboration and cross-platform compilation

When doing group projects you might find that each contributor has a different platform and possibly a different Theos installation path. To prevent make errors caused by the theos symlink, some may consider blacklisting it from the revision control software (git or svn). It doesn't matter if you do or not, the threat of a missing or incorrect symlink still exists.

Having worked with other developers with an Apple computer, while myself working with my iPhone5,1, I found myself "fighting" this annoyance. After a couple iterations I've made this snippet to fix this "problem":

__SYMLINK := /$(if $(filter $(shell uname -s)-$(shell uname -p),Darwin-arm Darwin-arm64),var,opt)/theos
T := $(shell [[ "$(__SYMLINK)" != `readlink theos` ]] && { rm -f theos; ln -s $(__SYMLINK) theos; })

To use it, place it anywhere before all includes, be it at the top of the Makefile or just before include theos/makefiles/common.mk.

Previous iterations.

Other Stuff

Similar Wanted Pages:

Inheritance hierarchy‏‎ MIG Subsystems
ApplicationScripting.framework/Inheritance hierarchy‏‎ ApplicationScripting.framework/MIG subsystem‏
AppSupport.framework/Inheritance hierarchy‏‎ AppSupport.framework/MIG subsystem
AudioToolbox.framework/Inheritance hierarchy ‏AudioToolbox.framework/MIG subsystem
AVFoundation.framework/Inheritance hierarchy‏ AVFoundation.framework/MIG subsystem
BackBoardServices.framework/Inheritance hierarchy‏ BackBoardServices.framework/MIG subsystem‏‎
‏BulletinBoard.framework/Inheritance hierarchy‏ ‏BulletinBoard.framework/MIG subsystem
ChatKit.framework/Inheritance hierarchy‏‎ ChatKit.framework/MIG subsystem‏
CoreFoundation.framework/Inheritance hierarchy‏‎ CoreFoundation.framework/MIG subsystem
CoreTelephony.framework/Inheritance hierarchy‏‎ CoreTelephony.framework/MIG subsystem
‏Foundation.frameworkInheritance hierarchy‏‎ ‏Foundation.framework/MIG subsystem
GraphicsServices.framework/Inheritance hierarchy‏‎ GraphicsServices.framework/MIG subsystem
IH boilerplate/Inheritance hierarchy‏‎ IH boilerplate/MIG subsystem‏‎
IOKit.framework/Inheritance hierarchy‏‎ IOKit.framework/MIG subsystem
IOSurface.framework/Inheritance hierarchy ‏IOSurface.framework/MIG subsystem
MapKit.framework/Inheritance hierarchy MapKit.framework/MIG subsystem
Message.framework/Inheritance hierarchy ‏Message.framework/MIG subsystem
QuartzCore.framework/Inheritance hierarchy QuartzCore.framework/MIG subsystem
Preferences.app/Inheritance hierarchy‏ ‏Preferences.app/MIG subsystem
Preferences.framework/Inheritance hierarchy Preferences.framework/MIG subsystem
SpringBoard.app/Inheritance hierarchy SpringBoard.app/MIG subsystem
SpringBoardServices.framework/Inheritance hierarchy‏ SpringBoardServices.framework/MIG subsystem
TelephonyUI.framework/Inheritance hierarchy TelephonyUI.framework/MIG subsystem
UIKit.framework/Inheritance hierarchy UIKit.framework/MIG subsystem
WiFiPicker.servicebundle/Inheritance hierarchy ‏WiFiPicker.servicebundle/MIG subsystem‏

Test Zone

Wondering what looks better:

To "wikitable"...

com.your.tweak.plist
JSON style XML style
{
    entry = {
        cell = PSSwitchCell;
        defaults = "com.your.tweak";
        label = "Your Tweak";
        key = enabled;
        default = 1;
        icon = "/Applications/Preferences.app/[email protected]";
        PostNotification = "com.your.tweak/preferences.changed";
    };
}
<?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>entry</key>
	<dict>
		<key>cell</key>
		<string>PSSwitchCell</string>
		<key>defaults</key>
		<string>com.your.tweak</string>
		<key>label</key>
		<string>Your Tweak</string>
		<key>key</key>
		<string>enabled</string>
		<key>default</key>
		<true/>
		<key>icon</key>
		<string>/Applications/Preferences.app/[email protected]</string>
		<key>PostNotification</key>
		<string>com.your.tweak/preferences.changed</string>
	</dict>
</dict>
</plist>

or not to "wikitable"...

com.your.tweak.plist
JSON style XML style
{
    entry = {
        cell = PSSwitchCell;
        defaults = "com.your.tweak";
        label = "Your Tweak";
        key = enabled;
        default = 1;
        icon = "/Applications/Preferences.app/[email protected]";
        PostNotification = "com.your.tweak/preferences.changed";
    };
}
<?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>entry</key>
	<dict>
		<key>cell</key>
		<string>PSSwitchCell</string>
		<key>defaults</key>
		<string>com.your.tweak</string>
		<key>label</key>
		<string>Your Tweak</string>
		<key>key</key>
		<string>enabled</string>
		<key>default</key>
		<true/>
		<key>icon</key>
		<string>/Applications/Preferences.app/[email protected]</string>
		<key>PostNotification</key>
		<string>com.your.tweak/preferences.changed</string>
	</dict>
</dict>
</plist>

Maybe collapsing?

com.your.tweak.plist