Explorar o código

Make new JSON viewer and System Log behavior opt-in

Tanner Bennett %!s(int64=6) %!d(string=hai) anos
pai
achega
a25ef87a51

+ 34 - 15
Classes/GlobalStateExplorers/SystemLog/FLEXSystemLogViewController.m

@@ -42,6 +42,11 @@ static BOOL my_os_log_shim_enabled(void *addr) {
 #pragma mark - Initialization
 
 + (void)load {
+    // User must opt-into disabling os_log
+    if (!NSUserDefaults.standardUserDefaults.flex_disableOSLog) {
+        return;
+    }
+    
     // Thanks to @Ram4096 on GitHub for telling me that
     // os_log is conditionally enabled by the SDK version
     void *addr = __builtin_return_address(0);
@@ -108,7 +113,7 @@ static BOOL my_os_log_shim_enabled(void *addr) {
     }
 
     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
-    self.title = @"Loading...";
+    self.title = @"Waiting for Logs...";
     
     // Toolbar buttons //
     
@@ -123,11 +128,7 @@ static BOOL my_os_log_shim_enabled(void *addr) {
         action:@selector(showLogSettings)
     ];
     
-    if (FLEXOSLogAvailable() && !FLEXNSLogHookWorks) {
-        [self addToolbarItems:@[scrollDown, settings]];
-    } else {
-        [self addToolbarItems:@[scrollDown]];
-    }
+    [self addToolbarItems:@[scrollDown, settings]];
 }
 
 - (void)viewWillAppear:(BOOL)animated {
@@ -191,17 +192,35 @@ static BOOL my_os_log_shim_enabled(void *addr) {
 }
 
 - (void)showLogSettings {
-    FLEXOSLogController *logController = (FLEXOSLogController *)self.logController;
-    BOOL persistent = NSUserDefaults.standardUserDefaults.flex_cacheOSLogMessages;
-    NSString *toggle = persistent ? @"Disable" : @"Enable";
-    NSString *title = [@"Persistent logging: " stringByAppendingString:persistent ? @"ON" : @"OFF"];
-    NSString *body = @"In iOS 10 and up, ASL is gone. The OS Log API is much more limited. "
-    "To get as close to the old behavior as possible, logs must be collected manually at launch and stored.\n\n"
-    "Turn this feature on only when you need it.";
+    NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
+    BOOL disableOSLog = defaults.flex_disableOSLog;
+    BOOL persistent = defaults.flex_cacheOSLogMessages;
 
+    NSString *aslToggle = disableOSLog ? @"Enable os_log (default)" : @"Disable os_log";
+    NSString *persistence = persistent ? @"Disable persistent logging" : @"Enable persistent logging";
+    
+    NSString *title = @"System Log Settings";
+    NSString *body = @"In iOS 10 and up, ASL has been replaced by os_log. "
+    "The os_log API is much more limited. Below, you can opt-into the old behavior "
+    "if you want cleaner, more reliable logs within FLEX, but this will break "
+    "anything that expects os_log to be working, such as Console.app. "
+    "This setting requires the app to restart to take effect. \n\n"
+    
+    "To get as close to the old behavior as possible with os_log enabled, logs must "
+    "be collected manually at launch and stored. This setting has no effect "
+    "on iOS 9 and below, or if os_log is disabled. "
+    "You should only enable persistent logging when you need it.";
+    
+    FLEXOSLogController *logController = (FLEXOSLogController *)self.logController;
+    
     [FLEXAlert makeAlert:^(FLEXAlert *make) {
-        make.title(title).message(body).button(toggle).handler(^(NSArray<NSString *> *strings) {
-            NSUserDefaults.standardUserDefaults.flex_cacheOSLogMessages = !persistent;
+        make.title(title).message(body);
+        make.button(aslToggle).destructiveStyle().handler(^(NSArray<NSString *> *strings) {
+            [defaults toggleBoolForKey:kFLEXDefaultsDisableOSLogForceASLKey];
+        });
+        
+        make.button(persistence).handler(^(NSArray<NSString *> *strings) {
+            [defaults toggleBoolForKey:kFLEXDefaultsiOSPersistentOSLogKey];
             logController.persistent = !persistent;
             [logController.messages addObjectsFromArray:self.logMessages.list];
         });

+ 14 - 11
Classes/Manager/FLEXManager+Networking.m

@@ -11,22 +11,25 @@
 #import "FLEXNetworkObserver.h"
 #import "FLEXNetworkRecorder.h"
 #import "FLEXObjectExplorerFactory.h"
+#import "NSUserDefaults+FLEX.h"
 
 @implementation FLEXManager (Networking)
 
 + (void)load {
-    dispatch_async(dispatch_get_main_queue(), ^{
-        // Register array/dictionary viewer for JSON responses
-        [self.sharedManager setCustomViewerForContentType:@"application/json"
-            viewControllerFutureBlock:^UIViewController *(NSData *data) {
-                id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
-                if (jsonObject) {
-                    return [FLEXObjectExplorerFactory explorerViewControllerForObject:jsonObject];
+    if (NSUserDefaults.standardUserDefaults.flex_registerDictionaryJSONViewerOnLaunch) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            // Register array/dictionary viewer for JSON responses
+            [self.sharedManager setCustomViewerForContentType:@"application/json"
+                viewControllerFutureBlock:^UIViewController *(NSData *data) {
+                    id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+                    if (jsonObject) {
+                        return [FLEXObjectExplorerFactory explorerViewControllerForObject:jsonObject];
+                    }
+                    return nil;
                 }
-                return nil;
-            }
-        ];
-    });
+            ];
+        });
+    }
 }
 
 - (BOOL)isNetworkDebuggingEnabled {

+ 35 - 3
Classes/Network/FLEXNetworkSettingsController.m

@@ -11,6 +11,7 @@
 #import "FLEXUtility.h"
 #import "FLEXTableView.h"
 #import "FLEXColor.h"
+#import "NSUserDefaults+FLEX.h"
 
 @interface FLEXNetworkSettingsController () <UIActionSheetDelegate>
 @property (nonatomic) float cacheLimitValue;
@@ -18,6 +19,7 @@
 
 @property (nonatomic, readonly) UISwitch *observerSwitch;
 @property (nonatomic, readonly) UISwitch *cacheMediaSwitch;
+@property (nonatomic, readonly) UISwitch *jsonViewerSwitch;
 @property (nonatomic, readonly) UISlider *cacheLimitSlider;
 @property (nonatomic) UILabel *cacheLimitLabel;
 
@@ -32,8 +34,11 @@
     [self disableToolbar];
     self.hostBlacklist = FLEXNetworkRecorder.defaultRecorder.hostBlacklist.mutableCopy;
     
+    NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
+    
     _observerSwitch = [UISwitch new];
     _cacheMediaSwitch = [UISwitch new];
+    _jsonViewerSwitch = [UISwitch new];
     _cacheLimitSlider = [UISlider new];
     
     self.observerSwitch.on = FLEXNetworkObserver.enabled;
@@ -48,6 +53,12 @@
         forControlEvents:UIControlEventValueChanged
     ];
     
+    self.jsonViewerSwitch.on = defaults.flex_registerDictionaryJSONViewerOnLaunch;
+    [self.jsonViewerSwitch addTarget:self
+        action:@selector(jsonViewerSettingToggled:)
+        forControlEvents:UIControlEventValueChanged
+    ];
+    
     [self.cacheLimitSlider addTarget:self
         action:@selector(cacheLimitAdjusted:)
         forControlEvents:UIControlEventValueChanged
@@ -84,12 +95,16 @@
     FLEXNetworkRecorder.defaultRecorder.shouldCacheMediaResponses = sender.isOn;
 }
 
+- (void)jsonViewerSettingToggled:(UISwitch *)sender {
+    [NSUserDefaults.standardUserDefaults toggleBoolForKey:kFLEXDefaultsRegisterJSONExplorerKey];
+}
+
 - (void)cacheLimitAdjusted:(UISlider *)sender {
     self.cacheLimitValue = sender.value;
 }
 
 
-#pragma mark - Table View
+#pragma mark - Table View Data Source
 
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
     return self.hostBlacklist.count ? 2 : 1;
@@ -97,7 +112,7 @@
 
 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
     switch (section) {
-        case 0: return 4;
+        case 0: return 5;
         case 1: return self.hostBlacklist.count;
         default: return 0;
     }
@@ -111,6 +126,17 @@
     }
 }
 
+- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
+    if (section == 0) {
+        return @"By default, JSON is rendered in a webview. Turn on "
+        "\"View JSON as a dictionary/array\" to convert JSON payloads "
+        "to objects and view them in an object explorer. "
+        "This setting requires a restart of the app.";
+    }
+    
+    return nil;
+}
+
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  {
     UITableViewCell *cell = [self.tableView
         dequeueReusableCellWithIdentifier:kFLEXDefaultCell forIndexPath:indexPath
@@ -132,10 +158,14 @@
                     cell.accessoryView = self.cacheMediaSwitch;
                     break;
                 case 2:
+                    cell.textLabel.text = @"View JSON as a dictionary/array";
+                    cell.accessoryView = self.jsonViewerSwitch;
+                    break;
+                case 3:
                     cell.textLabel.text = @"Reset Host Blacklist";
                     cell.textLabel.textColor = tableView.tintColor;
                     break;
-                case 3:
+                case 4:
                     cell.textLabel.text = self.cacheLimitCellTitle;
                     self.cacheLimitLabel = cell.textLabel;
                     [self.cacheLimitSlider removeFromSuperview];
@@ -179,6 +209,8 @@
     return cell;
 }
 
+#pragma mark - Table View Delegate
+
 - (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)ip {
     // Can only select the "Reset Host Blacklist" row
     return ip.section == 0 && ip.row == 2;

+ 12 - 9
Classes/Utility/Categories/NSUserDefaults+FLEX.h

@@ -8,7 +8,7 @@
 
 #import <Foundation/Foundation.h>
 
-// Only use these if the getters and setters aren't good enough for whatever reaso
+// Only use these if the getters and setters aren't good enough for whatever reason
 extern NSString * const kFLEXDefaultsToolbarTopMarginKey;
 extern NSString * const kFLEXDefaultsiOSPersistentOSLogKey;
 extern NSString * const kFLEXDefaultsHidePropertyIvarsKey;
@@ -16,26 +16,29 @@ extern NSString * const kFLEXDefaultsHidePropertyMethodsKey;
 extern NSString * const kFLEXDefaultsHideMethodOverridesKey;
 extern NSString * const kFLEXDefaultsHideVariablePreviewsKey;
 extern NSString * const kFLEXDefaultsNetworkHostBlacklistKey;
+extern NSString * const kFLEXDefaultsDisableOSLogForceASLKey;
+extern NSString * const kFLEXDefaultsRegisterJSONExplorerKey;
 
+/// All BOOL preferences are NO by default
 @interface NSUserDefaults (FLEX)
 
 - (void)toggleBoolForKey:(NSString *)key;
 
 @property (nonatomic) double flex_toolbarTopMargin;
 
-/// NO by default
+// Not actually stored in defaults, but written to a file
+@property (nonatomic) NSArray<NSString *> *flex_networkHostBlacklist;
+
+/// Whether or not to register the object explorer as a JSON viewer on launch
+@property (nonatomic) BOOL flex_registerDictionaryJSONViewerOnLaunch;
+
+/// Disable os_log and re-enable ASL. May break Console.app output.
+@property (nonatomic) BOOL flex_disableOSLog;
 @property (nonatomic) BOOL flex_cacheOSLogMessages;
 
-/// NO by default
 @property (nonatomic) BOOL flex_explorerHidesPropertyIvars;
-/// NO by default
 @property (nonatomic) BOOL flex_explorerHidesPropertyMethods;
-/// NO by default
 @property (nonatomic) BOOL flex_explorerShowsMethodOverrides;
-/// NO by default
 @property (nonatomic) BOOL flex_explorerHidesVariablePreviews;
 
-// Not actually stored in defaults, but written to a file
-@property (nonatomic) NSArray<NSString *> *flex_networkHostBlacklist;
-
 @end

+ 41 - 13
Classes/Utility/Categories/NSUserDefaults+FLEX.m

@@ -15,6 +15,8 @@ NSString * const kFLEXDefaultsHidePropertyMethodsKey = @"com.flipboard.FLEX.hide
 NSString * const kFLEXDefaultsHideMethodOverridesKey = @"com.flipboard.FLEX.hide_method_overrides";
 NSString * const kFLEXDefaultsHideVariablePreviewsKey = @"com.flipboard.FLEX.hide_variable_previews";
 NSString * const kFLEXDefaultsNetworkHostBlacklistKey = @"com.flipboard.FLEX.network_host_blacklist";
+NSString * const kFLEXDefaultsDisableOSLogForceASLKey = @"com.flipboard.FLEX.try_disable_os_log";
+NSString * const kFLEXDefaultsRegisterJSONExplorerKey = @"com.flipboard.FLEX.view_json_as_object";
 
 #define FLEXDefaultsPathForFile(name) ({ \
     NSArray *paths = NSSearchPathForDirectoriesInDomains( \
@@ -25,6 +27,8 @@ NSString * const kFLEXDefaultsNetworkHostBlacklistKey = @"com.flipboard.FLEX.net
 
 @implementation NSUserDefaults (FLEX)
 
+#pragma mark Internal
+
 /// @param filename the name of a plist file without any extension
 - (NSString *)flex_defaultsPathForFile:(NSString *)filename {
     filename = [filename stringByAppendingPathExtension:@"plist"];
@@ -36,11 +40,15 @@ NSString * const kFLEXDefaultsNetworkHostBlacklistKey = @"com.flipboard.FLEX.net
     return [preferences stringByAppendingPathComponent:filename];
 }
 
+#pragma mark Helper
+
 - (void)toggleBoolForKey:(NSString *)key {
     [self setBool:![self boolForKey:key] forKey:key];
     [NSNotificationCenter.defaultCenter postNotificationName:key object:nil];
 }
 
+#pragma mark Misc
+
 - (double)flex_toolbarTopMargin {
     if ([self objectForKey:kFLEXDefaultsToolbarTopMarginKey]) {
         return [self doubleForKey:kFLEXDefaultsToolbarTopMarginKey];
@@ -53,6 +61,37 @@ NSString * const kFLEXDefaultsNetworkHostBlacklistKey = @"com.flipboard.FLEX.net
     [self setDouble:margin forKey:kFLEXDefaultsToolbarTopMarginKey];
 }
 
+- (NSArray<NSString *> *)flex_networkHostBlacklist {
+    return [NSArray arrayWithContentsOfFile:[
+        self flex_defaultsPathForFile:kFLEXDefaultsNetworkHostBlacklistKey
+    ]] ?: @[];
+}
+
+- (void)setFlex_networkHostBlacklist:(NSArray<NSString *> *)blacklist {
+    NSParameterAssert(blacklist);
+    [blacklist writeToFile:[
+        self flex_defaultsPathForFile:kFLEXDefaultsNetworkHostBlacklistKey
+    ] atomically:YES];
+}
+
+- (BOOL)flex_registerDictionaryJSONViewerOnLaunch {
+    return [self boolForKey:kFLEXDefaultsRegisterJSONExplorerKey];
+}
+
+- (void)setFlex_registerDictionaryJSONViewerOnLaunch:(BOOL)enable {
+    [self setBool:enable forKey:kFLEXDefaultsRegisterJSONExplorerKey];
+}
+
+#pragma mark System Log
+
+- (BOOL)flex_disableOSLog {
+    return [self boolForKey:kFLEXDefaultsDisableOSLogForceASLKey];
+}
+
+- (void)setFlex_disableOSLog:(BOOL)disable {
+    [self setBool:disable forKey:kFLEXDefaultsDisableOSLogForceASLKey];
+}
+
 - (BOOL)flex_cacheOSLogMessages {
     return [self boolForKey:kFLEXDefaultsiOSPersistentOSLogKey];
 }
@@ -65,6 +104,8 @@ NSString * const kFLEXDefaultsNetworkHostBlacklistKey = @"com.flipboard.FLEX.net
     ];
 }
 
+#pragma mark Object Explorer
+
 - (BOOL)flex_explorerHidesPropertyIvars {
     return [self boolForKey:kFLEXDefaultsHidePropertyIvarsKey];
 }
@@ -113,17 +154,4 @@ NSString * const kFLEXDefaultsNetworkHostBlacklistKey = @"com.flipboard.FLEX.net
     ];
 }
 
-- (NSArray<NSString *> *)flex_networkHostBlacklist {
-    return [NSArray arrayWithContentsOfFile:[
-        self flex_defaultsPathForFile:kFLEXDefaultsNetworkHostBlacklistKey
-    ]] ?: @[];
-}
-
-- (void)setFlex_networkHostBlacklist:(NSArray<NSString *> *)blacklist {
-    NSParameterAssert(blacklist);
-    [blacklist writeToFile:[
-        self flex_defaultsPathForFile:kFLEXDefaultsNetworkHostBlacklistKey
-    ] atomically:YES];
-}
-
 @end