Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2bfba6715e | |||
| 0c87d94b0d | |||
| 401a94f81b | |||
| f92dd73442 | |||
| 3ccf4b8c59 | |||
| e036f964d8 | |||
| a1c3e86ce7 | |||
| 079f2d87a5 | |||
| 462c507df9 | |||
| a19f1acbed | |||
| 1b983160cc | |||
| 6616242d9c | |||
| 377a9a5f3f | |||
| 6f4d9c3ba1 | |||
| 56935533be | |||
| f0b2dc971e | |||
| 346301b628 | |||
| 692146831e | |||
| 81f748a33e | |||
| 038106f954 | |||
| 1bbf8dbea1 | |||
| 343eba92b6 | |||
| d6232baf03 | |||
| 9808b89d6d | |||
| de1cbfae4a | |||
| b036fb18a5 | |||
| c6ed5098cf | |||
| d7283cd22d | |||
| 785e181d75 | |||
| dd66f46a7b | |||
| 55bae8b53e | |||
| 5edca3fdad | |||
| 9bc319a38e | |||
| deac628b06 | |||
| 8e44d88c36 | |||
| 73e4a712e8 | |||
| 9e1f60b2f4 | |||
| 3c385143ee |
@@ -29,7 +29,8 @@
|
||||
@implementation FLEXNavigationController
|
||||
|
||||
+ (instancetype)withRootViewController:(UIViewController *)rootVC {
|
||||
return [[self alloc] initWithRootViewController:rootVC];
|
||||
FLEXNavigationController *nav = [[self alloc] initWithRootViewController:rootVC];
|
||||
return nav;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
@@ -66,6 +67,17 @@
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
if (@available(iOS 15.0, *)) {
|
||||
UISheetPresentationController *presenter = self.sheetPresentationController;
|
||||
presenter.detents = @[
|
||||
UISheetPresentationControllerDetent.mediumDetent,
|
||||
UISheetPresentationControllerDetent.largeDetent,
|
||||
];
|
||||
presenter.prefersScrollingExpandsWhenScrolledToEdge = NO;
|
||||
presenter.selectedDetentIdentifier = UISheetPresentationControllerDetentIdentifierLarge;
|
||||
presenter.largestUndimmedDetentIdentifier = UISheetPresentationControllerDetentIdentifierLarge;
|
||||
}
|
||||
|
||||
if (self.beingPresented && !self.didSetupPendingDismissButtons) {
|
||||
for (UIViewController *vc in self.viewControllers) {
|
||||
[self addNavigationBarItemsToViewController:vc.navigationItem];
|
||||
|
||||
@@ -96,7 +96,11 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
|
||||
self.searchController.searchBar.placeholder = @"Filter";
|
||||
self.searchController.searchResultsUpdater = (id)self;
|
||||
self.searchController.delegate = (id)self;
|
||||
self.searchController.dimsBackgroundDuringPresentation = NO;
|
||||
if (@available(iOS 9.1, *)) {
|
||||
self.searchController.obscuresBackgroundDuringPresentation = NO;
|
||||
} else {
|
||||
self.searchController.dimsBackgroundDuringPresentation = NO;
|
||||
}
|
||||
self.searchController.hidesNavigationBarDuringPresentation = NO;
|
||||
/// Not necessary in iOS 13; remove this when iOS 13 is the minimum deployment target
|
||||
self.searchController.searchBar.delegate = self;
|
||||
@@ -210,6 +214,8 @@ CGFloat const kFLEXDebounceForExpensiveIO = 0.5;
|
||||
self.tableView.dataSource = self;
|
||||
self.tableView.delegate = self;
|
||||
|
||||
self.tableView.estimatedRowHeight = 10;
|
||||
|
||||
_shareToolbarItem = FLEXBarButtonItemSystem(Action, self, @selector(shareButtonPressed:));
|
||||
_bookmarksToolbarItem = [UIBarButtonItem
|
||||
flex_itemWithImage:FLEXResources.bookmarksIcon target:self action:@selector(showBookmarks)
|
||||
|
||||
@@ -46,7 +46,13 @@
|
||||
UIPickerView *fontsPicker = [UIPickerView new];
|
||||
fontsPicker.dataSource = self;
|
||||
fontsPicker.delegate = self;
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
// Deprecated in iOS 13; from then on, selection is always shown
|
||||
fontsPicker.showsSelectionIndicator = YES;
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
return fontsPicker;
|
||||
}
|
||||
|
||||
|
||||
@@ -466,7 +466,11 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
toolbar.moveItem.selected = self.currentMode == FLEXExplorerModeMove;
|
||||
|
||||
// Recent only enabled when we have a last active tab
|
||||
toolbar.recentItem.enabled = FLEXTabList.sharedList.activeTab != nil;
|
||||
if (!self.presentedViewController) {
|
||||
toolbar.recentItem.enabled = FLEXTabList.sharedList.activeTab != nil;
|
||||
} else {
|
||||
toolbar.recentItem.enabled = NO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -848,31 +852,34 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
#pragma mark - Touch Handling
|
||||
|
||||
- (BOOL)shouldReceiveTouchAtWindowPoint:(CGPoint)pointInWindowCoordinates {
|
||||
BOOL shouldReceiveTouch = NO;
|
||||
|
||||
CGPoint pointInLocalCoordinates = [self.view convertPoint:pointInWindowCoordinates fromView:nil];
|
||||
|
||||
// Always if it's on the toolbar
|
||||
if (CGRectContainsPoint(self.explorerToolbar.frame, pointInLocalCoordinates)) {
|
||||
shouldReceiveTouch = YES;
|
||||
// If we have a modal presented, is it in the modal?
|
||||
if (self.presentedViewController) {
|
||||
UIView *presentedView = self.presentedViewController.view;
|
||||
CGPoint pipvc = [presentedView convertPoint:pointInLocalCoordinates fromView:self.view];
|
||||
UIView *hit = [presentedView hitTest:pipvc withEvent:nil];
|
||||
if (hit != nil) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
// Always if we're in selection mode
|
||||
if (!shouldReceiveTouch && self.currentMode == FLEXExplorerModeSelect) {
|
||||
shouldReceiveTouch = YES;
|
||||
if (self.currentMode == FLEXExplorerModeSelect) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Always in move mode too
|
||||
if (!shouldReceiveTouch && self.currentMode == FLEXExplorerModeMove) {
|
||||
shouldReceiveTouch = YES;
|
||||
if (self.currentMode == FLEXExplorerModeMove) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Always if we have a modal presented
|
||||
if (!shouldReceiveTouch && self.presentedViewController) {
|
||||
shouldReceiveTouch = YES;
|
||||
// Always if it's on the toolbar
|
||||
if (CGRectContainsPoint(self.explorerToolbar.frame, pointInLocalCoordinates)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return shouldReceiveTouch;
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
@@ -918,8 +925,14 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
// up in case we start replacing them again in the future
|
||||
self.appMenuItems = UIMenuController.sharedMenuController.menuItems;
|
||||
|
||||
[self updateButtonStates];
|
||||
|
||||
// Show the view controller
|
||||
[super presentViewController:toPresent animated:animated completion:completion];
|
||||
[super presentViewController:toPresent animated:animated completion:^{
|
||||
[self updateButtonStates];
|
||||
|
||||
if (completion) completion();
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)dismissViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion {
|
||||
@@ -940,7 +953,11 @@ typedef NS_ENUM(NSUInteger, FLEXExplorerMode) {
|
||||
|
||||
[self updateButtonStates];
|
||||
|
||||
[super dismissViewControllerAnimated:animated completion:completion];
|
||||
[super dismissViewControllerAnimated:animated completion:^{
|
||||
[self updateButtonStates];
|
||||
|
||||
if (completion) completion();
|
||||
}];
|
||||
}
|
||||
|
||||
- (BOOL)wantsWindowToBecomeKey {
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
// Some apps have windows at UIWindowLevelStatusBar + n.
|
||||
// If we make the window level too high, we block out UIAlertViews.
|
||||
// There's a balance between staying above the app's windows and staying below alerts.
|
||||
// UIWindowLevelStatusBar + 100 seems to hit that balance.
|
||||
self.windowLevel = UIWindowLevelStatusBar + 100.0;
|
||||
self.windowLevel = UIWindowLevelAlert - 1;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -93,16 +93,37 @@
|
||||
}
|
||||
|
||||
- (void)queryButtonPressed {
|
||||
[self showQueryInput:nil];
|
||||
}
|
||||
|
||||
- (void)showQueryInput:(NSString *)prefillQuery {
|
||||
FLEXSQLiteDatabaseManager *database = self.dbm;
|
||||
|
||||
[FLEXAlert makeAlert:^(FLEXAlert *make) {
|
||||
make.title(@"Execute an SQL query");
|
||||
make.textField(nil);
|
||||
make.configuredTextField(^(UITextField *textField) {
|
||||
textField.text = prefillQuery;
|
||||
});
|
||||
|
||||
make.button(@"Run").handler(^(NSArray<NSString *> *strings) {
|
||||
FLEXSQLResult *result = [database executeStatement:strings[0]];
|
||||
NSString *query = strings[0];
|
||||
FLEXSQLResult *result = [database executeStatement:query];
|
||||
|
||||
if (result.message) {
|
||||
[FLEXAlert showAlert:@"Message" message:result.message from:self];
|
||||
// Allow users to edit their last query if it had an error
|
||||
if ([result.message containsString:@"error"]) {
|
||||
[FLEXAlert makeAlert:^(FLEXAlert *make) {
|
||||
make.title(@"Error").message(result.message);
|
||||
make.button(@"Edit Query").preferred().handler(^(NSArray<NSString *> *_) {
|
||||
// Show query editor again with our last input
|
||||
[self showQueryInput:query];
|
||||
});
|
||||
|
||||
make.button(@"Cancel").cancelStyle();
|
||||
} showFrom:self];
|
||||
} else {
|
||||
[FLEXAlert showAlert:@"Message" message:result.message from:self];
|
||||
}
|
||||
} else {
|
||||
UIViewController *resultsScreen = [FLEXTableContentViewController
|
||||
columns:result.columns rows:result.rows
|
||||
|
||||
@@ -158,7 +158,7 @@ typedef NS_ENUM(NSUInteger, FLEXObjectReferenceSection) {
|
||||
}
|
||||
|
||||
+ (instancetype)subclassesOfClassWithName:(NSString *)className {
|
||||
NSArray<FLEXObjectRef *> *references = [FLEXHeapEnumerator subclassesOfClassWithName:className];
|
||||
NSArray<FLEXObjectRef *> *references = [FLEXRuntimeUtility subclassesOfClassWithName:className];
|
||||
FLEXObjectListViewController *controller = [[self alloc] initWithReferences:references];
|
||||
controller.title = [NSString stringWithFormat:@"Subclasses of %@ (%@)",
|
||||
className, @(references.count)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#import "FLEXTableViewController.h"
|
||||
#import "FLEXGlobalsEntry.h"
|
||||
#import "FLEXFileBrowserSearchOperation.h"
|
||||
|
||||
@interface FLEXFileBrowserController : FLEXTableViewController <FLEXGlobalsEntry>
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#import "FLEXObjectExplorerFactory.h"
|
||||
#import "FLEXObjectExplorerViewController.h"
|
||||
#import <mach-o/loader.h>
|
||||
#import "FLEXFileBrowserSearchOperation.h"
|
||||
|
||||
@interface FLEXFileBrowserTableViewCell : UITableViewCell
|
||||
@end
|
||||
@@ -265,14 +266,19 @@ typedef NS_ENUM(NSUInteger, FLEXFileBrowserSortAttribute) {
|
||||
if ([pathExtension isEqualToString:@"json"]) {
|
||||
prettyString = [FLEXUtility prettyJSONStringFromData:fileData];
|
||||
} else {
|
||||
// Regardless of file extension...
|
||||
|
||||
id object = nil;
|
||||
@try {
|
||||
// Try to decode an archived object regardless of file extension
|
||||
object = [NSKeyedUnarchiver unarchiveObjectWithData:fileData];
|
||||
} @catch (NSException *e) { }
|
||||
|
||||
// Try to decode an archived object, regardless of file extension
|
||||
NSKeyedUnarchiver *unarchiver = ({
|
||||
NSKeyedUnarchiver *obj = nil;
|
||||
if (@available(iOS 12.0, *)) {
|
||||
obj = [[NSKeyedUnarchiver alloc] initForReadingFromData:fileData error:nil];
|
||||
} else {
|
||||
obj = [[NSKeyedUnarchiver alloc] initForReadingWithData:fileData];
|
||||
}
|
||||
obj.requiresSecureCoding = NO;
|
||||
obj;
|
||||
});
|
||||
id object = [unarchiver decodeObjectForKey:NSKeyedArchiveRootObjectKey];
|
||||
|
||||
// Try to decode other things instead
|
||||
object = object ?: [NSPropertyListSerialization
|
||||
propertyListWithData:fileData
|
||||
|
||||
@@ -28,25 +28,26 @@
|
||||
if (status == errSecSuccess) {//item already exists, update it!
|
||||
query = [[NSMutableDictionary alloc]init];
|
||||
query[(__bridge id)kSecValueData] = self.passwordData;
|
||||
#if __IPHONE_4_0 && TARGET_OS_IPHONE
|
||||
#if __IPHONE_4_0 && TARGET_OS_IPHONE
|
||||
CFTypeRef accessibilityType = FLEXKeychain.accessibilityType;
|
||||
if (accessibilityType) {
|
||||
query[(__bridge id)kSecAttrAccessible] = (__bridge id)accessibilityType;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
status = SecItemUpdate((__bridge CFDictionaryRef)(searchQuery), (__bridge CFDictionaryRef)(query));
|
||||
}else if (status == errSecItemNotFound){//item not found, create it!
|
||||
}
|
||||
else if (status == errSecItemNotFound){//item not found, create it!
|
||||
query = [self query];
|
||||
if (self.label) {
|
||||
query[(__bridge id)kSecAttrLabel] = self.label;
|
||||
}
|
||||
query[(__bridge id)kSecValueData] = self.passwordData;
|
||||
#if __IPHONE_4_0 && TARGET_OS_IPHONE
|
||||
#if __IPHONE_4_0 && TARGET_OS_IPHONE
|
||||
CFTypeRef accessibilityType = FLEXKeychain.accessibilityType;
|
||||
if (accessibilityType) {
|
||||
query[(__bridge id)kSecAttrAccessible] = (__bridge id)accessibilityType;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
|
||||
}
|
||||
|
||||
@@ -69,9 +70,9 @@
|
||||
}
|
||||
|
||||
NSMutableDictionary *query = [self query];
|
||||
#if TARGET_OS_IPHONE
|
||||
#if TARGET_OS_IPHONE
|
||||
status = SecItemDelete((__bridge CFDictionaryRef)query);
|
||||
#else
|
||||
#else
|
||||
// On Mac OS, SecItemDelete will not delete a key created in a different
|
||||
// app, nor in a different version of the same app.
|
||||
//
|
||||
@@ -88,7 +89,7 @@
|
||||
status = SecKeychainItemDelete((SecKeychainItemRef)result);
|
||||
CFRelease(result);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (status != errSecSuccess && error != NULL) {
|
||||
*error = [self errorWithCode:status];
|
||||
@@ -102,12 +103,12 @@
|
||||
NSMutableDictionary *query = [self query];
|
||||
query[(__bridge id)kSecReturnAttributes] = @YES;
|
||||
query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;
|
||||
#if __IPHONE_4_0 && TARGET_OS_IPHONE
|
||||
#if __IPHONE_4_0 && TARGET_OS_IPHONE
|
||||
CFTypeRef accessibilityType = FLEXKeychain.accessibilityType;
|
||||
if (accessibilityType) {
|
||||
query[(__bridge id)kSecAttrAccessible] = (__bridge id)accessibilityType;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
CFTypeRef result = NULL;
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
|
||||
@@ -149,19 +150,6 @@
|
||||
|
||||
#pragma mark - Accessors
|
||||
|
||||
- (void)setPasswordObject:(id<NSCoding>)object {
|
||||
self.passwordData = [NSKeyedArchiver archivedDataWithRootObject:object];
|
||||
}
|
||||
|
||||
|
||||
- (id<NSCoding>)passwordObject {
|
||||
if (self.passwordData.length) {
|
||||
return [NSKeyedUnarchiver unarchiveObjectWithData:self.passwordData];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (void)setPassword:(NSString *)password {
|
||||
self.passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
|
||||
@@ -181,11 +169,11 @@
|
||||
|
||||
#ifdef FLEXKEYCHAIN_SYNCHRONIZATION_AVAILABLE
|
||||
+ (BOOL)isSynchronizationAvailable {
|
||||
#if TARGET_OS_IPHONE
|
||||
#if TARGET_OS_IPHONE
|
||||
return YES;
|
||||
#else
|
||||
#else
|
||||
return floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_8_4;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -204,15 +192,15 @@
|
||||
dictionary[(__bridge id)kSecAttrAccount] = self.account;
|
||||
}
|
||||
|
||||
#ifdef FLEXKEYCHAIN_ACCESS_GROUP_AVAILABLE
|
||||
#if !TARGET_IPHONE_SIMULATOR
|
||||
#ifdef FLEXKEYCHAIN_ACCESS_GROUP_AVAILABLE
|
||||
#if !TARGET_IPHONE_SIMULATOR
|
||||
if (self.accessGroup) {
|
||||
dictionary[(__bridge id)kSecAttrAccessGroup] = self.accessGroup;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef FLEXKEYCHAIN_SYNCHRONIZATION_AVAILABLE
|
||||
#ifdef FLEXKEYCHAIN_SYNCHRONIZATION_AVAILABLE
|
||||
if ([[self class] isSynchronizationAvailable]) {
|
||||
id value;
|
||||
|
||||
@@ -233,7 +221,7 @@
|
||||
|
||||
dictionary[(__bridge id)(kSecAttrSynchronizable)] = value;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
@@ -251,7 +239,7 @@
|
||||
case errSecSuccess: return nil;
|
||||
case FLEXKeychainErrorBadArguments: message = NSLocalizedStringFromTableInBundle(@"FLEXKeychainErrorBadArguments", @"FLEXKeychain", resourcesBundle, nil); break;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#if TARGET_OS_IPHONE
|
||||
case errSecUnimplemented: {
|
||||
message = NSLocalizedStringFromTableInBundle(@"errSecUnimplemented", @"FLEXKeychain", resourcesBundle, nil);
|
||||
break;
|
||||
@@ -291,10 +279,10 @@
|
||||
default: {
|
||||
message = NSLocalizedStringFromTableInBundle(@"errSecDefault", @"FLEXKeychain", resourcesBundle, nil);
|
||||
}
|
||||
#else
|
||||
#else
|
||||
default:
|
||||
message = (__bridge_transfer NSString *)SecCopyErrorMessageString(code, NULL);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
NSDictionary *userInfo = message ? @{ NSLocalizedDescriptionKey : message } : nil;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../../Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserController.h
|
||||
@@ -290,7 +290,8 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
postBodyRow.selectionFuture = ^UIViewController * () {
|
||||
// Show the body if we can
|
||||
NSString *contentType = [transaction.request valueForHTTPHeaderField:@"Content-Type"];
|
||||
UIViewController *detailViewController = [self detailViewControllerForMIMEType:contentType data:[self postBodyDataForTransaction:transaction]];
|
||||
NSData *body = [self postBodyDataForTransaction:transaction];
|
||||
UIViewController *detailViewController = [self detailViewControllerForMIMEType:contentType data:body];
|
||||
if (detailViewController) {
|
||||
detailViewController.title = @"Request Body";
|
||||
return detailViewController;
|
||||
@@ -298,8 +299,13 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
// We can't show the body, alert user
|
||||
return [FLEXAlert makeAlert:^(FLEXAlert *make) {
|
||||
make.title(@"Can't View HTTP Body Data");
|
||||
make.message(@"FLEX does not have a viewer for request body data with MIME type: ");
|
||||
if (!body) {
|
||||
make.title(@"Empty HTTP Body");
|
||||
} else {
|
||||
make.title(@"Cannot View HTTP Body Data");
|
||||
make.message(@"FLEX does not have a viewer for request body data with MIME type: ");
|
||||
}
|
||||
|
||||
make.message(contentType);
|
||||
make.button(@"Dismiss").cancelStyle();
|
||||
}];
|
||||
@@ -482,6 +488,10 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
}
|
||||
|
||||
+ (UIViewController *)detailViewControllerForMIMEType:(NSString *)mimeType data:(NSData *)data {
|
||||
if (!data) {
|
||||
return nil; // An alert will be presented in place of this screen
|
||||
}
|
||||
|
||||
FLEXCustomContentViewerFuture makeCustomViewer = FLEXManager.sharedManager.customContentTypeViewers[mimeType.lowercaseString];
|
||||
|
||||
if (makeCustomViewer) {
|
||||
@@ -519,11 +529,8 @@ typedef UIViewController *(^FLEXNetworkDetailRowSelectionFuture)(void);
|
||||
|
||||
+ (NSData *)postBodyDataForTransaction:(FLEXHTTPTransaction *)transaction {
|
||||
NSData *bodyData = transaction.cachedRequestBody;
|
||||
if (bodyData.length > 0) {
|
||||
NSString *contentEncoding = [transaction.request valueForHTTPHeaderField:@"Content-Encoding"];
|
||||
if ([contentEncoding rangeOfString:@"deflate" options:NSCaseInsensitiveSearch].length > 0 || [contentEncoding rangeOfString:@"gzip" options:NSCaseInsensitiveSearch].length > 0) {
|
||||
bodyData = [FLEXUtility inflatedDataFromCompressedData:bodyData];
|
||||
}
|
||||
if (bodyData.length > 0 && [FLEXUtility hasCompressedContentEncoding:transaction.request]) {
|
||||
bodyData = [FLEXUtility inflatedDataFromCompressedData:bodyData];
|
||||
}
|
||||
return bodyData;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
#import "FLEXNetworkCurlLogger.h"
|
||||
#import "FLEXUtility.h"
|
||||
|
||||
@implementation FLEXNetworkCurlLogger
|
||||
|
||||
@@ -28,8 +29,22 @@
|
||||
}
|
||||
|
||||
if (request.HTTPBody) {
|
||||
NSString *body = [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
|
||||
[curlCommandString appendFormat:@"-d \'%@\'", body];
|
||||
NSData *bodyData = request.HTTPBody;
|
||||
if ([FLEXUtility hasCompressedContentEncoding:request]) {
|
||||
bodyData = [FLEXUtility inflatedDataFromCompressedData:bodyData];
|
||||
}
|
||||
NSString *body = [[NSString alloc] initWithData:bodyData encoding:NSUTF8StringEncoding];
|
||||
|
||||
if (body != nil) {
|
||||
[curlCommandString appendFormat:@"-d \'%@\'", body];
|
||||
} else {
|
||||
// Fallback to using base64 encoding
|
||||
[curlCommandString appendString:@"--data-binary @-"];
|
||||
|
||||
NSString *base64 = [request.HTTPBody base64EncodedStringWithOptions:0];
|
||||
NSString *prefix = [NSString stringWithFormat:@"echo -n '%@' | base64 -D | ", base64];
|
||||
[curlCommandString insertString:prefix atIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
return curlCommandString;
|
||||
|
||||
@@ -332,13 +332,13 @@ typedef NS_ENUM(NSInteger, FLEXNetworkObserverMode) {
|
||||
make.title(@"Network Monitor Disabled");
|
||||
make.message(@"You must enable network monitoring to proceed.");
|
||||
|
||||
make.button(@"Turn On").handler(^(NSArray<NSString *> *strings) {
|
||||
make.button(@"Turn On").preferred().handler(^(NSArray<NSString *> *strings) {
|
||||
FLEXNetworkObserver.enabled = YES;
|
||||
[host.navigationController pushViewController:[
|
||||
self globalsEntryViewController:row
|
||||
] animated:YES];
|
||||
}).cancelStyle();
|
||||
make.button(@"Dismiss");
|
||||
});
|
||||
make.button(@"Dismiss").cancelStyle();
|
||||
} showFrom:host];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -90,7 +90,7 @@ typedef NS_ENUM(NSUInteger, FLEXWebsocketMessageDirection) {
|
||||
@property (nonatomic) NSTimeInterval latency;
|
||||
@property (nonatomic) NSTimeInterval duration;
|
||||
|
||||
/// Populated lazily. Handles both normal HTTPBody data and HTTPBodyStreams.
|
||||
/// Populated lazily, nullable. Handles both normal HTTPBody data and HTTPBodyStreams.
|
||||
@property (nonatomic, readonly) NSData *cachedRequestBody;
|
||||
|
||||
@end
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#import "FLEXMethod.h"
|
||||
#import "Firestore.h"
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
#import <dispatch/queue.h>
|
||||
@@ -237,7 +238,9 @@ static void _logos_method$_ungrouped$FIRDocumentReference$getDocumentWithComplet
|
||||
FIRDocumentSnapshotBlock orig = completion;
|
||||
completion = ^(FIRDocumentSnapshot *document, NSError *error) {
|
||||
[FLEXNetworkRecorder.defaultRecorder recordFIRDocumentDidFetch:document error:error transactionID:requestID];
|
||||
orig(document, error);
|
||||
if (orig != nil) {
|
||||
orig(document, error);
|
||||
}
|
||||
};
|
||||
|
||||
// Forward invocation
|
||||
@@ -256,7 +259,9 @@ static void _logos_method$_ungrouped$FIRQuery$getDocumentsWithCompletion$(
|
||||
FIRQuerySnapshotBlock orig = completion;
|
||||
completion = ^(FIRQuerySnapshot *query, NSError *error) {
|
||||
[FLEXNetworkRecorder.defaultRecorder recordFIRQueryDidFetch:query error:error transactionID:requestID];
|
||||
orig(query, error);
|
||||
if (orig != nil) {
|
||||
orig(query, error);
|
||||
}
|
||||
};
|
||||
|
||||
// Forward invocation
|
||||
@@ -285,7 +290,9 @@ static void _logos_method$_ungrouped$FIRDocumentReference$setData$merge$completi
|
||||
void (^orig)(NSError *) = completion;
|
||||
completion = ^(NSError *error) {
|
||||
[FLEXNetworkRecorder.defaultRecorder recordFIRDidSetData:error transactionID:requestID];
|
||||
orig(error);
|
||||
if (orig != nil) {
|
||||
orig(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Forward invocation
|
||||
@@ -313,7 +320,9 @@ static void _logos_method$_ungrouped$FIRDocumentReference$setData$mergeFields$co
|
||||
void (^orig)(NSError *) = completion;
|
||||
completion = ^(NSError *error) {
|
||||
[FLEXNetworkRecorder.defaultRecorder recordFIRDidSetData:error transactionID:requestID];
|
||||
orig(error);
|
||||
if (orig != nil) {
|
||||
orig(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Forward invocation
|
||||
@@ -333,7 +342,9 @@ static void _logos_method$_ungrouped$FIRDocumentReference$updateData$completion$
|
||||
void (^orig)(NSError *) = completion;
|
||||
completion = ^(NSError *error) {
|
||||
[FLEXNetworkRecorder.defaultRecorder recordFIRDidUpdateData:error transactionID:requestID];
|
||||
orig(error);
|
||||
if (orig != nil) {
|
||||
orig(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Forward invocation
|
||||
@@ -353,7 +364,9 @@ static void _logos_method$_ungrouped$FIRDocumentReference$deleteDocumentWithComp
|
||||
void (^orig)(NSError *) = completion;
|
||||
completion = ^(NSError *error) {
|
||||
[FLEXNetworkRecorder.defaultRecorder recordFIRDidDeleteDocument:error transactionID:requestID];
|
||||
orig(error);
|
||||
if (orig != nil) {
|
||||
orig(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Forward invocation
|
||||
@@ -371,7 +384,9 @@ static FIRDocumentReference * _logos_method$_ungrouped$FIRCollectionReference$ad
|
||||
void (^orig)(NSError *) = completion;
|
||||
completion = ^(NSError *error) {
|
||||
[FLEXNetworkRecorder.defaultRecorder recordFIRDidAddDocument:error transactionID:requestID];
|
||||
orig(error);
|
||||
if (orig != nil) {
|
||||
orig(error);
|
||||
}
|
||||
};
|
||||
|
||||
// Forward invocation
|
||||
@@ -652,15 +667,22 @@ static FIRDocumentReference * _logos_method$_ungrouped$FIRCollectionReference$ad
|
||||
Method originalResume = class_getInstanceMethod(class, selector);
|
||||
IMP implementation = imp_implementationWithBlock(^(NSURLSessionTask *slf) {
|
||||
|
||||
// iOS's internal HTTP parser finalization code is mysteriously not thread safe,
|
||||
// invoking it asynchronously has a chance to cause a `double free` crash.
|
||||
// This line below will ask for HTTPBody synchronously, make the HTTPParser
|
||||
// parse the request, and cache them in advance. After that the HTTPParser
|
||||
// will be finalized. Make sure other threads inspecting the request
|
||||
// won't trigger a race to finalize the parser.
|
||||
[slf.currentRequest HTTPBody];
|
||||
if (@available(iOS 11.0, *)) {
|
||||
// AVAggregateAssetDownloadTask deeply does not like to be looked at. Accessing -currentRequest or
|
||||
// -originalRequest will crash. Do not try to observe these. https://github.com/FLEXTool/FLEX/issues/276
|
||||
if (![slf isKindOfClass:[AVAggregateAssetDownloadTask class]]) {
|
||||
// iOS's internal HTTP parser finalization code is mysteriously not thread safe,
|
||||
// invoking it asynchronously has a chance to cause a `double free` crash.
|
||||
// This line below will ask for HTTPBody synchronously, make the HTTPParser
|
||||
// parse the request, and cache them in advance. After that the HTTPParser
|
||||
// will be finalized. Make sure other threads inspecting the request
|
||||
// won't trigger a race to finalize the parser.
|
||||
[slf.currentRequest HTTPBody];
|
||||
|
||||
[FLEXNetworkObserver.sharedObserver URLSessionTaskWillResume:slf];
|
||||
}
|
||||
}
|
||||
|
||||
[FLEXNetworkObserver.sharedObserver URLSessionTaskWillResume:slf];
|
||||
((void(*)(id, SEL))objc_msgSend)(
|
||||
slf, swizzledSelector
|
||||
);
|
||||
@@ -1881,6 +1903,12 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
NSString *requestID = [[self class] requestIDForConnectionOrTask:dataTask];
|
||||
FLEXInternalRequestState *requestState = [self requestStateForRequestID:requestID];
|
||||
|
||||
// Fix for "Response body not in cache" issue reported by developers
|
||||
// See this github comment for detailed explanation on why this happens
|
||||
// https://github.com/FLEXTool/FLEX/issues/568#issuecomment-1141015572
|
||||
if (requestState.dataAccumulator == nil) {
|
||||
requestState.dataAccumulator = [NSMutableData new];
|
||||
}
|
||||
[requestState.dataAccumulator appendData:data];
|
||||
|
||||
[FLEXNetworkRecorder.defaultRecorder
|
||||
@@ -1959,6 +1987,14 @@ didFinishDownloadingToURL:(NSURL *)location data:(NSData *)data
|
||||
}
|
||||
|
||||
- (void)URLSessionTaskWillResume:(NSURLSessionTask *)task {
|
||||
if (@available(iOS 11.0, *)) {
|
||||
// AVAggregateAssetDownloadTask deeply does not like to be looked at. Accessing -currentRequest or
|
||||
// -originalRequest will crash. Do not try to observe these. https://github.com/FLEXTool/FLEX/issues/276
|
||||
if ([task isKindOfClass:[AVAggregateAssetDownloadTask class]]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Since resume can be called multiple times on the same task, only treat the first resume as
|
||||
// the equivalent to connection:willSendRequest:...
|
||||
[self performBlock:^{
|
||||
|
||||
@@ -353,6 +353,10 @@
|
||||
if ([names containsObject:name]) {
|
||||
return NO;
|
||||
} else {
|
||||
if (!name) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
[names addObject:name];
|
||||
|
||||
// Skip methods and properties which are just overrides,
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
});
|
||||
|
||||
make.button(@"OK").handler(^(NSArray<NSString *> *strings) {
|
||||
CGFloat speedValue = strings.firstObject.floatValue;
|
||||
NSNumberFormatter *formatter = [NSNumberFormatter new];
|
||||
formatter.numberStyle = NSNumberFormatterDecimalStyle;
|
||||
CGFloat speedValue = [formatter numberFromString:strings.firstObject].floatValue;
|
||||
window.layer.speed = speedValue;
|
||||
|
||||
// Refresh the host view controller to update the shortcut subtitle, reflecting current speed
|
||||
|
||||
@@ -71,8 +71,11 @@ typedef FLEXAlertAction * _Nonnull (^FLEXAlertActionHandler)(void(^handler)(NSAr
|
||||
@property (nonatomic, readonly) FLEXAlertActionStringProperty title;
|
||||
/// Make the action destructive. It appears with red text.
|
||||
@property (nonatomic, readonly) FLEXAlertActionProperty destructiveStyle;
|
||||
/// Make the action cancel-style. It appears with a bolder font.
|
||||
/// Make the action cancel-style. It sometimes appears with a bolder font.
|
||||
@property (nonatomic, readonly) FLEXAlertActionProperty cancelStyle;
|
||||
/// Make the action the preferred action. It appears with a bolder font.
|
||||
/// The first action that is set as preferred will be used as the preferred action.
|
||||
@property (nonatomic, readonly) FLEXAlertActionProperty preferred;
|
||||
/// Enable or disable the action. Enabled by default.
|
||||
@property (nonatomic, readonly) FLEXAlertActionBOOLProperty enabled;
|
||||
/// Give the button an action. The action takes an array of text field strings.
|
||||
|
||||
@@ -22,6 +22,7 @@ NSAssert(!self._action, @"Cannot mutate action after retreiving underlying UIAle
|
||||
@property (nonatomic) NSString *_title;
|
||||
@property (nonatomic) UIAlertActionStyle _style;
|
||||
@property (nonatomic) BOOL _disable;
|
||||
@property (nonatomic) BOOL _isPreferred;
|
||||
@property (nonatomic) void(^_handler)(UIAlertAction *action);
|
||||
@property (nonatomic) UIAlertAction *_action;
|
||||
@end
|
||||
@@ -72,7 +73,18 @@ NSAssert(!self._action, @"Cannot mutate action after retreiving underlying UIAle
|
||||
[alert._controller addAction:builder.action];
|
||||
}
|
||||
|
||||
return alert._controller;
|
||||
UIAlertController *controller = alert._controller;
|
||||
|
||||
// Set preferred action on alert controller
|
||||
for (FLEXAlertAction *builder in alert._actions) {
|
||||
UIAlertAction *action = builder.action;
|
||||
if (builder._isPreferred) {
|
||||
controller.preferredAction = action;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
+ (void)make:(FLEXAlertBuilder)block
|
||||
@@ -203,6 +215,14 @@ NSAssert(!self._action, @"Cannot mutate action after retreiving underlying UIAle
|
||||
};
|
||||
}
|
||||
|
||||
- (FLEXAlertActionProperty)preferred {
|
||||
return ^FLEXAlertAction *() {
|
||||
FLEXAlertActionMutationAssertion();
|
||||
self._isPreferred = YES;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
- (FLEXAlertActionBOOLProperty)enabled {
|
||||
return ^FLEXAlertAction *(BOOL enabled) {
|
||||
FLEXAlertActionMutationAssertion();
|
||||
|
||||
@@ -9,17 +9,46 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
@class FLEXObjectRef;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^flex_object_enumeration_block_t)(__unsafe_unretained id object, __unsafe_unretained Class actualClass);
|
||||
|
||||
/// Counts and identifies all class instances on the heap.
|
||||
@interface FLEXHeapSnapshot : NSObject
|
||||
|
||||
/// The names of every class instance discovered on the heap.
|
||||
@property (nonatomic, readonly) NSArray<NSString *> *classNames;
|
||||
/// A mapping of instance counts to class names.
|
||||
@property (nonatomic, readonly) NSDictionary<NSString *, NSNumber *> *instanceCountsForClassNames;
|
||||
/// A mapping of class instance size to class name.
|
||||
///
|
||||
/// To roughly calculate the memory usage of an entire class, multiply this number by the instance count.
|
||||
@property (nonatomic, readonly) NSDictionary<NSString *, NSNumber *> *instanceSizesForClassNames;
|
||||
|
||||
@end
|
||||
|
||||
@interface FLEXHeapEnumerator : NSObject
|
||||
|
||||
+ (void)enumerateLiveObjectsUsingBlock:(flex_object_enumeration_block_t)block;
|
||||
/// Use carefully; this method puts a global lock on the heap in between callbacks.
|
||||
///
|
||||
/// Inspired by:
|
||||
/// [heap_find.cpp](https://llvm.org/svn/llvm-project/lldb/tags/RELEASE_34/final/examples/darwin/heap_find/heap/heap_find.cpp)
|
||||
/// and [samdmarshall](https://gist.github.com/samdmarshall/17f4e66b5e2e579fd396)
|
||||
+ (void)enumerateLiveObjectsUsingBlock:(flex_object_enumeration_block_t)callback
|
||||
NS_SWIFT_UNAVAILABLE("Use one of the other methods instead.");
|
||||
|
||||
/// Returned references are not validated beyond containing a valid isa.
|
||||
/// To validate them yourself, pass each reference's object to \c FLEXPointerIsValidObjcObject
|
||||
+ (NSArray<FLEXObjectRef *> *)instancesOfClassWithName:(NSString *)className retained:(BOOL)retain;
|
||||
+ (NSArray<FLEXObjectRef *> *)subclassesOfClassWithName:(NSString *)className;
|
||||
|
||||
/// Returned references have been validated via \c FLEXPointerIsValidObjcObject
|
||||
/// @param object the object to find references to
|
||||
/// @param retain whether to retain the objects referencing \c object
|
||||
+ (NSArray<FLEXObjectRef *> *)objectsWithReferencesToObject:(id)object retained:(BOOL)retain;
|
||||
|
||||
/// Capture all live objects on the heap and do with this information what you will.
|
||||
+ (FLEXHeapSnapshot *)generateHeapSnapshot;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -22,6 +22,18 @@ typedef struct {
|
||||
Class isa;
|
||||
} flex_maybe_object_t;
|
||||
|
||||
@implementation FLEXHeapSnapshot
|
||||
+ (instancetype)snapshotWithCounts:(NSDictionary<NSString *, NSNumber *> *)counts
|
||||
sizes:(NSDictionary<NSString *, NSNumber *> *)sizes {
|
||||
FLEXHeapSnapshot *snapshot = [FLEXHeapSnapshot new];
|
||||
snapshot->_classNames = counts.allKeys;
|
||||
snapshot->_instanceCountsForClassNames = counts;
|
||||
snapshot->_instanceSizesForClassNames = sizes;
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation FLEXHeapEnumerator
|
||||
|
||||
static void range_callback(task_t task, void *context, unsigned type, vm_range_t *ranges, unsigned rangeCount) {
|
||||
@@ -138,12 +150,6 @@ static kern_return_t reader(__unused task_t remote_task, vm_address_t remote_add
|
||||
return references;
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXObjectRef *> *)subclassesOfClassWithName:(NSString *)className {
|
||||
NSArray<Class> *classes = FLEXGetAllSubclasses(NSClassFromString(className), NO);
|
||||
NSArray<FLEXObjectRef *> *references = [FLEXObjectRef referencingClasses:classes];
|
||||
return references;
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXObjectRef *> *)objectsWithReferencesToObject:(id)object retained:(BOOL)retain {
|
||||
NSMutableArray<FLEXObjectRef *> *instances = [NSMutableArray new];
|
||||
[FLEXHeapEnumerator enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id tryObject, __unsafe_unretained Class actualClass) {
|
||||
@@ -185,4 +191,48 @@ static kern_return_t reader(__unused task_t remote_task, vm_address_t remote_add
|
||||
return instances;
|
||||
}
|
||||
|
||||
+ (FLEXHeapSnapshot *)generateHeapSnapshot {
|
||||
// Set up a CFMutableDictionary with class pointer keys and NSUInteger values.
|
||||
// We abuse CFMutableDictionary a little to have primitive keys through judicious casting, but it gets the job done.
|
||||
// The dictionary is intialized with a 0 count for each class so that it doesn't have to expand during enumeration.
|
||||
// While it might be a little cleaner to populate an NSMutableDictionary with class name string keys to NSNumber
|
||||
// counts, we choose the CF/primitives approach because it lets us enumerate the objects in the heap without
|
||||
// allocating any memory during enumeration. The alternative of creating one NSString/NSNumber per object
|
||||
// on the heap ends up polluting the count of live objects quite a bit.
|
||||
unsigned int classCount = 0;
|
||||
Class *classes = objc_copyClassList(&classCount);
|
||||
CFMutableDictionaryRef mutableCountsForClasses = CFDictionaryCreateMutable(NULL, classCount, NULL, NULL);
|
||||
for (unsigned int i = 0; i < classCount; i++) {
|
||||
CFDictionarySetValue(mutableCountsForClasses, (__bridge const void *)classes[i], (const void *)0);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
NSUInteger instanceCount = (NSUInteger)CFDictionaryGetValue(
|
||||
mutableCountsForClasses, (__bridge const void *)cls
|
||||
);
|
||||
instanceCount++;
|
||||
CFDictionarySetValue(
|
||||
mutableCountsForClasses, (__bridge const void *)cls, (const void *)instanceCount
|
||||
);
|
||||
}];
|
||||
|
||||
// Convert our CF primitive dictionary into a nicer mapping of class name strings to instance counts
|
||||
NSMutableDictionary<NSString *, NSNumber *> *countsForClassNames = [NSMutableDictionary new];
|
||||
NSMutableDictionary<NSString *, NSNumber *> *sizesForClassNames = [NSMutableDictionary new];
|
||||
for (unsigned int i = 0; i < classCount; i++) {
|
||||
Class class = classes[i];
|
||||
NSUInteger instanceCount = (NSUInteger)CFDictionaryGetValue(mutableCountsForClasses, (__bridge const void *)(class));
|
||||
NSString *className = @(class_getName(class));
|
||||
|
||||
if (instanceCount > 0) {
|
||||
countsForClassNames[className] = @(instanceCount);
|
||||
sizesForClassNames[className] = @(class_getInstanceSize(class));
|
||||
}
|
||||
}
|
||||
free(classes);
|
||||
|
||||
return [FLEXHeapSnapshot snapshotWithCounts:countsForClassNames sizes:sizesForClassNames];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
+ (NSString *)prettyJSONStringFromData:(NSData *)data;
|
||||
+ (BOOL)isValidJSONData:(NSData *)data;
|
||||
+ (NSData *)inflatedDataFromCompressedData:(NSData *)compressedData;
|
||||
+ (BOOL)hasCompressedContentEncoding:(NSURLRequest *)request;
|
||||
|
||||
// Swizzling utilities
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#import <objc/runtime.h>
|
||||
#import <zlib.h>
|
||||
|
||||
BOOL FLEXConstructorsShouldRun() {
|
||||
BOOL FLEXConstructorsShouldRun(void) {
|
||||
#if FLEX_DISABLE_CTORS
|
||||
return NO;
|
||||
#else
|
||||
@@ -100,8 +100,9 @@ BOOL FLEXConstructorsShouldRun() {
|
||||
description = [description stringByAppendingFormat:@" %@", [self stringForCGRect:view.frame]];
|
||||
}
|
||||
|
||||
if (view.accessibilityLabel.length > 0) {
|
||||
description = [description stringByAppendingFormat:@" · %@", view.accessibilityLabel];
|
||||
if (view.accessibilityLabel.length > 0 || view.accessibilityIdentifier.length > 0) {
|
||||
description = [description stringByAppendingFormat:@" · %@",
|
||||
view.accessibilityLabel.length > 0 ? view.accessibilityLabel : view.accessibilityIdentifier];
|
||||
}
|
||||
|
||||
return description;
|
||||
@@ -412,6 +413,11 @@ BOOL FLEXConstructorsShouldRun() {
|
||||
return inflatedData;
|
||||
}
|
||||
|
||||
+ (BOOL)hasCompressedContentEncoding:(NSURLRequest *)request {
|
||||
NSString *contentEncoding = [request valueForHTTPHeaderField:@"Content-Encoding"];
|
||||
return ([contentEncoding rangeOfString:@"deflate" options:NSCaseInsensitiveSearch].length > 0 || [contentEncoding rangeOfString:@"gzip" options:NSCaseInsensitiveSearch].length > 0);
|
||||
}
|
||||
|
||||
+ (NSArray<UIWindow *> *)allWindows {
|
||||
BOOL includeInternalWindows = YES;
|
||||
BOOL onlyVisibleWindows = NO;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
self.textView.backgroundColor = UIColor.blackColor;
|
||||
self.textView.textColor = UIColor.whiteColor;
|
||||
self.textView.font = [UIFont boldSystemFontOfSize:14.0];
|
||||
self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
|
||||
self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
|
||||
|
||||
self.title = @"Simulator Shortcuts";
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(donePressed:)];
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
#import "FLEXRuntimeConstants.h"
|
||||
@class FLEXObjectRef;
|
||||
|
||||
#define PropertyKey(suffix) kFLEXPropertyAttributeKey##suffix : @""
|
||||
#define PropertyKeyGetter(getter) kFLEXPropertyAttributeKeyCustomGetter : NSStringFromSelector(@selector(getter))
|
||||
@@ -45,7 +46,9 @@ typedef NS_ENUM(NSInteger, FLEXRuntimeUtilityErrorCode) {
|
||||
|
||||
@interface FLEXRuntimeUtility : NSObject
|
||||
|
||||
// General Helpers
|
||||
#pragma mark - General Helpers
|
||||
|
||||
/// Calls into \c FLEXPointerIsValidObjcObject()
|
||||
+ (BOOL)pointerIsValidObjcObject:(const void *)pointer;
|
||||
/// Unwraps raw pointers to objects stored in NSValue, and re-boxes C strings into NSStrings.
|
||||
+ (id)potentiallyUnwrapBoxedPointer:(id)returnedObjectOrNil type:(const FLEXTypeEncoding *)returnType;
|
||||
@@ -59,6 +62,8 @@ typedef NS_ENUM(NSInteger, FLEXRuntimeUtilityErrorCode) {
|
||||
/// @return The class hierarchy for the given object or class,
|
||||
/// from the current class to the root-most class.
|
||||
+ (NSArray<Class> *)classHierarchyOfObject:(id)objectOrClass;
|
||||
/// @return Every subclass of the given class name.
|
||||
+ (NSArray<FLEXObjectRef *> *)subclassesOfClassWithName:(NSString *)className;
|
||||
|
||||
/// Used to describe an object in brief within an explorer row
|
||||
+ (NSString *)summaryForObject:(id)value;
|
||||
@@ -69,16 +74,19 @@ typedef NS_ENUM(NSInteger, FLEXRuntimeUtilityErrorCode) {
|
||||
+ (BOOL)safeObject:(id)object isKindOfClass:(Class)cls;
|
||||
+ (BOOL)safeObject:(id)object respondsToSelector:(SEL)sel;
|
||||
|
||||
// Property Helpers
|
||||
#pragma mark - Property Helpers
|
||||
|
||||
+ (BOOL)tryAddPropertyWithName:(const char *)name
|
||||
attributes:(NSDictionary<NSString *, NSString *> *)attributePairs
|
||||
toClass:(__unsafe_unretained Class)theClass;
|
||||
+ (NSArray<NSString *> *)allPropertyAttributeKeys;
|
||||
|
||||
// Method Helpers
|
||||
#pragma mark - Method Helpers
|
||||
|
||||
+ (NSArray *)prettyArgumentComponentsForMethod:(Method)method;
|
||||
|
||||
// Method Calling/Field Editing
|
||||
#pragma mark - Method Calling/Field Editing
|
||||
|
||||
+ (id)performSelector:(SEL)selector onObject:(id)object;
|
||||
+ (id)performSelector:(SEL)selector
|
||||
onObject:(id)object
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "FLEXRuntimeUtility.h"
|
||||
#import "FLEXObjcInternal.h"
|
||||
#import "FLEXObjectRef.h"
|
||||
#import "NSObject+FLEX_Reflection.h"
|
||||
#import "FLEXTypeEncodingParser.h"
|
||||
#import "FLEXMethod.h"
|
||||
|
||||
@@ -92,6 +94,12 @@ NSString * const FLEXRuntimeUtilityErrorDomain = @"FLEXRuntimeUtilityErrorDomain
|
||||
return superClasses;
|
||||
}
|
||||
|
||||
+ (NSArray<FLEXObjectRef *> *)subclassesOfClassWithName:(NSString *)className {
|
||||
NSArray<Class> *classes = FLEXGetAllSubclasses(NSClassFromString(className), NO);
|
||||
NSArray<FLEXObjectRef *> *references = [FLEXObjectRef referencingClasses:classes];
|
||||
return references;
|
||||
}
|
||||
|
||||
+ (NSString *)safeClassNameForObject:(id)object {
|
||||
// Don't assume that we have an NSObject subclass
|
||||
if ([self safeObject:object respondsToSelector:@selector(class)]) {
|
||||
|
||||
@@ -59,6 +59,7 @@ NS_INLINE BOOL flex_isTaggedPointer(const void *ptr) {
|
||||
|
||||
#define FLEXPointerIsTaggedPointer(obj) flex_isTaggedPointer((__bridge void *)obj)
|
||||
|
||||
/// Whether the given pointer is a valid, readable address.
|
||||
BOOL FLEXPointerIsReadable(const void * ptr);
|
||||
|
||||
/// @brief Assumes memory is valid and readable.
|
||||
|
||||
@@ -19,7 +19,7 @@ CFSetRef FLEXKnownUnsafeIvars = nil;
|
||||
(class_getInstanceVariable([cls class], name) ?: (void *)kCFNull)
|
||||
|
||||
__attribute__((constructor))
|
||||
static void FLEXRuntimeSafteyInit() {
|
||||
static void FLEXRuntimeSafteyInit(void) {
|
||||
FLEXKnownUnsafeClasses = CFSetCreate(
|
||||
kCFAllocatorDefault,
|
||||
(const void **)(uintptr_t)FLEXKnownUnsafeClassList(),
|
||||
@@ -39,7 +39,7 @@ static void FLEXRuntimeSafteyInit() {
|
||||
);
|
||||
}
|
||||
|
||||
const Class * FLEXKnownUnsafeClassList() {
|
||||
const Class * FLEXKnownUnsafeClassList(void) {
|
||||
if (!_UnsafeClasses) {
|
||||
const Class ignored[] = {
|
||||
FLEXClassPointerOrCFNull(@"__ARCLite__"),
|
||||
@@ -74,7 +74,7 @@ const Class * FLEXKnownUnsafeClassList() {
|
||||
return _UnsafeClasses;
|
||||
}
|
||||
|
||||
NSSet * FLEXKnownUnsafeClassNames() {
|
||||
NSSet * FLEXKnownUnsafeClassNames(void) {
|
||||
static NSSet *set = nil;
|
||||
if (!set) {
|
||||
NSArray *ignored = @[
|
||||
|
||||
@@ -52,9 +52,15 @@
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription {
|
||||
return [NSString stringWithFormat:@"<%@ name=%@, %lu properties, %lu required methods, %lu optional methods, %lu protocols>",
|
||||
if (@available(iOS 10.0, *)) {
|
||||
return [NSString stringWithFormat:@"<%@ name=%@, %lu required properties, %lu optional properties %lu required methods, %lu optional methods, %lu protocols>",
|
||||
NSStringFromClass(self.class), self.name, (unsigned long)self.requiredProperties.count, (unsigned long)self.optionalProperties.count,
|
||||
(unsigned long)self.requiredMethods.count, (unsigned long)self.optionalMethods.count, (unsigned long)self.protocols.count];
|
||||
} else {
|
||||
return [NSString stringWithFormat:@"<%@ name=%@, %lu properties, %lu required methods, %lu optional methods, %lu protocols>",
|
||||
NSStringFromClass(self.class), self.name, (unsigned long)self.properties.count,
|
||||
(unsigned long)self.requiredMethods.count, (unsigned long)self.optionalMethods.count, (unsigned long)self.protocols.count];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)examine {
|
||||
|
||||
@@ -88,8 +88,19 @@
|
||||
@implementation FHSView (Snapshotting)
|
||||
|
||||
+ (UIImage *)drawView:(UIView *)view {
|
||||
UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0);
|
||||
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
|
||||
if (CGRectIsEmpty(view.bounds)) {
|
||||
return [UIImage new];
|
||||
}
|
||||
|
||||
CGSize size = view.bounds.size;
|
||||
CGFloat minUnit = 1.f / UIScreen.mainScreen.scale;
|
||||
|
||||
// Every drawn view must not have 0 width or height
|
||||
CGSize minsize = CGSizeMake(MAX(size.width, minUnit), MAX(size.height, minUnit));
|
||||
CGRect minBounds = CGRectMake(0, 0, minsize.width, minsize.height);
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(minsize, NO, 0);
|
||||
[view drawViewHierarchyInRect:minBounds afterScreenUpdates:YES];
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
C35F0EF4292CC5CA00B728BC /* Reflex in Frameworks */ = {isa = PBXBuildFile; productRef = C35F0EF3292CC5CA00B728BC /* Reflex */; };
|
||||
C386D6D02419975A00699085 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C386D6CF2419975A00699085 /* AppDelegate.swift */; };
|
||||
C386D6D22419975A00699085 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C386D6D12419975A00699085 /* SceneDelegate.swift */; };
|
||||
C386D6D62419975B00699085 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C386D6D52419975B00699085 /* Assets.xcassets */; };
|
||||
@@ -21,7 +22,6 @@
|
||||
C386D705241AA61600699085 /* music_library_schema.jpg in Resources */ = {isa = PBXBuildFile; fileRef = C386D703241AA61600699085 /* music_library_schema.jpg */; };
|
||||
C386D70B241AA67800699085 /* Dog.m in Sources */ = {isa = PBXBuildFile; fileRef = C386D709241AA67800699085 /* Dog.m */; };
|
||||
C386D70C241AA67800699085 /* Owner.m in Sources */ = {isa = PBXBuildFile; fileRef = C386D70A241AA67800699085 /* Owner.m */; };
|
||||
C38D96EC2818F306008709D0 /* Reflex in Frameworks */ = {isa = PBXBuildFile; productRef = C38D96EB2818F306008709D0 /* Reflex */; };
|
||||
C3A67856241AB8AD005A4681 /* MiscNetworkRequests.m in Sources */ = {isa = PBXBuildFile; fileRef = C3A67855241AB8AD005A4681 /* MiscNetworkRequests.m */; };
|
||||
C3A67858241ADDF7005A4681 /* Commit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3A67857241ADDF7005A4681 /* Commit.swift */; };
|
||||
C3B3760025B8CDA300AD43AB /* Person.m in Sources */ = {isa = PBXBuildFile; fileRef = C3B375FF25B8CDA300AD43AB /* Person.m */; };
|
||||
@@ -62,7 +62,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C38D96EC2818F306008709D0 /* Reflex in Frameworks */,
|
||||
C35F0EF4292CC5CA00B728BC /* Reflex in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -183,7 +183,7 @@
|
||||
);
|
||||
name = FLEXample;
|
||||
packageProductDependencies = (
|
||||
C38D96EB2818F306008709D0 /* Reflex */,
|
||||
C35F0EF3292CC5CA00B728BC /* Reflex */,
|
||||
);
|
||||
productName = FLEXample;
|
||||
productReference = C386D6CC2419975A00699085 /* FLEXample.app */;
|
||||
@@ -215,7 +215,7 @@
|
||||
);
|
||||
mainGroup = C386D6C32419975A00699085;
|
||||
packageReferences = (
|
||||
C38D96EA2818F306008709D0 /* XCRemoteSwiftPackageReference "Reflex" */,
|
||||
C35F0EF2292CC5CA00B728BC /* XCRemoteSwiftPackageReference "Reflex" */,
|
||||
);
|
||||
productRefGroup = C386D6CD2419975A00699085 /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -462,9 +462,9 @@
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
C38D96EA2818F306008709D0 /* XCRemoteSwiftPackageReference "Reflex" */ = {
|
||||
C35F0EF2292CC5CA00B728BC /* XCRemoteSwiftPackageReference "Reflex" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "file:///Users/tanner/Repos/Reflex";
|
||||
repositoryURL = "https://github.com/FLEXTool/Reflex";
|
||||
requirement = {
|
||||
branch = master;
|
||||
kind = branch;
|
||||
@@ -473,9 +473,9 @@
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
C38D96EB2818F306008709D0 /* Reflex */ = {
|
||||
C35F0EF3292CC5CA00B728BC /* Reflex */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = C38D96EA2818F306008709D0 /* XCRemoteSwiftPackageReference "Reflex" */;
|
||||
package = C35F0EF2292CC5CA00B728BC /* XCRemoteSwiftPackageReference "Reflex" */;
|
||||
productName = Reflex;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
|
||||
+2
-2
@@ -28,7 +28,6 @@ Pod::Spec.new do |spec|
|
||||
|
||||
spec.license = { :type => "BSD", :file => "LICENSE" }
|
||||
spec.author = { "Tanner Bennett" => "tannerbennett@me.com" }
|
||||
spec.social_media_url = "https://twitter.com/NSExceptional"
|
||||
spec.platform = :ios, "9.0"
|
||||
spec.source = { :git => "https://github.com/FLEXTool/FLEX.git", :tag => "#{spec.version}" }
|
||||
spec.source_files = "Classes/**/*.{h,c,m,mm}"
|
||||
@@ -54,6 +53,7 @@ Pod::Spec.new do |spec|
|
||||
"Classes/Utility/FLEXResources.h",
|
||||
"Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.h",
|
||||
"Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.h",
|
||||
"Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h"
|
||||
"Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h",
|
||||
"Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserController.h"
|
||||
]
|
||||
end
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
C383C3C523B6BB81007A321B /* FLEXCodeFontCell.h in Headers */ = {isa = PBXBuildFile; fileRef = C383C3C323B6BB81007A321B /* FLEXCodeFontCell.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C383C3C623B6BB81007A321B /* FLEXCodeFontCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C383C3C423B6BB81007A321B /* FLEXCodeFontCell.m */; };
|
||||
C3854DF023F36C1700FCD1E2 /* FLEXTypeEncodingParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C3854DEF23F36C1700FCD1E2 /* FLEXTypeEncodingParserTests.m */; };
|
||||
C38568FA272B3BFC00B1E37F /* FLEXSwiftInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = C38568F8272B3BFC00B1E37F /* FLEXSwiftInternal.h */; };
|
||||
C38568FA272B3BFC00B1E37F /* FLEXSwiftInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = C38568F8272B3BFC00B1E37F /* FLEXSwiftInternal.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C38568FB272B3BFC00B1E37F /* FLEXSwiftInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = C38568F9272B3BFC00B1E37F /* FLEXSwiftInternal.mm */; };
|
||||
C386D6A9241995A800699085 /* FLEXTypeEncodingParser.h in Headers */ = {isa = PBXBuildFile; fileRef = C3854DF223F36C9E00FCD1E2 /* FLEXTypeEncodingParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C386D6E924199C1B00699085 /* FLEX-Core.h in Headers */ = {isa = PBXBuildFile; fileRef = C386D6E824199C1B00699085 /* FLEX-Core.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@@ -267,7 +267,7 @@
|
||||
C387C88322E0D24A00750E58 /* UIView+FLEX_Layout.h in Headers */ = {isa = PBXBuildFile; fileRef = C387C88122E0D24A00750E58 /* UIView+FLEX_Layout.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
C387C88422E0D24A00750E58 /* UIView+FLEX_Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = C387C88222E0D24A00750E58 /* UIView+FLEX_Layout.m */; };
|
||||
C38D970228190C93008709D0 /* FLEXMetadataExtras.m in Sources */ = {isa = PBXBuildFile; fileRef = C38D970028190C93008709D0 /* FLEXMetadataExtras.m */; };
|
||||
C38D970328190C93008709D0 /* FLEXMetadataExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = C38D970128190C93008709D0 /* FLEXMetadataExtras.h */; };
|
||||
C38D970328190C93008709D0 /* FLEXMetadataExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = C38D970128190C93008709D0 /* FLEXMetadataExtras.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C38DF0EA22CFE4370077B4AD /* FLEXTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38DF0E822CFE4370077B4AD /* FLEXTableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C38DF0EB22CFE4370077B4AD /* FLEXTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38DF0E922CFE4370077B4AD /* FLEXTableViewController.m */; };
|
||||
C38EF26223A2FCD20047A7EC /* FLEXViewControllerShortcuts.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF26023A2FCD20047A7EC /* FLEXViewControllerShortcuts.m */; };
|
||||
@@ -309,7 +309,7 @@
|
||||
C39EADC923F37B89005618BE /* FLEXTypeEncodingParser.m in Sources */ = {isa = PBXBuildFile; fileRef = C3854DF123F36C9E00FCD1E2 /* FLEXTypeEncodingParser.m */; };
|
||||
C39ED92822D63F3200B5773A /* FLEXAddressExplorerCoordinator.h in Headers */ = {isa = PBXBuildFile; fileRef = C39ED92622D63F3200B5773A /* FLEXAddressExplorerCoordinator.h */; };
|
||||
C39ED92922D63F3200B5773A /* FLEXAddressExplorerCoordinator.m in Sources */ = {isa = PBXBuildFile; fileRef = C39ED92722D63F3200B5773A /* FLEXAddressExplorerCoordinator.m */; };
|
||||
C3A04B64288E007100F2C16D /* NSDateFormatter+FLEX.h in Headers */ = {isa = PBXBuildFile; fileRef = C3A04B62288E007100F2C16D /* NSDateFormatter+FLEX.h */; };
|
||||
C3A04B64288E007100F2C16D /* NSDateFormatter+FLEX.h in Headers */ = {isa = PBXBuildFile; fileRef = C3A04B62288E007100F2C16D /* NSDateFormatter+FLEX.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C3A04B65288E007100F2C16D /* NSDateFormatter+FLEX.m in Sources */ = {isa = PBXBuildFile; fileRef = C3A04B63288E007100F2C16D /* NSDateFormatter+FLEX.m */; };
|
||||
C3A9422C23C3DA39006871A3 /* FHSView.h in Headers */ = {isa = PBXBuildFile; fileRef = C3A9422823C3DA39006871A3 /* FHSView.h */; };
|
||||
C3A9422D23C3DA39006871A3 /* FHSView.m in Sources */ = {isa = PBXBuildFile; fileRef = C3A9422923C3DA39006871A3 /* FHSView.m */; };
|
||||
@@ -1761,7 +1761,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
CLASSPREFIX = FLEX;
|
||||
LastUpgradeCheck = 1240;
|
||||
LastUpgradeCheck = 1400;
|
||||
ORGANIZATIONNAME = Flipboard;
|
||||
TargetAttributes = {
|
||||
1C27A8B51F0E5A0300F0D02D = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1240"
|
||||
LastUpgradeVersion = "1400"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1240"
|
||||
LastUpgradeVersion = "1400"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
+3
-1
@@ -7,7 +7,9 @@ enum FLEXBuildOptions {
|
||||
static let silenceWarnings = false
|
||||
}
|
||||
|
||||
#if swift(>=5.7)
|
||||
#if swift(>=5.9)
|
||||
let platforms: [PackageDescription.SupportedPlatform] = [.iOS(.v12)]
|
||||
#elseif swift(>=5.7)
|
||||
let platforms: [PackageDescription.SupportedPlatform] = [.iOS(.v11)]
|
||||
#else
|
||||
let platforms: [PackageDescription.SupportedPlatform] = [.iOS(.v10)]
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<?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>output_path</key>
|
||||
<string>build</string>
|
||||
<key>framework</key>
|
||||
<string>FLEX</string>
|
||||
<key>targets</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>sdk</key>
|
||||
<string>iOS</string>
|
||||
<key>project</key>
|
||||
<string>FLEX.xcodeproj</string>
|
||||
<key>scheme</key>
|
||||
<string>FLEX</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>sdk</key>
|
||||
<string>iOSSimulator</string>
|
||||
<key>project</key>
|
||||
<string>FLEX.xcodeproj</string>
|
||||
<key>scheme</key>
|
||||
<string>FLEX</string>
|
||||
</dict>
|
||||
<!--
|
||||
Remove this comment and add more targets for Simulators and the Devices.
|
||||
-->
|
||||
</array>
|
||||
<key>finalActions</key>
|
||||
<array>
|
||||
<string>openDirectory</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -33,6 +33,10 @@ generate_headers() {
|
||||
# "Classes/ObjectExplorers/**/*.h", "Classes/Editing/**/*.h",
|
||||
# "Classes/Utility/FLEXMacros.h", "Classes/Utility/Categories/*.h",
|
||||
# "Classes/Utility/FLEXAlert.h", "Classes/Utility/FLEXResources.h"
|
||||
# "Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.h",
|
||||
# "Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.h",
|
||||
# "Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h",
|
||||
# "Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserController.h"
|
||||
|
||||
rm -rf Classes/Headers
|
||||
mkdir -p Classes/Headers
|
||||
@@ -58,6 +62,7 @@ makeheader "Classes/Utility/FLEXResources.h"
|
||||
makeheader "Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcut.h"
|
||||
makeheader "Classes/ObjectExplorers/Sections/Shortcuts/FLEXShortcutsSection.h"
|
||||
makeheader "Classes/GlobalStateExplorers/Globals/FLEXGlobalsEntry.h"
|
||||
makeheader "Classes/GlobalStateExplorers/FileBrowser/FLEXFileBrowserController.h"
|
||||
|
||||
# Print all folders in Classes for use in Package.swift
|
||||
for folder in `find "Classes" -type d`; do
|
||||
|
||||
Reference in New Issue
Block a user