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