-
Notifications
You must be signed in to change notification settings - Fork 24.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
iOS AppDelegate changes no longer permit configuring a loading view fade delay to avoid native -> JS "white flash" #35937
Comments
Potential workaround: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.moduleName = @"MainApp";
// You can add your custom initial props in the dictionary below.
// They will be passed down to the ViewController used by React Native.
self.initialProps = @{};
BOOL success = [super application:application didFinishLaunchingWithOptions:launchOptions];
if (success) {
// Modify as needed to match the main color of your splash.
self.window.rootViewController.view.backgroundColor = [UIColor colorNamed:@"primary"];
}
return success;
} |
@mysport12
|
Thank you both for some potential solutions! I will evaluate and comment back. |
@alpha0010 your solution didn't get me all the way there but provided me with enough insight to get things working as intended (see below)
@jafar-jabr I couldn't seem to get your solution to work as is but like alpha's proposed solution, gave me clues into what I needed to do. |
@mysport12 Running into the exact same issue while updating from React Native 0.70.0 to 0.71.0, thanks for posting. I used your example to do something a little different and thought I'd post too in case it's helpful to anyone. For reference, I am also using Codepush and This is what my launch options looked like at React Native 0.70.0, with the main things to note enclosed by
This is what it looked like after 0.71.0:
Big difference!
Native files are not my strong suit at all, basically just learning them off the cuff. If anyone comes across this and believes I'm missing something/implemented this incorrectly, I'm very open to correction. |
Actually, you can do whatever you want with the RootView. The RCTAppDelegate.h exposes methods that you can override in order to customise your views. For example, this method allows you to get the default UIView * and to customise it:
And there are a method to customise the view controller if needed. I’m sorry to see this issue only now. |
Thanks @gabriellend, the suggested code worked out great. |
@zallanx @gabriellend @mysport12 @jafar-jabr @alpha0010: please, refer to my comment above as the proper way to customise your Let me know if they work (as they should). Meanwhile, I'll close this issue. |
Here is another example that worked for me:
And here is a link to convert HEX and RGB into UIColor: https://www.uicolor.io/ |
@cipolleschi Where would that snippet go in AppDelegate? In launch options? |
@gabriellend That's another method of the app delegate. So you can just add the snippet below the So, something like: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.moduleName = @"RnDiffApp";
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initProps:(NSDictionary *)initProps
{
UIView * rootView = [super createRootViewWithBridge:bridge moduleName:moduleName initProps:initProps];
rootView.backgroundColor = [[UIColor alloc] initWithRed:0.13 green:0.13 blue:0.13 alpha:1];
return rootView;
} This should simplify the app code quite a bit, limiting the possibility that something can go wrong! 😉 |
@cipolleschi I was able to get that approach to work for preventing the flash, but the storyboard launch screen size was all out of whack so for now will stick with the original approach I posted above (in 'didFinishLaunchingWithOptions) for my use case. Agree though that for setting a background color it works perfectly fine |
Uhm.. @mysport12 that should not be the case... Just to make sure, your code of the createRootView was something like this? - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initProps:(NSDictionary *)initProps
{
UIView * rootView = [super createRootViewWithBridge:bridge moduleName:moduleName initProps:initProps];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil];
[rootView setLoadingView:[[storyboard instantiateInitialViewController] view]];
rootView.loadingViewFadeDelay = 0.5;
rootView.loadingViewFadeDuration = 0.5;
return rootView;
? React Native does nothing specific with the View Controller, so as long as you use the UIView created by the framework, you should be good... Also, why you need to access the storyboard to retrieve the loading view? Can't it be (I'm trying to understand the use case, to make sure we can support everyone of you! 😊) |
Yes that's correct. Only difference being the rootView declared as RCTRootView to have access to the loading view methods/params.
We want the loading view to be the launch screen which just has a background color and a centered image (some of my apps have a slightly more complicated image arrangement). That way launch -> loading -> JS splash are consistent so the user doesn't perceive a difference as those transitions take place. The behavior witnessed was that the centered image was scaled pretty large to the point where it was clipped by the edges of the device. It almost seems like the bounds weren't correct. Could it be the order of operations of when the following line gets called?
in the code block from the AppDelegate.mm from react native
Prior to 0.71.0 when our individual apps called the code, the self.window logic was executed prior to the loading view logic. Just spitballing. I will try and dig into it more tonight/tomorrow. |
The gist of the above being that it seems to work when the loading view is set AFTER the window is set. Combined approaches with code snippets below for conciseness Pre 0.71.0 (working):
0.71.X
0.71.X createRootViewWithBridge (not working - launch screen image scaling oversized):
Appreciate the dialog and the assistance on this FWIW. It seems to have helped others as well which is always beneficial. |
@cipolleschi Ok I tried your example but it didn't take care of the white flash so I'm just going to stick with my original fix. The white flash happens when CodePush finishes downloading the new JS bundle and the JS app is restarted. I don't know enough to add any hypotheses of why your solution didn't work in my case, but I really appreciate your help and this discussion! |
Oh.. I understood what's the culprit. What we did, to simplify the client code, was to encapsulate the initialization logic into the In doing so, we moved the code as it was to that class, adding some hooks you can override to further customization. Among these hooks, there is So, given that you are actually updating the only property the AppDelegate is modifying, your change get lost. :( So sorry for this. I'll create a task for myself to expose a last resort method to customize the How does this sound? I'm sorry for the disruption it may has caused. |
@cipolleschi I'm not familiar enough with the native side of things to totally follow so this could be wrong but the line of code you reference at your link for "we preset the background color" is no longer present in React Native 0.71. It sounds like you are saying that since it's being set there, any changes we make later (i.e. with your new code) are being overridden. But in 0.71, that "setting" block is gone so it seems like it's not being set and therefore not overriding anything. I don't know if that's clear. If you want to find another solution that is better, that would be great, but honestly I'm happy with the solution I found for now. It's not been a huge disruption at all, and I thank you for your attention to this issue. |
Summary: When we introduced the RCTAppDelegate library, we prepared some template methods for the user to customise their views. However, after they customized their view, we were chaing the background color to match the system background. This would actually override the background color they set in their own customisation step. This change make sure that we set the background color before they apply their customisations. In this way, we set the background color and, if they want, they can change it and that changw would be honoured. This change also fixes [this issue](facebook#35937) Changelog [iOS][Fixed] - Honour background color customisation in RCTAppDelegate Differential Revision: D43435946 fbshipit-source-id: 0fe740eba816f42cbbdaa8ec65e6f1e6e76c7dc8
Summary: Pull Request resolved: facebook#36215 When we introduced the RCTAppDelegate library, we prepared some template methods for the user to customise their views. However, after they customized their view, we were chaing the background color to match the system background. This would actually override the background color they set in their own customisation step. This change make sure that we set the background color before they apply their customisations. In this way, we set the background color and, if they want, they can change it and that changw would be honoured. This change also fixes [this issue](facebook#35937) ## Changelog [iOS][Fixed] - Honour background color customisation in RCTAppDelegate Differential Revision: D43435946 fbshipit-source-id: 0e02c1b3bbbbfb1c7d75fbd08a74140da8e6cf5c
Summary: Pull Request resolved: #36215 When we introduced the RCTAppDelegate library, we prepared some template methods for the user to customise their views. However, after they customized their view, we were chaing the background color to match the system background. This would actually override the background color they set in their own customisation step. This change make sure that we set the background color before they apply their customisations. In this way, we set the background color and, if they want, they can change it and that changw would be honoured. This change also fixes [this issue](#35937) ## Changelog [iOS][Fixed] - Honour background color customisation in RCTAppDelegate Reviewed By: cortinico Differential Revision: D43435946 fbshipit-source-id: cdbdbd5b07082ae7843a4dab352dd1195c69e036
I'm seeing a blank white screen before my splash screen after upgrading too. Previously I solved the problem by adding this snippet below into self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view.backgroundColor = [UIColor colorWithRed:1.00 green:0.00 blue:0.40 alpha:1.00];
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible]; I tried using what you suggested @cipolleschi but I didn't have any luck. |
@cipolleschi How i can show the splash screen in the transition ,instead of showing a background color as u did above? |
@rifad4u it really depends on the kind of splashscreen you have. Is it a static image, handled by the catalog/plist? Is it a custom views? It may help to see what was your code before 0.71, so I can understand it better and suggest the best path forward. |
It is a static image only and i have configured it as like below |
Ok, I think that you can do it similarly to what I suggested above: // In AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.moduleName = @"InteropApp";
// You can add your custom initial props in the dictionary below.
// They will be passed down to the ViewController used by React Native.
self.initialProps = @{};
- return [super application:application didFinishLaunchingWithOptions:launchOptions];
+ BOOL result = [super application:application didFinishLaunchingWithOptions:launchOptions];
+ UIStoryboard *sb = [UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil];
+ UIViewController *vc = [sb instantiateInitialViewController];
+ self.window.rootViewController.view.loadingView = vc.view;
+ return result;
} |
Right, because the View returned by the So, the code I posted above must be changed to: //....
RCTRootView * rootView = (RCTRootView *) self.window.rootViewController.view;
rootView.loadingView = vc.view;
Return result; |
After it's fixed in a future release, should we still do it this way? |
@Dajust No, after the fix lands, the right way to do it will be to override the - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initProps:(NSDictionary *)initProps
{
// get the base, preconfigured view for React native
UIView * view = [super createRootViewWithBridge:bridge
moduleName:moduleName
initProps:initProps];
// Add your customisations
view.backgroundColor = [UIColor colorWithRed:1.00 green:0.00 blue:0.40 alpha:1.00];
// Return the customised view
return view;
} |
Hey all,
|
Summary: Pull Request resolved: facebook#36215 When we introduced the RCTAppDelegate library, we prepared some template methods for the user to customise their views. However, after they customized their view, we were chaing the background color to match the system background. This would actually override the background color they set in their own customisation step. This change make sure that we set the background color before they apply their customisations. In this way, we set the background color and, if they want, they can change it and that changw would be honoured. This change also fixes [this issue](facebook#35937) ## Changelog [iOS][Fixed] - Honour background color customisation in RCTAppDelegate Reviewed By: cortinico Differential Revision: D43435946 fbshipit-source-id: cdbdbd5b07082ae7843a4dab352dd1195c69e036
@cipolleschi We would appreciate if documentation can be updated => https://reactnative.dev/docs/publishing-to-app-store#pro-tips As well as how we can disable animation. With previous implementation all was good. Now we have to patch-package changes in RN0.71 and RN0.72 to put the old solution between |
Hi @professorkolik, thank for the question. Let me understand, it's only a matter of updating the doc or you feel blocked somehow? The proper way to apply these changes:
In 0.71 and onward, is to override - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initProps:(NSDictionary *)initProps; in your
We can update the documentation with this approach, if that's what you were looking for (or we welcome contributions to the website too! 😄 It is backed by this GitHub repo: https://github.com/facebook/react-native-website ). |
@cipolleschi Thank you for response! It's both documentation and block. And one comes from other, so we are blocked and I think may be I do smth wrong. I tried all the suggestions. It actually works, but not as expected or not as before. To give a background: We had a UIStoryBoard with app icon, when the bundle loaded we have the same SplashScreen component but with loading indicator, when StoryBoard hides for our users there is no change in behaviour just loading spinner appears. When I implement new way of controlling the Flash screen. I got behaviour that UIStoryBoard hides but with animation.
Changing this values to 0, doesn't work as well. To summarize, if I just put the solution from docs into didFinishLaunchingWithOptions of RCTAppDelegate.mm, between
Thank you again, any hint is appreciated 🙏 |
Ah... that's weird. 🤔 Just to make sure, you changed the private Would you be able to prepare a simple reproducer using this template? |
Both tried 😄
Definitely, though might take some time, thank you |
Hi @cipolleschi Just trying to work out, with version 0.71.xx, the correct way to go about preventing the blank screen flash between the splash screen and the display of the root application view. These are the now outdated but still live docs. Have tried the solutions on this thread but no luck so far. |
@joegoodall1 thanks for trying. Yeah, that doc is live but outdated. |
Here you go https://github.com/joegoodall1/whiteflashsplash Intentionally extremely simple changes (changed background of splash screen and 1st RN screen to red so white flash is visible) splash.mov |
@joegoodall1 before @cipolleschi will take a look, I don't see you applied suggested changes in AppDelegate.mm file. So I'm not sure what you expect |
@professorkolik Thanks for the quick response Do you mean like this?
Seeing this error with that code |
@joegoodall1 |
Yeah, the |
Now seeing this error |
I tested the repro and with the proper patch, it is fixed (no white flash anymore). This is the right fix for both architectures: // At the beginning of the AppDelegate.mm file
#import <React/RCTRootView.h>
#if RCT_NEW_ARCH_ENABLED
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#endif
// ...
- (UIView *)createRootViewWithBridge:(RCTBridge *)bridge
moduleName:(NSString *)moduleName
initProps:(NSDictionary *)initProps
{
UIView * view = [super createRootViewWithBridge:bridge moduleName:moduleName initProps:initProps];
#if RCT_NEW_ARCH_ENABLED
RCTFabricSurfaceHostingProxyRootView * rootView = (RCTFabricSurfaceHostingProxyRootView *)view;
#else
RCTRootView * rootView = (RCTRootView *)view;
#endif
// workaround:
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil];
UIViewController *vc = [sb instantiateInitialViewController];
rootView.loadingView = vc.view;
return rootView;
} The There is still a bug in the New Architecture that makes the flash appear, currently, but it is in the internals. It has to work this way. We are also working on the APIs to make sure we can soon remove those ugly But on the old architecture, it works properly. |
@cipolleschi Yep, that's done it 🙂 Thanks for the quick response |
This is the way i did it to to change - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.moduleName = @"DApp";
// You can add your custom initial props in the dictionary below.
// They will be passed down to the ViewController used by React Native.
self.initialProps = @{};
// check if app is loaded
BOOL success = [super application:application didFinishLaunchingWithOptions:launchOptions];
if (success) {
UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
// Force disable dark mode
if (@available(iOS 13.0, *)) {
rootViewController.view.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
// change rootView background
rootViewController.view.backgroundColor = [[UIColor alloc] initWithRed:0.0f green:0.0f blue:0.0f alpha:1];
}
return success;
} |
@fadi-quader-mox this is not the right way to do it. |
New Version
0.71.1
Old Version
0.70.6
Build Target(s)
iOS
Output of
react-native info
System:
OS: macOS 13.2
CPU: (10) arm64 Apple M1 Pro
Memory: 85.22 MB / 16.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 19.4.0 - /private/var/folders/lx/8pd1v4bj6656dm288zdsl9p00000gn/T/xfs-1926afa9/node
Yarn: 3.3.1 - /private/var/folders/lx/8pd1v4bj6656dm288zdsl9p00000gn/T/xfs-1926afa9/yarn
npm: 9.2.0 - /opt/homebrew/bin/npm
Watchman: 2023.01.16.00 - /opt/homebrew/bin/watchman
Managers:
CocoaPods: 1.11.3 - /Users/craig/.rvm/gems/ruby-2.7.6/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 22.2, iOS 16.2, macOS 13.1, tvOS 16.1, watchOS 9.1
Android SDK:
API Levels: 24, 25, 26, 27, 28, 29, 30, 31, 33
Build Tools: 28.0.3, 29.0.2, 29.0.3, 30.0.1, 30.0.2, 30.0.3, 31.0.0, 33.0.0
System Images: android-28 | Google Play Intel x86 Atom, android-29 | Google APIs Intel x86 Atom, android-29 | Google Play Intel x86 Atom, android-30 | Google APIs Intel x86 Atom, android-30 | Google APIs Intel x86 Atom_64, android-30 | Google Play Intel x86 Atom, android-30 | Google Play Intel x86 Atom_64
Android NDK: Not Found
IDEs:
Android Studio: 2021.3 AI-213.7172.25.2113.9123335
Xcode: 14.2/14C18 - /usr/bin/xcodebuild
Languages:
Java: 11.0.12 - /usr/bin/javac
npmPackages:
@react-native-community/cli: Not Found
react: 18.2.0 => 18.2.0
react-native: 0.71.1 => 0.71.1
react-native-macos: Not Found
npmGlobalPackages:
react-native: Not Found
Issue and Reproduction Steps
First of all, thank you for all the hard work improving React Native! The changes made to both the Android and iOS setup configs are great (and welcomed) however we are running into a challenge on iOS. Previously we could write something like the following:
to, in the user's eyes, delay the fade out of the launch screen to avoid the white flash between the native launch screen and our JS "splash" screen. This has been working well for countless releases. With the root view logic being internalized to the RN setup, it is not clear how to keep this behavior (if at all possible). From what I gather, the new architecture doesn't have a mechanism to accomplish this either. So the ask is 1) expose some config variables for (existing architecture) to keep this functionality in place for those that currently use it 2) implement a way for the new architecture to have this same behavior (eventually the switch will be made).
The text was updated successfully, but these errors were encountered: