diff --git a/.github/workflows/FLEX.yml b/.github/workflows/FLEX.yml new file mode 100644 index 0000000000..7bae5a269c --- /dev/null +++ b/.github/workflows/FLEX.yml @@ -0,0 +1,90 @@ +name: Build + +on: + push: + branches: + - main + - master + - codex/flex-mit-github-actions-kompilieren + pull_request: + workflow_dispatch: + +jobs: + xcode: + name: Xcode build and tests + runs-on: macos-15 + + env: + DERIVED_DATA_PATH: build/DerivedData + + steps: + - name: Check out repository + uses: actions/checkout@v5 + + - name: Show build environment + run: | + xcodebuild -version + xcodebuild -showsdks + - name: Build FLEX framework + run: | + xcodebuild build \ + -project FLEX.xcodeproj \ + -scheme FLEX \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination 'generic/platform=iOS Simulator' \ + -derivedDataPath "$DERIVED_DATA_PATH" \ + CODE_SIGNING_ALLOWED=NO + - name: Upload FLEX framework + uses: actions/upload-artifact@v6 + with: + name: FLEX-framework-debug-iphonesimulator + path: ${{ env.DERIVED_DATA_PATH }}/Build/Products/Debug-iphonesimulator/FLEX.framework + if-no-files-found: error + + - name: Build FLEX tests + run: | + xcodebuild build-for-testing \ + -project FLEX.xcodeproj \ + -scheme FLEXTests \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination 'generic/platform=iOS Simulator' \ + -derivedDataPath "$DERIVED_DATA_PATH" \ + CODE_SIGNING_ALLOWED=NO + tweak: + name: Theos tweak package + runs-on: macos-15 + + steps: + - name: Check out repository + uses: actions/checkout@v5 + + - name: Install Theos + run: | + git clone --recursive https://github.com/theos/theos.git "$HOME/theos" + echo "THEOS=$HOME/theos" >> "$GITHUB_ENV" + - name: Install tweak signing tools + run: | + brew install ldid + - name: Build FLEX Loader tweak package + working-directory: Tweak + run: | + make package FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless + - name: Collect injectable FLEX Loader dylib + run: | + mkdir -p Tweak/artifacts + cp Tweak/.theos/obj/FLEXLoader.dylib Tweak/artifacts/FLEXLoader.dylib + - name: Upload injectable FLEX Loader dylib + uses: actions/upload-artifact@v6 + with: + name: FLEXLoader-dylib + path: Tweak/artifacts/FLEXLoader.dylib + if-no-files-found: error + + - name: Upload FLEX Loader tweak + uses: actions/upload-artifact@v6 + with: + name: FLEXLoader-tweak + path: Tweak/packages/*.deb + if-no-files-found: error diff --git a/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m b/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m index fce0f8c6e4..881d9acd60 100644 --- a/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m +++ b/Classes/GlobalStateExplorers/FLEXLiveObjectsController.m @@ -66,6 +66,10 @@ - (void)reloadTableData { // Enumerate all objects on the heap to build the counts of instances for each class. [FLEXHeapEnumerator enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id object, __unsafe_unretained Class actualClass) { + if (!actualClass) { + return; + } + NSUInteger instanceCount = (NSUInteger)CFDictionaryGetValue(mutableCountsForClasses, (__bridge const void *)actualClass); instanceCount++; CFDictionarySetValue(mutableCountsForClasses, (__bridge const void *)actualClass, (const void *)instanceCount); @@ -76,8 +80,13 @@ - (void)reloadTableData { NSMutableDictionary *mutableSizesForClassNames = [NSMutableDictionary new]; for (unsigned int i = 0; i < classCount; i++) { Class class = classes[i]; + const char *classNameCString = class_getName(class); + if (!classNameCString) { + continue; + } + NSUInteger instanceCount = (NSUInteger)CFDictionaryGetValue(mutableCountsForClasses, (__bridge const void *)(class)); - NSString *className = @(class_getName(class)); + NSString *className = @(classNameCString); if (instanceCount > 0) { [mutableCountsForClassNames setObject:@(instanceCount) forKey:className]; } diff --git a/Classes/ObjectExplorers/FLEXRecommendation.h b/Classes/ObjectExplorers/FLEXRecommendation.h new file mode 100644 index 0000000000..e5f89825fd --- /dev/null +++ b/Classes/ObjectExplorers/FLEXRecommendation.h @@ -0,0 +1,25 @@ +// +// FLEXRecommendation.h +// FLEX +// +// Created by [Your Team] on 2025-06-26. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXRecommendation : NSObject + +@property (nonatomic, copy) NSString *title; +@property (nonatomic, copy) NSString *subtitle; +@property (nonatomic, strong) id relevantObject; +@property (nonatomic, copy) NSString *action; ++ (instancetype)createWithTitle:(NSString *)title + subtitle:(NSString *)subtitle + relevantObject:(id)object + action:(NSString *)action; +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/Classes/ObjectExplorers/FLEXRecommendation.m b/Classes/ObjectExplorers/FLEXRecommendation.m new file mode 100644 index 0000000000..e0aa054f35 --- /dev/null +++ b/Classes/ObjectExplorers/FLEXRecommendation.m @@ -0,0 +1,25 @@ +// +// FLEXRecommendation.m +// FLEX +// +// Created by [Your Team] on 2025-06-26. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXRecommendation.h" + +@implementation FLEXRecommendation + ++ (instancetype)createWithTitle:(NSString *)title + subtitle:(NSString *)subtitle + relevantObject:(id)object + action:(NSString *)action { + FLEXRecommendation *rec = [[FLEXRecommendation alloc] init]; + rec.title = title; + rec.subtitle = subtitle; + rec.relevantObject = object; + rec.action = action; + return rec; +} + +@end \ No newline at end of file diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.h b/Classes/ObjectExplorers/FLEXRecommendationEngine.h new file mode 100644 index 0000000000..536c1c40c7 --- /dev/null +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.h @@ -0,0 +1,34 @@ +// +// FLEXRecommendationEngine.h +// FLEX +// +// Created by [Your Team] on 2025-06-26. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import +#import "FLEXObjectExplorer.h" + +// Forward declaration to resolve unknown type name +@class FLEXRecommendation; + +NS_ASSUME_NONNULL_BEGIN + +@interface FLEXRecommendationEngine : NSObject + +/// Generates recommendations for a specific object +/// - parameter object: The object being explored +/// - parameter context: Optional context about the current usage scenario +/// - Returns: An array of FLEXRecommendation objects +- (NSArray *)suggestionsForObject:(id)object + context:(nullable id)context; + +/// Adds recommendation sections to the Object Explorer UI +/// - parameter customSections: Mutable array of sections to prepend to +/// - parameter forObject: The object being explored ++ (void)addRecommendationsToSections:(NSMutableArray *)customSections + forObject:(id)object; + +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/Classes/ObjectExplorers/FLEXRecommendationEngine.m b/Classes/ObjectExplorers/FLEXRecommendationEngine.m new file mode 100644 index 0000000000..10fc06e54f --- /dev/null +++ b/Classes/ObjectExplorers/FLEXRecommendationEngine.m @@ -0,0 +1,142 @@ +// +// FLEXRecommendationEngine.m +// FLEX +// +// Created by [Your Team] on 2025-06-26. +// Copyright © 2020 FLEX Team. All rights reserved. +// + +#import "FLEXRecommendationEngine.h" +#import "FLEXRecommendation.h" +#import "FLEXObjectExplorer.h" +#import "FLEXUtility.h" +#import "FLEXSingleRowSection.h" +#import "FLEXRuntimeUtility.h" +#import "FLEXTableView.h" +#import "FLEXTableViewCell.h" +#import "FLEXManager.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation FLEXRecommendationEngine + +- (NSArray *)suggestionsForObject:(id)object context:(nullable id)context { + NSString *objectType = [FLEXRuntimeUtility safeClassNameForObject:object]; + NSUInteger maxCount = 3; + + if ([objectType isEqualToString:@"UIButton"]) { + return [self generateUIButtonRecommendations:object type:objectType]; + } else if ([objectType isEqualToString:@"UIView"]) { + return [self generateUIViewRecommendations:object type:objectType]; + } else if ([objectType isEqualToString:@"UIViewController"]) { + return [self generateUIViewControllerRecommendations:object type:objectType]; + } else { + return [self generateGenericRecommendations:object type:objectType count:maxCount]; + } +} + +- (NSArray *)generateUIButtonRecommendations:(id)object type:(NSString *)type { + NSMutableArray *recommendations = [NSMutableArray array]; + + FLEXRecommendation *size = [FLEXRecommendation createWithTitle:@"Constrained Size" + subtitle:@"Add Auto‑Layout constraints to define the button size" + relevantObject:object + action:@"SIZE_SETUP"]; + FLEXRecommendation *handler = [FLEXRecommendation createWithTitle:@"Touch Handler" + subtitle:@"Add target‑action for user interaction" + relevantObject:object + action:@"HANDLER_SETUP"]; + FLEXRecommendation *state = [FLEXRecommendation createWithTitle:@"Button State" + subtitle:@"Configure normal / highlighted / disabled states" + relevantObject:object + action:@"STATE_SETUP"]; + + [recommendations addObjectsFromArray:@[size, handler, state]]; + return recommendations; +} + +- (NSArray *)generateUIViewRecommendations:(id)object type:(NSString *)type { + NSMutableArray *recommendations = [NSMutableArray array]; + + FLEXRecommendation *autoLayout = [FLEXRecommendation createWithTitle:@"Auto Layout" + subtitle:@"Add constraints or adjust frames" + relevantObject:object + action:@"AUTOLAYOUT_SETUP"]; + FLEXRecommendation *background = [FLEXRecommendation createWithTitle:@"Background" + subtitle:@"Set background colour / image / alpha" + relevantObject:object + action:@"BACKGROUND_SETUP"]; + FLEXRecommendation *corners = [FLEXRecommendation createWithTitle:@"Corners" + subtitle:@"Add corner radius / border styling" + relevantObject:object + action:@"CORNER_SETUP"]; + + [recommendations addObjectsFromArray:@[autoLayout, background, corners]]; + return recommendations; +} + +- (NSArray *)generateUIViewControllerRecommendations:(id)object type:(NSString *)type { + NSMutableArray *recommendations = [NSMutableArray array]; + + FLEXRecommendation *navigation = [FLEXRecommendation createWithTitle:@"Navigation" + subtitle:@"Configure navigation bar items / hierarchy" + relevantObject:object + action:@"NAVIGATION_SETUP"]; + FLEXRecommendation *outlets = [FLEXRecommendation createWithTitle:@"Outlets" + subtitle:@"Connect IBOutlets for easier inspection" + relevantObject:object + action:@"OUTLETS_SETUP"]; + FLEXRecommendation *lifecycle = [FLEXRecommendation createWithTitle:@"Lifecycle" + subtitle:@"Add viewDidLoad / viewWillAppear hooks" + relevantObject:object + action:@"LIFECYCLE_SETUP"]; + + [recommendations addObjectsFromArray:@[navigation, outlets, lifecycle]]; + return recommendations; +} + +- (NSArray *)generateGenericRecommendations:(id)object type:(NSString *)type count:(NSUInteger)maxCount { + NSMutableArray *recommendations = [NSMutableArray array]; + + FLEXRecommendation *methods = [FLEXRecommendation createWithTitle:@"Methods" + subtitle:@"Inspect / invoke instance & class methods" + relevantObject:object + action:@"METHODS_INSPECT"]; + FLEXRecommendation *properties = [FLEXRecommendation createWithTitle:@"Properties" + subtitle:@"View / edit ivars & properties" + relevantObject:object + action:@"PROPERTIES_EDIT"]; + FLEXRecommendation *references = [FLEXRecommendation createWithTitle:@"References" + subtitle:@"Find live objects referencing this instance" + relevantObject:object + action:@"REFERENCES_FIND"]; + + [recommendations addObjectsFromArray:@[methods, properties, references]]; + + if (recommendations.count > maxCount) { + return [recommendations subarrayWithRange:NSMakeRange(0, maxCount)]; + } + return recommendations; +} + ++ (void)addRecommendationsToSections:(NSMutableArray *)customSections forObject:(id)object { + FLEXRecommendationEngine *engine = [[FLEXRecommendationEngine alloc] init]; + NSArray *recs = [engine suggestionsForObject:object context:nil]; + + for (FLEXRecommendation *rec in recs) { + FLEXSingleRowSection *section = [FLEXSingleRowSection title:rec.title + reuse:kFLEXDefaultCell + cell:^(FLEXTableViewCell *cell) { + cell.titleLabel.text = rec.title; + cell.titleLabel.font = UIFont.flex_defaultTableCellFont; + }]; + section.selectionAction = ^(UIViewController *host) { + [[FLEXManager sharedManager] presentObjectExplorer:rec.relevantObject completion:nil]; + }; + [customSections addObject:section]; + } +} + +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/Classes/Toolbar/FLEXExplorerToolbar.m b/Classes/Toolbar/FLEXExplorerToolbar.m index b9050a6e0f..42579b780b 100644 --- a/Classes/Toolbar/FLEXExplorerToolbar.m +++ b/Classes/Toolbar/FLEXExplorerToolbar.m @@ -52,11 +52,12 @@ - (id)initWithFrame:(CGRect)frame { self.backgroundGlassView = [[UIVisualEffectView alloc] initWithEffect:glassEffect]; self.backgroundGlassView.clipsToBounds = YES; self.backgroundGlassView.layer.cornerRadius = 16; + self.backgroundGlassView.backgroundColor = FLEXColor.toolbarBackgroundColor; [self addSubview:self.backgroundGlassView]; self.backgroundView = self.backgroundGlassView; } else { self.backgroundView = [UIView new]; - self.backgroundView.backgroundColor = [FLEXColor secondaryBackgroundColorWithAlpha:0.95]; + self.backgroundView.backgroundColor = FLEXColor.toolbarBackgroundColor; [self addSubview:self.backgroundView]; } @@ -64,7 +65,7 @@ - (id)initWithFrame:(CGRect)frame { self.dragHandle = [UIView new]; self.dragHandle.backgroundColor = UIColor.clearColor; self.dragHandleImageView = [[UIImageView alloc] initWithImage:FLEXResources.dragHandle]; - self.dragHandleImageView.tintColor = [FLEXColor.iconColor colorWithAlphaComponent:0.666]; + self.dragHandleImageView.tintColor = FLEXColor.toolbarDragHandleColor; [self.dragHandle addSubview:self.dragHandleImageView]; [self addSubview:self.dragHandle]; @@ -93,12 +94,13 @@ - (id)initWithFrame:(CGRect)frame { self.descriptionGlassView = [[UIVisualEffectView alloc] initWithEffect:descGlassEffect]; self.descriptionGlassView.clipsToBounds = YES; self.descriptionGlassView.layer.cornerRadius = [[self class] descriptionContainerHeight] / 2.0; + self.descriptionGlassView.backgroundColor = FLEXColor.toolbarDescriptionBackgroundColor; self.descriptionGlassView.hidden = YES; [self addSubview:self.descriptionGlassView]; self.selectedViewDescriptionContainer = self.descriptionGlassView; } else { self.selectedViewDescriptionContainer = [UIView new]; - self.selectedViewDescriptionContainer.backgroundColor = [FLEXColor tertiaryBackgroundColorWithAlpha:0.95]; + self.selectedViewDescriptionContainer.backgroundColor = FLEXColor.toolbarDescriptionBackgroundColor; self.selectedViewDescriptionContainer.hidden = YES; [self addSubview:self.selectedViewDescriptionContainer]; } @@ -117,6 +119,7 @@ - (id)initWithFrame:(CGRect)frame { self.selectedViewDescriptionLabel = [UILabel new]; self.selectedViewDescriptionLabel.backgroundColor = UIColor.clearColor; + self.selectedViewDescriptionLabel.textColor = FLEXColor.toolbarTextColor; self.selectedViewDescriptionLabel.font = [[self class] descriptionLabelFont]; [self.selectedViewDescriptionSafeAreaContainer addSubview:self.selectedViewDescriptionLabel]; diff --git a/Classes/Toolbar/FLEXExplorerToolbarItem.m b/Classes/Toolbar/FLEXExplorerToolbarItem.m index b704d283a4..03f4d8d812 100644 --- a/Classes/Toolbar/FLEXExplorerToolbarItem.m +++ b/Classes/Toolbar/FLEXExplorerToolbarItem.m @@ -39,13 +39,13 @@ + (instancetype)itemWithTitle:(NSString *)title image:(UIImage *)image sibling:( toolbarItem.sibling = backupItem; toolbarItem.title = title; toolbarItem.image = image; - toolbarItem.tintColor = FLEXColor.iconColor; + toolbarItem.tintColor = FLEXColor.toolbarTextColor; toolbarItem.backgroundColor = self.defaultBackgroundColor; toolbarItem.titleLabel.font = [UIFont systemFontOfSize:12.0]; [toolbarItem setTitle:title forState:UIControlStateNormal]; [toolbarItem setImage:image forState:UIControlStateNormal]; - [toolbarItem setTitleColor:FLEXColor.primaryTextColor forState:UIControlStateNormal]; - [toolbarItem setTitleColor:FLEXColor.deemphasizedTextColor forState:UIControlStateDisabled]; + [toolbarItem setTitleColor:FLEXColor.toolbarTextColor forState:UIControlStateNormal]; + [toolbarItem setTitleColor:FLEXColor.toolbarDisabledTextColor forState:UIControlStateDisabled]; return toolbarItem; } diff --git a/Classes/Utility/FLEXColor.h b/Classes/Utility/FLEXColor.h index e472ba4ba1..1d19d392ec 100644 --- a/Classes/Utility/FLEXColor.h +++ b/Classes/Utility/FLEXColor.h @@ -37,6 +37,11 @@ NS_ASSUME_NONNULL_BEGIN @property (readonly, class) UIColor *scrollViewBackgroundColor; @property (readonly, class) UIColor *iconColor; @property (readonly, class) UIColor *borderColor; +@property (readonly, class) UIColor *toolbarBackgroundColor; +@property (readonly, class) UIColor *toolbarDescriptionBackgroundColor; +@property (readonly, class) UIColor *toolbarTextColor; +@property (readonly, class) UIColor *toolbarDisabledTextColor; +@property (readonly, class) UIColor *toolbarDragHandleColor; @property (readonly, class) UIColor *toolbarItemHighlightedColor; @property (readonly, class) UIColor *toolbarItemSelectedColor; @property (readonly, class) UIColor *hairlineColor; diff --git a/Classes/Utility/FLEXColor.m b/Classes/Utility/FLEXColor.m index 95a995bfcd..a30ba58eea 100644 --- a/Classes/Utility/FLEXColor.m +++ b/Classes/Utility/FLEXColor.m @@ -111,18 +111,62 @@ + (UIColor *)borderColor { return [self primaryBackgroundColor]; } ++ (UIColor *)toolbarBackgroundColor { + if (@available(iOS 13.0, *)) { + return [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traits) { + if (traits.userInterfaceStyle == UIUserInterfaceStyleDark) { + return [UIColor colorWithWhite:1.0 alpha:0.82]; + } + + return [UIColor colorWithWhite:0.0 alpha:0.78]; + }]; + } + + return [UIColor colorWithWhite:0.0 alpha:0.78]; +} + ++ (UIColor *)toolbarDescriptionBackgroundColor { + if (@available(iOS 13.0, *)) { + return [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traits) { + if (traits.userInterfaceStyle == UIUserInterfaceStyleDark) { + return [UIColor colorWithWhite:1.0 alpha:0.90]; + } + + return [UIColor colorWithWhite:0.0 alpha:0.86]; + }]; + } + + return [UIColor colorWithWhite:0.0 alpha:0.86]; +} + ++ (UIColor *)toolbarTextColor { + if (@available(iOS 13.0, *)) { + return [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traits) { + if (traits.userInterfaceStyle == UIUserInterfaceStyleDark) { + return UIColor.blackColor; + } + + return UIColor.whiteColor; + }]; + } + + return UIColor.whiteColor; +} + ++ (UIColor *)toolbarDisabledTextColor { + return [[self toolbarTextColor] colorWithAlphaComponent:0.45]; +} + ++ (UIColor *)toolbarDragHandleColor { + return [[self toolbarTextColor] colorWithAlphaComponent:0.72]; +} + + (UIColor *)toolbarItemHighlightedColor { - return FLEXDynamicColor( - quaternaryLabelColor, - colorWithHue:2.0/3.0 saturation:0.1 brightness:0.25 alpha:0.6 - ); + return [[self toolbarTextColor] colorWithAlphaComponent:0.18]; } + (UIColor *)toolbarItemSelectedColor { - return FLEXDynamicColor( - secondaryLabelColor, - colorWithHue:2.0/3.0 saturation:0.1 brightness:0.25 alpha:0.68 - ); + return [[self toolbarTextColor] colorWithAlphaComponent:0.28]; } + (UIColor *)hairlineColor { diff --git a/Classes/Utility/FLEXHeapEnumerator.m b/Classes/Utility/FLEXHeapEnumerator.m index 5707160656..910c447a25 100644 --- a/Classes/Utility/FLEXHeapEnumerator.m +++ b/Classes/Utility/FLEXHeapEnumerator.m @@ -208,6 +208,10 @@ + (FLEXHeapSnapshot *)generateHeapSnapshot { // Enumerate all objects on the heap to build the counts of instances for each class [FLEXHeapEnumerator enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id object, __unsafe_unretained Class cls) { + if (!cls) { + return; + } + NSUInteger instanceCount = (NSUInteger)CFDictionaryGetValue( mutableCountsForClasses, (__bridge const void *)cls ); @@ -222,8 +226,13 @@ + (FLEXHeapSnapshot *)generateHeapSnapshot { NSMutableDictionary *sizesForClassNames = [NSMutableDictionary new]; for (unsigned int i = 0; i < classCount; i++) { Class class = classes[i]; + const char *classNameCString = class_getName(class); + if (!classNameCString) { + continue; + } + NSUInteger instanceCount = (NSUInteger)CFDictionaryGetValue(mutableCountsForClasses, (__bridge const void *)(class)); - NSString *className = @(class_getName(class)); + NSString *className = @(classNameCString); if (instanceCount > 0) { countsForClassNames[className] = @(instanceCount); diff --git a/FLEX.xcodeproj/project.pbxproj b/FLEX.xcodeproj/project.pbxproj index 4a779e9c87..b9031f8780 100644 --- a/FLEX.xcodeproj/project.pbxproj +++ b/FLEX.xcodeproj/project.pbxproj @@ -74,7 +74,7 @@ 3A4C95101B5B21410088C3F2 /* FLEXMethodCallingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C948B1B5B21410088C3F2 /* FLEXMethodCallingViewController.m */; }; 3A4C95221B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C949F1B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.h */; settings = {ATTRIBUTES = (Private, ); }; }; 3A4C95231B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94A01B5B21410088C3F2 /* FLEXFileBrowserSearchOperation.m */; }; - 3A4C95241B5B21410088C3F2 /* FLEXFileBrowserController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A11B5B21410088C3F2 /* FLEXFileBrowserController.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 3A4C95241B5B21410088C3F2 /* FLEXFileBrowserController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A11B5B21410088C3F2 /* FLEXFileBrowserController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3A4C95251B5B21410088C3F2 /* FLEXFileBrowserController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94A21B5B21410088C3F2 /* FLEXFileBrowserController.m */; }; 3A4C95261B5B21410088C3F2 /* FLEXGlobalsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A4C94A31B5B21410088C3F2 /* FLEXGlobalsViewController.h */; }; 3A4C95271B5B21410088C3F2 /* FLEXGlobalsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A4C94A41B5B21410088C3F2 /* FLEXGlobalsViewController.m */; }; diff --git a/Tweak/FLEXLoader.plist b/Tweak/FLEXLoader.plist new file mode 100644 index 0000000000..52fa316847 --- /dev/null +++ b/Tweak/FLEXLoader.plist @@ -0,0 +1,7 @@ +{ + Filter = { + Bundles = ( + "com.apple.UIKit" + ); + }; +} diff --git a/Tweak/Makefile b/Tweak/Makefile new file mode 100644 index 0000000000..53c15c70bf --- /dev/null +++ b/Tweak/Makefile @@ -0,0 +1,15 @@ +ARCHS = arm64 arm64e +TARGET := iphone:clang:latest:14.0 +INSTALL_TARGET_PROCESSES = SpringBoard + +include $(THEOS)/makefiles/common.mk + +TWEAK_NAME = FLEXLoader + +FLEXLoader_FILES = Tweak.xm $(shell find ../Classes -type f \( -name '*.m' -o -name '*.mm' -o -name '*.c' \)) +FLEXLoader_CFLAGS = -fobjc-arc -Wno-error -Wno-unused-but-set-variable -Wno-deprecated-declarations -Wno-unsupported-availability-guard $(shell find ../Classes -type d -exec printf ' -I%s' {} \;) +FLEXLoader_CXXFLAGS = -std=gnu++11 +FLEXLoader_FRAMEWORKS = UIKit Foundation CoreGraphics ImageIO QuartzCore WebKit Security SceneKit +FLEXLoader_LIBRARIES = sqlite3 z c++ + +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Tweak/Tweak.xm b/Tweak/Tweak.xm new file mode 100644 index 0000000000..2442a4ffd1 --- /dev/null +++ b/Tweak/Tweak.xm @@ -0,0 +1,42 @@ +#import +#import "FLEXManager.h" + +static BOOL FLEXLoaderDidShowExplorer = NO; + +static void FLEXLoaderShowExplorer(void) { + if (FLEXLoaderDidShowExplorer) { + return; + } + + FLEXLoaderDidShowExplorer = YES; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [[FLEXManager sharedManager] showExplorer]; + }); +} + +%ctor { + if (NSProcessInfo.processInfo.environment[@"FLEX_LOADER_DISABLED"]) { + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + UIApplication *application = UIApplication.sharedApplication; + if (application.applicationState != UIApplicationStateBackground) { + FLEXLoaderShowExplorer(); + } + + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification + object:nil + queue:NSOperationQueue.mainQueue + usingBlock:^(__unused NSNotification *notification) { + FLEXLoaderShowExplorer(); + }]; + + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification + object:nil + queue:NSOperationQueue.mainQueue + usingBlock:^(__unused NSNotification *notification) { + FLEXLoaderShowExplorer(); + }]; + }); +} diff --git a/Tweak/control b/Tweak/control new file mode 100644 index 0000000000..d1801f4d4e --- /dev/null +++ b/Tweak/control @@ -0,0 +1,9 @@ +Package: com.flextool.flexloader +Name: FLEX Loader +Version: 1.0.0 +Architecture: iphoneos-arm +Description: Loads FLEX automatically into UIKit applications. +Maintainer: FLEX Team +Author: FLEX Team +Section: Tweaks +Depends: mobilesubstrate