LibStatusBar icon disappears on 3rd-party app launch - ios

I wrote a tweak for Cydia, it adds an icon to the status bar.
It works fine on the home screen and when SpringBoard is launched, also, if an app is already launched then it works fine,
however, if an app (such as Facebook or Twitter) is closed (completely) and the icon is showing, when launching the app, it will cause the icon to disappear.
The icon is displayed using libStatusBar using this code:
if(icon) // if icon needs to be removed
{
[icon release];
icon = nil;
}
...
// add the icon to the status bar
icon = [[%c(LSStatusBarItem) alloc] initWithIdentifier:[NSString stringWithFormat:#"muteIconLablabla"] alignment:StatusBarAlignmentRight];
icon.imageName = [NSString stringWithFormat:#"Mute"];
I also tried using the methods suggested in libStatusBar README file
[[UIApplication sharedApplication] addStatusBarImageNamed:#"ON_Mute"]; // and removeStatusBarImageNamed:...
I tried overriding -(id)init and updating the icon there, but the same result.
The code shown above is being called from a static void function. this function is being called several times, for example from -(void)applicationDidFinishLaunching:(id)application
under %hook SpringBoard and -(void)ringerChanged:(int)changed
All inside Tweak.xm.
The problem happens in iOS7 as well.

It's been a while since I've used libstatusbar, but if you are absolutely sure the LSStatusBarItem is not being released, it's possible it's being hidden by Springboard or another app. Consider setting icon.visible = YES explicitly. You also might want to consider setting timeHidden on LSStatusBarServer to NO explicitly by calling [item setHidesTime:NO].
Additionally, if you're not making any changes to the icon, set icon.manualUpdate = NO.
References:
Libstatusbar on the iPhoneDevWiki
LSStatusBarItem.mm source

Related

How can I choose which scene gets restored on iPadOS when all have been dismissed?

I have an iPad app in which I'm starting to support multiple windows / scenes. I have one main window type, let's say MainScene, and at least one secondary window type for opening specific types of content, say DetailScene.
I have not declared my scene types in Info.plist. I have implemented application:configurationForConnectingSceneSession:options: like this:
-(UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options
{
NSUserActivity *activity = options.userActivities.anyObject;
NSString *activityType = activity.activityType;
if ([activityType isEqualToString:#"detailType"])
return [DetailSceneDelegate makeSceneConfiguration];
return [MainSceneDelegate makeSceneConfiguration];
}
Say I perform these steps:
Launch app for the first time. I get a call to configurationForConnectingSceneSession, and the activity type is nil so it returns a MainScene.
Open a new window for some piece of content. That uses the detail scene activity type, so configurationForConnectingSceneSession returns a DetailScene. Creating the new scene looks like this:
NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:#"detailType"];
activity.userInfo = #{#"content_id": #(contentRowId)};
[[UIApplication sharedApplication] requestSceneSessionActivation:nil userActivity:activity options:nil errorHandler:nil];
Suspend the app and open the app switcher. Discard (by flicking up) first the main window and then the detail window. The app is now killed.
Relaunch the app.
At this point I do not get a call to configurationForConnectingSceneSession. I get the detail scene back, restored from its user activity, with calls straight to DetailSceneDelegate.
My question: how do I control what scene gets restored in this situation? I want my main scene to come back.
Messages and Mail and Notes all do this. If you open Messages and drag a conversation out into a new window, you get a window for that conversation with a Done button in the corner that will dismiss the window. If you perform my steps above with Messages, you will relaunch to the full Messages view. Are they converting the detail view to a main view on the fly? Or is there a way to tell the system that the detail scene is secondary and should not be restored first, or that I should get asked what I want to restore via configurationForConnectingSceneSession? Or something else?
I cross-posted this to the Apple Developer forums and got an answer from a Framework Engineer. The answer is UISceneActivationConditions, set as a property on UIScene. Set the canActivateForTargetContentIdentifierPredicate to always return NO:
scene.activationConditions.canActivateForTargetContentIdentifierPredicate = [NSPredicate predicateWithValue:NO];
I do this in my implementation of scene:willConnectToSession:options: in my UIWindowSceneDelegate implementation.
As of current writing, on Xcode 13.2 and iOS 15.2 simulator, it works if the second launch (step 4 above) is via tapping the app icon, but not when it's via building and running in Xcode. I may file a feedback on this.

How can I get a transparent background in my iOS app so I can see the Home Screen wallpaper?

I’m fairly sure this is going to be straight forward in that it’s probably not possible.
Basically, I’d like to be able to lightly see the background wallpaper through my view in the same way that the new Newsstand app does.
I've tried changing the alpha value of the view, and the background color to clear, but neither of these seem to do it.
Apple has removed the ability to use this api in 7.0.3. What a shame.
You certainly can in iOS7, at least as of a few days ago. In our app once you set the following it makes your background transparent and shows the user wallpaper. If you try to programmatically take a screenshot, it will just show black instead.
Set UIApplicationIsOpaque to false in the project plist
In the app delegate load function:
self.window.backgroundColor = [UIColor clearColor];
self.window.opaque = NO;
Set the UIViewController.view's background color to [UIColor clearColor]
Good news. From iOS 13, the background transparency can finally be enabled for all third-party apps. It’s no longer a private API.
In your app’s Info.plist file, set the boolean value for
UIApplicationIsOpaque to NO.
And now the user’s wallpaper is visible inside your app.
It's not possible in iOS. While your app is running it does not mean that there is home screen behind your app.
However, If you do want to do it, there is a way that you make your app go in background, take screenshot and use that image as your background which will feel like home screen.
See this post. In this link, the accepted answer gives a way to take screenshot of home screen while your app is in background. But that's been achieved through a private API, which means your app probably will get rejected by App Store on time of submission.

Changing rootViewController in applicaitonWillEnterForeground

Long story short, I'm trying to change my iOS app's rootViewController on applicationWillEnterForeground:, like so:
- (void)applicationWillEnterForeground:(UIApplication *)application
{
MyViewController *controller = [[MyViewController alloc] init];
self.window.rootViewController = controller;
}
However, when iOS performs the "zoom in" animation that is performed when an app is moved from the background to the foreground, it still shows the previous rootViewController's view. Then, as soon as the animation is complete, the app blasts the new rootViewController's view onto the screen.
One way to solve this is to simply move that code to - (void)applicationDidEnterBackground:, but the problem with this solution is that, in my app, there is no way to tell if a new rootViewController will be assigned until - (void)applicationWillEnterForeground:(UIApplication *)application (it is based on time passed since leaving the app).
How can I force the app to redraw before iOS performs the animation taking the app from the background to the foreground?
I believe this is not possible. The screen that iOS shows of your app when it comes into the foreground is actually a screenshot the system took when the app went into the background. There is no way to manipulate or replace that image at the time the app comes back into the foreground.
This behavior is partly documented in the Moving to the Background section of the iOS Application Programming Guide:
Apps can use their applicationDidEnterBackground: method to prepare for moving to the background state. When moving to the background, all apps should do the following:
Prepare to have their picture taken. When the applicationDidEnterBackground: method returns, the system takes a picture of your app’s user interface and uses the resulting image for transition animations. If any views in your interface contain sensitive information, you should hide or modify those views before the applicationDidEnterBackground: method returns.
Apple does not explicitly document that you cannot modify or replace this screenshot at a later time but neither do they say the opposite anywhere I know of.

Show splash screen at every launch

My app uses a splash screen as per client requirement. I need to display this splash screen at every launch when user presses the home button again. Pressing app I need to load app from beginning or else display splash at a specific time interval.
Please help me to solve this.
You can disable the Multitasking capability of the app and make it start from scratch each time you re-open the app from the home screen.
#implementation MyAppDelegate
- (void) applicationDidEnterBackground:(UIApplication *)application {
exit(0);
}
#end
OR See "Opting Out of Background Execution" in the iOS Application Programming Guide:
"...you can explicitly opt out of the
background execution model by adding
the UIApplicationExitsOnSuspend key to
your application’s Info.plist file and
setting its value to YES."

Show MBProgressHUD on iPhone app's splash screen while Core Data store is migrating to new version?

If my iPhone app needs to update the Core Data database, I would like to show an MBProgressHUD view to users while my iPhone app is loading, so they know that it's working and not hanging. How might I go about adding an MBProgressHUD to the splash screen while the data store is migrating? Normally I would attach it to the UIViewController's view, but the splash screen is under the app delegate. Is this possible to do?
No it is not possible to overlay anything over the splash screen as it's static.
You could, however, delay the intensive process for a bit until the app loads, then create a fake splash screen with the progress indicator while the intensive stuff goes on in a background thread.
You could create a #define macro in your application delegate header file (or in a "globals" header), like so:
#define MyAppDelegate [[UIApplication sharedApplication] delegate]
Then, when you want access the application delegate property, you can do so like this anywhere in your application you have imported that header (or the globals header):
MyAppDelegate.property = foo;
[[MyAppDelegate property] bar];
This may help you manage your progress view at any point in the app's life.
EDIT
sudo rm -rf is correct that you can't do work during the splash screen. But you can start your progress view in the app delegate's -applicationDidFinishLaunching: method, and then launch work on a background thread. Once your background thread's work is finished, have a callback dismiss the progress view.

Resources