How to hide statusbar icons in iOS

2019-07-20 20:17发布

问题:

I want to create a simple mobilesubstrate tweak that hides and shows status bar icons like battery or Carrier or wifi signal indecator. I've seen libstatusbar project but i can't find out how to hide iOS's icons. Is there any other way to do this without the use of this library? I just want to hide and show the default icons

回答1:

Here is what I use in my tweak:

int itemToHide = 0;
[[objc_getClass("SBStatusBarStateAggregator") sharedInstance] beginCoalescentBlock];
[[objc_getClass("SBStatusBarStateAggregator") sharedInstance] _setItem:itemToHide enabled:NO];
[[objc_getClass("SBStatusBarStateAggregator") sharedInstance] endCoalescentBlock];

Only problem - iOS uses integer values for status bar items and they're different on different iOS versions. You could test every iOS version and store values for each one of them but I found a better way.

I hook SBStatusBarStateAggregator _setItem:(int)arg1 enabled:(BOOL)arg2 method. Then I call one of the SBStatusBarStateAggregator -(void)_update**** methods. For example, let's say I want to find location icon index. I call SBStatusBarStateAggregator -(void)_updateLocationItem method. It then will call hooked SBStatusBarStateAggregator _setItem:(int)arg1 enabled:(BOOL)arg2 where I will store the index.

I also hook SBStatusBarStateAggregator -(void)_notifyItemChanged:(int)arg. This method is called as part of SBStatusBarStateAggregator -(void)_update**** call. When determing status bar icon index I simply ignore calls to it by returning without calling original implementation.

And if you want to permanently hide some of the icons you still need to hook SBStatusBarStateAggregator _setItem:(int)arg1 enabled:(BOOL)arg2 and SBStatusBarStateAggregator -(void)_notifyItemChanged:(int)arg in order to ignore any iOS attempts to show hidden icons. For example, signal level and data/time are reanabled every time they're updated.

That's all for iOS 7. On iOS 5-6 API is different but I use pretty much the same approach. To hide status bar item

int itemToHide = 0;
[[objc_getClass("SBStatusBarDataManager") sharedDataManager] setStatusBarItem:itemToHide enabled:NO];

I hook SBStatusBarDataManager -(void)updateStatusBarItem:(int)item to determine icon index and then call SBStatusBarDataManager -(void)_locationStatusChange in case of location icon.



回答2:

Not possible using public API. You can only hide the entire status bar, not only certain elements of it.

For jailbreak, take a look at:

https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIStatusBarItem.h

In particularly, look at the following methods:

+ (BOOL)itemType:(int)arg1 idiom:(int)arg2 appearsInRegion:(int)arg3;
+ (BOOL)itemType:(int)arg1 idiom:(int)arg2 canBeEnabledForData:(id)arg3 style:(id)arg4;

These methods are consulted whether iterms should appear or not. Return NO here to disable items.



回答3:

Ok. Here is solution.
In your plist file add row:

View controller-based status bar appearance  :  NO 

Make a category on UINavigationBar with this content:

#import "UINavigationBar+StatusBar.h"
#import 

@implementation UINavigationBar (StatusBar)

+ (void)load
{
    [self swizzleOriginalSelectorWithName:@"layoutSubviews" toSelectorWithName:@"my_layoutSubviews"];
}

- (void)my_layoutSubviews
{
    [self my_layoutSubviews];
    [self setFrame:CGRectMake(0, 0, self.frame.size.width, 64)];
}

+ (void)swizzleOriginalSelectorWithName:(NSString *)origName toSelectorWithName:(NSString *)swizzleName
{
    Method origMethod = class_getInstanceMethod([self class], NSSelectorFromString(origName));
    Method newMethod = class_getInstanceMethod([self class], NSSelectorFromString(swizzleName));
    method_exchangeImplementations(origMethod, newMethod);
}

@end

This will increase navigation bar for 20pt.

Then, make your custom view for status bar. e.g.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [self makeCustomSatusBar];
    // Override point for customization after application launch.
    return YES;
}

- (void)makeCustomSatusBar
{
    [[UIApplication sharedApplication] setStatusBarHidden:YES];

    UIColor *statusBarColor = [UIColor blackColor];

    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.window.frame.size.width, 20)];
    view.layer.zPosition = INT_MAX;
    view.backgroundColor = [UIColor clearColor];

    // Making time label
    NSDateFormatter *formatter = [NSDateFormatter new];
    formatter.dateFormat = @"HH:mm";
    UILabel *timeLabel = [UILabel new];
    timeLabel.text = [formatter stringFromDate:[NSDate date]];
    timeLabel.textColor = statusBarColor;
    timeLabel.font = [UIFont systemFontOfSize:12];
    [timeLabel sizeToFit];
    timeLabel.center = CGPointMake(view.frame.size.width/2, view.frame.size.height/2);
    [view addSubview:timeLabel];
    //

    // make other indicators you need...
    //...

    [self.window addSubview:view];
}

And you will have something like this:

Note, that you need to update values of your custom view every time (i.e. time label, battery, etc..) , so it would be better to make a separate class for your status bar, and make a infinite timer with 1 sec of tick and do your updates in timer's action.



回答4:

may be you just need this?

[[UIApplication sharedApplication] setStatusBarHidden:YES]

And if you want just empty view on top of 20pt height, then make that and add to UIWindow, and shift down subview of UIWindow for 20 pt