├── BBWeeAppController-Protocol.h ├── Makefile ├── README.md ├── Tweak.x └── layout ├── DEBIAN └── control └── Library └── MobileSubstrate └── DynamicLibraries └── WeeLoader.plist /BBWeeAppController-Protocol.h: -------------------------------------------------------------------------------- 1 | @protocol BBWeeAppController 2 | @required 3 | - (UIView *)view; 4 | @optional 5 | - (void)loadPlaceholderView; 6 | - (void)loadFullView; 7 | - (void)loadView; 8 | - (void)unloadView; 9 | - (void)clearShapshotImage; 10 | - (NSURL *)launchURL; 11 | - (NSURL *)launchURLForTapLocation:(CGPoint)tapLocation; 12 | - (float)viewHeight; 13 | - (void)viewWillAppear; 14 | - (void)viewDidAppear; 15 | - (void)viewWillDisappear; 16 | - (void)viewDidDisappear; 17 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; 18 | - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; 19 | - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; 20 | @end 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET := iphone:clang::5.0 2 | ARCHS := armv7 arm64 3 | 4 | ADDITIONAL_CFLAGS += -fobjc-arc -g -fvisibility=hidden 5 | ADDITIONAL_LDFLAGS += -Wl,-map,$@.map -g -x c /dev/null -x none 6 | 7 | TWEAK_NAME = WeeLoader 8 | WeeLoader_FILES = Tweak.x 9 | WeeLoader_FRAMEWORKS = UIKit 10 | WeeLoader_PRIVATE_FRAMEWORKS = BulletinBoard 11 | WeeLoader_LDFLAGS = -weak_framework SpringBoardUIServices 12 | 13 | after-stage:: 14 | $(ECHO_NOTHING)find $(THEOS_STAGING_DIR) -d \( -iname '*.dSYM' -or -iname '*.map' \) -execdir rm -rf {} \;$(ECHO_END) 15 | $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/System/Library/WeeAppPlugins$(ECHO_END) 16 | $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/System/Library/BulletinBoardPlugins$(ECHO_END) 17 | $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/WeeLoader/Plugins$(ECHO_END) 18 | $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/WeeLoader/BulletinBoardPlugins$(ECHO_END) 19 | 20 | after-install:: 21 | install.exec "(killall backboardd || killall SpringBoard) 2>/dev/null" 22 | 23 | include theos/makefiles/common.mk 24 | include $(THEOS_MAKE_PATH)/tweak.mk 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## WeeLoader 2 | 3 | WeeLoader is similar to PreferenceLoader, but for WeeAppPlugins rather than PreferenceBundles. Basically, it makes SpringBoard load WeeAppPlugins from a different directory. This is beneficial for a few reasons: it works better with Safe Mode, as WeeLoader isn't loaded into SpringBoard in that case, and it easily fixes all of the issues with semitethered jailbreaks and Wee apps. 4 | 5 | To use WeeLoader with your plugins, simply move your bundles from `/System/Library/WeeAppPlugins/` to `/Library/WeeLoader/Plugins/` (for Wee apps) or `/System/Library/BulletinBoardPlugins/` to `/Library/WeeLoader/BulletinBoardPlugins` (for Bulletin Board plugins), and update any hardcoded paths in your code (if necessary). You'll also want to add a dependency on `com.chpwn.weeloader` to ensure WeeLoader is installed. 6 | 7 | In addition, WeeLoader adds a compatibility layer so that iOS 5/6 Wee apps (i.e. those implementing the `BBWeeAppController` protocol) work on iOS 7 and iOS 8. 8 | 9 | -------------------------------------------------------------------------------- /Tweak.x: -------------------------------------------------------------------------------- 1 | #import "BBWeeAppController-Protocol.h" 2 | 3 | static NSString * const WeeLoaderDefaultPluginDirectory = @"/System/Library/WeeAppPlugins"; 4 | static NSString * const WeeLoaderCustomPluginDirectory = @"/Library/WeeLoader/Plugins"; 5 | static NSString * const WeeLoaderSerializationPrefix = @"/WeeLoaderFailsafePathShouldNotExist/"; 6 | 7 | static NSString * const WeeLoaderDefaultBulletinBoardPluginDirectory = @"/System/Library/BulletinBoardPlugins"; 8 | static NSString * const WeeLoaderCustomBulletinBoardPluginDirectory = @"/Library/WeeLoader/BulletinBoardPlugins"; 9 | 10 | static NSString * const WeeLoaderThreadDictionaryKey = @"WeeLoaderLoadingPlugins"; 11 | 12 | static NSInteger WeeLoaderCurrentThreadLoadingStatus() { 13 | return [[NSThread.currentThread.threadDictionary objectForKey:WeeLoaderThreadDictionaryKey] intValue]; 14 | } 15 | 16 | static void WeeLoaderSetCurrentThreadLoadingStatus(NSInteger loading) { 17 | [NSThread.currentThread.threadDictionary setObject:@(loading) forKey:WeeLoaderThreadDictionaryKey]; 18 | } 19 | 20 | __attribute__((weak_import)) @interface BBSectionIconVariant: NSObject 21 | + (id)variantWithFormat:(int)format imageName:(NSString *)name inBundle:(NSBundle *)bundle; 22 | @end 23 | 24 | __attribute__((weak_import)) @interface BBSectionIcon: NSObject 25 | - (void)addVariant:(BBSectionIconVariant *)variant; 26 | @end 27 | 28 | @interface BBSectionInfo: NSObject 29 | @property (copy, nonatomic) NSString *pathToWeeAppPluginBundle; 30 | @property (copy, nonatomic) NSString *displayName; 31 | @property (copy, nonatomic) BBSectionIcon *icon; 32 | @property (assign, nonatomic) BOOL showsInNotificationCenter; 33 | @end 34 | 35 | %hook BBSectionInfo 36 | 37 | - (void)encodeWithCoder:(NSCoder *)encoder { 38 | WeeLoaderSetCurrentThreadLoadingStatus(3); 39 | %orig; 40 | WeeLoaderSetCurrentThreadLoadingStatus(0); 41 | } 42 | 43 | - (NSString *)pathToWeeAppPluginBundle { 44 | NSString *path = %orig; 45 | 46 | if (WeeLoaderCurrentThreadLoadingStatus() == 3) { 47 | if ([path hasPrefix:WeeLoaderCustomPluginDirectory]) { 48 | return [WeeLoaderSerializationPrefix stringByAppendingString:path]; 49 | } 50 | } 51 | 52 | return path; 53 | } 54 | 55 | - (void)setPathToWeeAppPluginBundle:(NSString *)path { 56 | if ([path hasPrefix:WeeLoaderSerializationPrefix]) { 57 | %orig([path substringFromIndex:WeeLoaderSerializationPrefix.length]); 58 | } else { 59 | %orig; 60 | } 61 | } 62 | 63 | %end 64 | 65 | %group iOS_5_and_6 66 | 67 | %hook BBServer 68 | 69 | - (void)_loadAllWeeAppSections { 70 | WeeLoaderSetCurrentThreadLoadingStatus(1); 71 | %orig; 72 | WeeLoaderSetCurrentThreadLoadingStatus(0); 73 | } 74 | 75 | - (void)_loadAllDataProviderPluginBundles { 76 | WeeLoaderSetCurrentThreadLoadingStatus(2); 77 | %orig; 78 | WeeLoaderSetCurrentThreadLoadingStatus(0); 79 | } 80 | 81 | %end 82 | 83 | %hook NSFileManager 84 | 85 | - (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error { 86 | switch (WeeLoaderCurrentThreadLoadingStatus()) { 87 | case 1: { 88 | NSArray *plugins = %orig; 89 | NSArray *custom = %orig(WeeLoaderCustomPluginDirectory, error); 90 | 91 | return [plugins arrayByAddingObjectsFromArray:custom]; 92 | } 93 | case 2: { 94 | NSArray *plugins = %orig; 95 | NSArray *custom = %orig(WeeLoaderCustomBulletinBoardPluginDirectory, error); 96 | 97 | return [plugins arrayByAddingObjectsFromArray:custom]; 98 | } 99 | default: 100 | return %orig; 101 | } 102 | } 103 | 104 | %end 105 | 106 | %hook NSBundle 107 | 108 | + (NSBundle *)bundleWithPath:(NSString *)fullPath { 109 | switch (WeeLoaderCurrentThreadLoadingStatus()) { 110 | case 1: { 111 | NSBundle *bundle = %orig; 112 | 113 | if (bundle == nil && [fullPath hasPrefix:WeeLoaderDefaultPluginDirectory]) { 114 | fullPath = [WeeLoaderCustomPluginDirectory stringByAppendingString:[fullPath substringFromIndex:[WeeLoaderDefaultPluginDirectory length]]]; 115 | bundle = %orig(fullPath); 116 | } 117 | 118 | return bundle; 119 | } 120 | case 2: { 121 | NSBundle *bundle = %orig; 122 | 123 | if (bundle == nil && [fullPath hasPrefix:WeeLoaderDefaultBulletinBoardPluginDirectory]) { 124 | fullPath = [WeeLoaderCustomBulletinBoardPluginDirectory stringByAppendingString:[fullPath substringFromIndex:[WeeLoaderDefaultBulletinBoardPluginDirectory length]]]; 125 | bundle = %orig(fullPath); 126 | } 127 | 128 | return bundle; 129 | } 130 | default: 131 | return %orig; 132 | } 133 | } 134 | 135 | %end 136 | 137 | %end 138 | 139 | %group iOS_8 140 | 141 | @interface SBNotificationCenterDataProvider: NSObject 142 | - (BBSectionInfo *)defaultSectionInfo; 143 | @end 144 | 145 | @interface SBNotificationCenterDataProviderController: NSObject 146 | + (id)sharedInstance; 147 | - (BBSectionInfo *)_sectionForWidgetExtension:(id)extension withSectionID:(NSString *)sectionID forCategory:(int)category; 148 | - (void)_publishWidgetSection:(BBSectionInfo *)sectionInfo withExtension:(id)extension defaultEnabledWeeAppIDs:(NSArray *)ids; 149 | @end 150 | 151 | %hook SBNotificationCenterDataProvider 152 | 153 | - (NSString *)sectionDisplayName { 154 | return %orig ?: self.defaultSectionInfo.displayName; 155 | } 156 | 157 | - (BBSectionIcon *)sectionIcon { 158 | return %orig ?: self.defaultSectionInfo.icon; 159 | } 160 | 161 | %end 162 | 163 | %hook SpringBoard 164 | - (void)_startBulletinBoardServer { 165 | %orig; 166 | SBNotificationCenterDataProviderController *controller = [%c(SBNotificationCenterDataProviderController) sharedInstance]; 167 | for (NSString *basename in [NSFileManager.defaultManager contentsOfDirectoryAtPath:WeeLoaderCustomPluginDirectory error:NULL]) { 168 | if ([basename hasSuffix:@".bundle"]) { 169 | NSString *path = [WeeLoaderCustomPluginDirectory stringByAppendingPathComponent:basename]; 170 | NSBundle *bundle = [NSBundle bundleWithPath:path]; 171 | if (bundle) { 172 | NSString *sectionID = bundle.bundleIdentifier; 173 | BBSectionInfo *sectionInfo = [controller _sectionForWidgetExtension:nil withSectionID:sectionID forCategory:1]; 174 | sectionInfo.pathToWeeAppPluginBundle = path; 175 | NSString *displayName = [bundle.infoDictionary objectForKey:@"CFBundleDisplayName"] ?: sectionID; 176 | displayName = [bundle localizedStringForKey:displayName value:nil table:@"InfoPlist"]; 177 | sectionInfo.displayName = displayName; 178 | NSString *iconName = [bundle.infoDictionary objectForKey:@"CFBundleIconFile"]; 179 | if (iconName) { 180 | BBSectionIconVariant *iconVariant = [BBSectionIconVariant variantWithFormat:0 imageName:iconName inBundle:bundle]; 181 | BBSectionIcon *sectionIcon = [[BBSectionIcon alloc] init]; 182 | [sectionIcon addVariant:iconVariant]; 183 | sectionInfo.icon = sectionIcon; 184 | } 185 | [controller _publishWidgetSection:sectionInfo withExtension:nil defaultEnabledWeeAppIDs:@[]]; 186 | } 187 | } 188 | } 189 | } 190 | %end 191 | 192 | %hook SBWidgetsSettingsViewController 193 | - (BOOL)_setSectionInfo:(BBSectionInfo *)sectionInfo enabled:(BOOL)enabled { 194 | BOOL success = %orig; 195 | if (!success && [sectionInfo.pathToWeeAppPluginBundle hasPrefix:WeeLoaderCustomPluginDirectory]) { 196 | sectionInfo.showsInNotificationCenter = enabled; 197 | success = YES; 198 | } 199 | return success; 200 | } 201 | %end 202 | 203 | %end 204 | 205 | @interface WeeLoaderLegacyView: UIView 206 | @end 207 | 208 | @implementation WeeLoaderLegacyView 209 | - (void)layoutSubviews { 210 | for (UIView *subview in self.subviews) { 211 | subview.frame = self.frame; 212 | } 213 | [super layoutSubviews]; 214 | } 215 | @end 216 | 217 | @interface _SBUIWidgetViewController: UIViewController 218 | @property (copy, nonatomic) NSString *widgetIdentifier; 219 | - (void)loadView; 220 | - (void)unloadView; 221 | - (void)hostWillPresent; 222 | - (void)hostDidDismiss; 223 | - (CGSize)preferredViewSize; 224 | @end 225 | 226 | typedef NS_ENUM(NSInteger, WeeLoaderLegacyControllerViewState) { 227 | WeeLoaderLegacyControllerViewStateNone, 228 | WeeLoaderLegacyControllerViewStatePlaceholder, 229 | WeeLoaderLegacyControllerViewStateLoaded 230 | }; 231 | 232 | @interface WeeLoaderLegacyController: _SBUIWidgetViewController 233 | @end 234 | 235 | @implementation WeeLoaderLegacyController { 236 | id _weeAppController; 237 | WeeLoaderLegacyControllerViewState _viewState; 238 | } 239 | 240 | - (void)setWidgetIdentifier:(NSString *)widgetIdentifier { 241 | if (!_weeAppController && widgetIdentifier) { 242 | NSBundle *weeAppBundle = [NSBundle bundleWithIdentifier:widgetIdentifier]; 243 | _weeAppController = [[weeAppBundle.principalClass alloc] init]; 244 | } 245 | [super setWidgetIdentifier:widgetIdentifier]; 246 | } 247 | 248 | - (void)loadView { 249 | CGSize size = self.preferredViewSize; 250 | self.view = [[WeeLoaderLegacyView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)]; 251 | if ([_weeAppController respondsToSelector:@selector(launchURLForTapLocation:)]) { 252 | UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(launchURLForTapLocationFromRecognizer:)]; 253 | [self.view addGestureRecognizer:tapRecognizer]; 254 | } else if ([_weeAppController respondsToSelector:@selector(launchURL)]) { 255 | UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(launchURL)]; 256 | [self.view addGestureRecognizer:tapRecognizer]; 257 | } 258 | [self loadPlaceholderWeeAppView]; 259 | } 260 | 261 | - (void)unloadView { 262 | [self unloadWeeAppView]; 263 | [super unloadView]; 264 | } 265 | 266 | - (CGSize)preferredViewSize { 267 | if ([_weeAppController respondsToSelector:@selector(viewHeight)]) { 268 | CGSize size = CGSizeMake(0, _weeAppController.viewHeight); 269 | return size; 270 | } 271 | return [super preferredViewSize]; 272 | } 273 | 274 | - (void)loadPlaceholderWeeAppView { 275 | if (!_weeAppController.view && [_weeAppController respondsToSelector:@selector(loadPlaceholderView)]) { 276 | [_weeAppController loadPlaceholderView]; 277 | _viewState = WeeLoaderLegacyControllerViewStatePlaceholder; 278 | } 279 | } 280 | 281 | - (void)loadFullWeeAppView { 282 | if ([_weeAppController respondsToSelector:@selector(loadFullView)]) { 283 | [_weeAppController loadFullView]; 284 | _viewState = WeeLoaderLegacyControllerViewStateLoaded; 285 | } else if ([_weeAppController respondsToSelector:@selector(loadView)]) { 286 | [_weeAppController loadView]; 287 | _viewState = WeeLoaderLegacyControllerViewStateLoaded; 288 | } 289 | } 290 | 291 | - (void)unloadWeeAppView { 292 | [_weeAppController.view removeFromSuperview]; 293 | if ([_weeAppController respondsToSelector:@selector(unloadView)]) { 294 | [_weeAppController unloadView]; 295 | if (!_weeAppController.view) { 296 | _viewState = WeeLoaderLegacyControllerViewStateNone; 297 | } 298 | } 299 | } 300 | 301 | - (void)hostWillPresent { 302 | if (_viewState == WeeLoaderLegacyControllerViewStateNone) { 303 | [self loadPlaceholderWeeAppView]; 304 | } 305 | if (_viewState != WeeLoaderLegacyControllerViewStateLoaded) { 306 | [self loadFullWeeAppView]; 307 | } 308 | [self.view addSubview:_weeAppController.view]; 309 | [super hostWillPresent]; 310 | } 311 | 312 | - (void)hostDidDismiss { 313 | [self unloadWeeAppView]; 314 | [self loadPlaceholderWeeAppView]; 315 | [super hostDidDismiss]; 316 | } 317 | 318 | - (void)launchURLForTapLocationFromRecognizer:(UITapGestureRecognizer *)recognizer { 319 | CGPoint location = [recognizer locationInView:_weeAppController.view]; 320 | NSURL *url = [_weeAppController launchURLForTapLocation:location]; 321 | if (url) { 322 | [UIApplication.sharedApplication openURL:url]; 323 | } 324 | } 325 | 326 | - (void)launchURL { 327 | NSURL *url = [_weeAppController launchURL]; 328 | if (url) { 329 | [UIApplication.sharedApplication openURL:url]; 330 | } 331 | } 332 | 333 | - (void)viewWillAppear:(BOOL)animated { 334 | if ([_weeAppController respondsToSelector:@selector(viewWillAppear)]) { 335 | [_weeAppController viewWillAppear]; 336 | } 337 | [super viewWillAppear:animated]; 338 | } 339 | 340 | - (void)viewDidAppear:(BOOL)animated { 341 | // On iOS 8, -hostWillPresent might never be called (e.g. when we are disabled and then re-enabled), so 342 | // let's make sure we load the full view somewhere. We could do this in -loadView or -viewWillAppear 343 | // instead, but if we wait for -viewDidAppear the widget gets better initial size info. 344 | if ([%c(SBNotificationCenterDataProviderController) instancesRespondToSelector:@selector(beginPublishingIfNecessary)]) { // iOS 8 345 | [self hostWillPresent]; 346 | } 347 | 348 | if ([_weeAppController respondsToSelector:@selector(viewDidAppear)]) { 349 | [_weeAppController viewDidAppear]; 350 | } 351 | [super viewDidAppear:animated]; 352 | } 353 | 354 | - (void)viewWillDisappear:(BOOL)animated { 355 | if ([_weeAppController respondsToSelector:@selector(viewWillDisappear)]) { 356 | [_weeAppController viewWillDisappear]; 357 | } 358 | [super viewWillDisappear:animated]; 359 | } 360 | 361 | - (void)viewDidDisappear:(BOOL)animated { 362 | if ([_weeAppController respondsToSelector:@selector(viewDidDisappear)]) { 363 | [_weeAppController viewDidDisappear]; 364 | } 365 | [super viewDidDisappear:animated]; 366 | } 367 | 368 | - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { 369 | if ([_weeAppController respondsToSelector:@selector(willRotateToInterfaceOrientation:duration:)]) { 370 | [_weeAppController willRotateToInterfaceOrientation:toInterfaceOrientation]; 371 | } 372 | [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; 373 | } 374 | 375 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { 376 | if ([_weeAppController respondsToSelector:@selector(willAnimateRotationToInterfaceOrientation:duration:)]) { 377 | [_weeAppController willAnimateRotationToInterfaceOrientation:interfaceOrientation]; 378 | } 379 | [super willAnimateRotationToInterfaceOrientation:interfaceOrientation duration:duration]; 380 | } 381 | 382 | - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { 383 | if ([_weeAppController respondsToSelector:@selector(didRotateFromInterfaceOrientation:)]) { 384 | [_weeAppController didRotateFromInterfaceOrientation:fromInterfaceOrientation]; 385 | } 386 | [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; 387 | } 388 | 389 | @end 390 | 391 | extern NSArray *BBLibraryDirectoriesForFolderNamed(NSString *name) __attribute__((weak_import)); 392 | MSHook(NSArray *,BBLibraryDirectoriesForFolderNamed, NSString *name) { 393 | NSArray *directories = _BBLibraryDirectoriesForFolderNamed(name); 394 | if ([name isEqualToString:WeeLoaderDefaultBulletinBoardPluginDirectory.lastPathComponent]) { 395 | directories = [directories arrayByAddingObject:WeeLoaderCustomBulletinBoardPluginDirectory]; 396 | } 397 | return directories; 398 | } 399 | 400 | extern NSArray *_SBUIWidgetBundlePaths() __attribute__((weak_import)); 401 | MSHook(NSArray *, _SBUIWidgetBundlePaths) { 402 | NSMutableArray *paths = [NSMutableArray arrayWithArray:__SBUIWidgetBundlePaths()]; 403 | NSArray *additionalPaths = [NSFileManager.defaultManager contentsOfDirectoryAtPath:WeeLoaderCustomPluginDirectory error:NULL]; 404 | for (NSString *basename in additionalPaths) { 405 | if ([basename hasSuffix:@".bundle"]) { 406 | NSString *bundlePath = [WeeLoaderCustomPluginDirectory stringByAppendingPathComponent:basename]; 407 | [paths addObject:bundlePath]; 408 | } 409 | } 410 | return paths; 411 | } 412 | 413 | MSHook(CFDictionaryRef, CFBundleGetInfoDictionary, CFBundleRef bundle) { 414 | CFDictionaryRef cf_infoDictionary = _CFBundleGetInfoDictionary(bundle); 415 | NSURL *bundleURL = (__bridge_transfer NSURL *)CFBundleCopyBundleURL(bundle); 416 | if ([bundleURL.URLByDeletingLastPathComponent.path isEqualToString:WeeLoaderCustomPluginDirectory]) { 417 | NSDictionary *infoDict = (__bridge NSDictionary *)cf_infoDictionary; 418 | if (![infoDict objectForKey:@"SBUIWidgetViewControllers"]) { 419 | CFMutableDictionaryRef newInfoDict = CFDictionaryCreateMutableCopy(NULL, infoDict.count + 1, cf_infoDictionary); 420 | NSDictionary *widgetControllers = @{ 421 | @"SBUIWidgetIdiomNotificationCenterToday" : NSStringFromClass(WeeLoaderLegacyController.class) 422 | }; 423 | [((__bridge NSMutableDictionary *)newInfoDict) setObject:widgetControllers forKey:@"SBUIWidgetViewControllers"]; 424 | CFAutorelease(newInfoDict); 425 | return newInfoDict; 426 | } 427 | } 428 | return cf_infoDictionary; 429 | } 430 | 431 | %ctor { 432 | %init; 433 | if ([%c(BBServer) instancesRespondToSelector:@selector(_loadAllDataProviderPluginBundles)]) { // iOS 5, 6 434 | %init(iOS_5_and_6); 435 | } else { // iOS 7, 8 436 | MSHookFunction(BBLibraryDirectoriesForFolderNamed, $BBLibraryDirectoriesForFolderNamed, (void **)&_BBLibraryDirectoriesForFolderNamed); 437 | MSHookFunction(_SBUIWidgetBundlePaths, $_SBUIWidgetBundlePaths, (void **)&__SBUIWidgetBundlePaths); 438 | MSHookFunction(CFBundleGetInfoDictionary, $CFBundleGetInfoDictionary, (void **)&_CFBundleGetInfoDictionary); 439 | if ([%c(SBNotificationCenterDataProviderController) instancesRespondToSelector:@selector(beginPublishingIfNecessary)]) { // iOS 8 440 | %init(iOS_8); 441 | } 442 | } 443 | } 444 | -------------------------------------------------------------------------------- /layout/DEBIAN/control: -------------------------------------------------------------------------------- 1 | Homepage: http://moreinfo.thebigboss.org/moreinfo/depiction.php?file=weeloaderDp 2 | Depiction: http://moreinfo.thebigboss.org/moreinfo/depiction.php?file=weeloaderDp 3 | Author: joedj 4 | Maintainer: BigBoss 5 | Name: WeeLoader 6 | Package: com.chpwn.weeloader 7 | Pre-Depends: firmware (>= 5.0) 8 | Depends: mobilesubstrate 9 | Section: Development 10 | Version: 1.4 11 | Architecture: iphoneos-arm 12 | Description: Weeeeeeeeeee! Load Wee apps safely. 13 | Sponsor: thebigboss.org 14 | dev: joejordan 15 | Tag: role::developer, purpose::extension 16 | -------------------------------------------------------------------------------- /layout/Library/MobileSubstrate/DynamicLibraries/WeeLoader.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.springboard" ); }; } 2 | --------------------------------------------------------------------------------