ionic-team / ionic-v1

The repo for Ionic 1.x. For the latest version of Ionic, please see https://github.com/ionic-team/ionic
Other
192 stars 187 forks source link

Xcode 11 simulator changed device screen layouts & no longer honors safe-area code #410

Open rolinger opened 3 years ago

rolinger commented 3 years ago

THIS IS MORE AN FYI FOR THOSE STILL WORKING ON V1 APPS

Short description of the problem:

Xcode 11 simulator has now added window.outerHeight to all devices, reducing window.innerHeight by 20px on ALL iPhone and iOS types. Xcode 10 and lower did not use window.outerHeight and assigned the entire window height to window.innerHeight. This messes with screen layouts for Ionic v1 apps (maybe others too) that are analyzing inner/outer heights.. As well, Xcode 11 simulator does not honor safe-area code designed to keep apps below the notch on phones like iPhoneX/iPhone11

As you can imagine, if you can't trust what your apps looks like in Simulator how can you trust what it will really look like on real devices - and if you don't have every type of real device to test (which I don't) then you really risk deploying a prod app that doesn't render properly.

What behavior are you expecting?

Screen layouts are skewed and app is pushed up behind safe-area notch on iPhoneX/iPhone 11.

Steps to reproduce:

  1. Deploy v1 app to Xcode 11 simulator - any phone.

Details: XCode 11 Simulator Window Height:

For the window height issue, I use a custom frame for a map component on my app that sizes properly to any device screen layout. I had to modify it for Xcode 11 simulator because it without accounting for innerHeight it added a 20px buffer between the bottom the map frame to the bottom of the screen. To implement a fix for that I added the following:

  // use parseInt because some older phones would report heights as 49.5, or 43.2
  var statusBar = parseInt(document.getElementById('mapTitleBar').clientHeight) ;
  var tabBar = parseInt(document.getElementById('allTabsBar').clientHeight) ;
  var addressBar = parseInt(document.getElementById('map_addressFields').clientHeight) ;

  var totalBars = statusBar + tabBar + addressBar - deviceData.iosStatusBar ;
  var innerHeight = deviceData.windowInnerHeight  ;
  var outerHeight = deviceData.windowOuterHeight  ;
  if (outerHeight == 0) {
    var mapHeight = innerHeight - toolBars ;  // Xcode 10 and lower
  } else {
    var mapHeight = outerHeight - toolBars ;  // Xcode 11 and up.
  }
  document.getElementById("mapWrapper").style.height = mapHeight+"px" ;

Of course, there are other solutions for map wrappers/frames to auto fill the remainder of screens, but thats not the point here. I have mine for specific reasons and Apple has changed how it renders apps between Xcode 10 and Xcode 11 through the use of window.innerHeight for the first time.

Details: XCode 11 Simulator safe-area notch:

I have no solution for the safe-area problem. And this is frustrating because I can't see what my app is going to look like on various notch iPhones. And since I don't have 4 of every iPhone type (running iOS x10, x11, x12, x13) I can't see what my app will look like deployed across the various iOSs which risks there being a real issue when I deploy prod apps from Xcode 11.

I verified Xcode 10 Sim iPhoneX (iOS 11.4 and 12.4) against Xcode 11 Sim iPhoneX (iOS 11.4 & 12.4) and all devices on Xcode 10 rendered properly, but none rendered properly on Xcode 11. I did this check just to ensure it wasn't an iOS 12 vs 13 issue.

I rebuilt my app using cordova-plugin-ionic-webview, webview-plus and without any webview - it didn't matter. My app deployed to Xcode 11 simulator devices with the notch all showed my app status/menu bars pushed up behind the notch.

I need to find a way of Xcode 11 Sim iPhoneX iOS 12.4 app so that I can port the compiled version over to Xcode 10 simulators just to see if it renders correctly. Since you can't run iOS 13 on Xcode 10, I have to resort to testing only older iOS versions.

Does ANYONE have a solution for this?

PS: I will be testing my Xcode 11 Ionic v1 app later today on a real iPhone 11 to see if the Simulator issue is actually happening on real phones - I will report my findings then.

Which Ionic Version? 1.x or 2.x Ionic v1

revie commented 3 years ago

The one thing I had to do with Xcode 11 (and specifically iOS 13) is to adjust the iOS detection in Ionic at the isIPad() and setPlatform() checks:

  if (/iPad/i.test(self.navigator.platform) ||
      (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) {

My guess is that with Ionic unable to detect iPhones properly, the iOS CSS rules aren't being triggered because the "platform-ios" class isn't being added to the tag?

rolinger commented 3 years ago

@revie - I assume your fix is for the safe-area notch issue? Is it a fix specifically for the simulator or actual device deployment...or both? I will give this a shot and report back but at a 10,000 ft level I have doubts, because even on Simulators for iOS 11.4 and 12.4 the same issue is happening - its not specific to iOS 13. But it is, seemingly, specific to Xcode 11.

Also, which specific isIPad and setPlatform sections did you modify, there seem to be several of both throughout the project files.

revie commented 3 years ago

The fix was for general iOS detection which I use elsewhere for things such as for push notifications and in-app purchases, and wasn't specific to safe-area or simulators/physical devices. I did make the change everywhere in the Ionic bundle.js that dealt with iOS detection, which looks like it's a total of 3 areas, with a 4th being a change to isWebView, adding "Mac OS" to the regex.

Sorry, I didn't realize you were having issues with older iOS simulators too. Maybe you should do the usual notch-specific checks, such as using storyboards instead of splash screen images, "viewport-fit=cover" in your <meta name="viewport">, and making sure you have the latest cordova-plugin-splashscreen and cordova-plugin-statusbar? These are all changes you would've had to do for Xcode 10, which is why I didn't suggest it at first, but maybe Apple changed the older iOS simulators in Xcode 11 to support the iPad useragent change? Unlikely, but possible I guess.

I know Ionic v1 works on Xcode 11 on both iOS 12.4 and 13.6 simulators, and the iOS detection is really the only Ionic-specific change I had to make for my apps. Good luck!

rolinger commented 3 years ago

@revie - I just grabbed my neighbors iPhone11 Pro Max and the same issue regarding the "safe area" is happening on his phone too. So its not just simulators as I was hoping it was, its now a real production issue. At this point I don't think its necessarily an iOS 13 issue as much as it is an Xcode 11 issue. Because on older Xcode 10 everything deploys fine.

In fact, on his phone I downloaded active app on App Store to his phone and it runs perfectly - his phone is iOS 13, but that app was submitted with Xcode 10. Then from my new dev mac running Xcode 11, I loaded the app direct to his phone and the safe-area/notch issue is happening.

I do have the latest cordova-plugin-splashscreen and cordova-plugin-statusbar. All the same safe-area code and meta viewport tag are still in place, but something has def changed in Xcode 11 that is causing safe area to not work. Unless it requires some new techniques I am not aware of. I assume you aren't having the safe-area issue I am having (status/menu bars pushed up behind the notch) - and if NOT then I would really appreciate your assistance helping me figure out what I need to fix. I am freaking because I need to push a new version of my app soon but I can't do it if I know this UI issue is happening on iPhoneX/iPhone 11.

I am specifically using node@10 / gulp@3.9.1 to avoid Gulp 4 issues - so the ONLY thing different between code on older Mac running Xcode 10 and newer Mac running Xcode 11 is Xcode itself. Identical app code base, packages, installs everything.

My meta tag: <meta name="viewport" content="initial-scale=1, width=device-width, height=device-height, viewport-fit=cover">

And in my CSS:

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  padding-top: constant(safe-area-inset-top) ;
  padding-top: env(safe-area-inset-top) ;
}
.tabs {
  padding-top: constant(safe-area-inset-top) ;
  padding-top: env(safe-area-inset-top) ;
}

And when I use Safari Inspector I can see padding-top: env(safe-area-inset-top) is applied to the BODY tag

body {
display: flex;
flex-direction: column;
min-height: 100vh;
padding-top: constant(safe-area-inset-top);  // this line has strike through
padding-top: env(safe-area-inset-top);  // this is active line on element
}
revie commented 3 years ago

https://stackoverflow.com/questions/57084407/xcode-11-uilaunchimages-has-been-deprecated-use-launch-storyboards-instead-warn

Have you switched from launch images to using storyboards yet?

rolinger commented 3 years ago

@revie - i have not, but at the same time my app builds and launches just fine and the splashscreen/launch image shows just fine. How would this be related to safe-area issues on iPhoneX/iPhone11 ? I am reading your link and reading up on launch story boards.

rolinger commented 3 years ago

@revie - i just switched to a LaunchScreen.storyboard, the new image loads as the splash screen but my app is still pushed up behind the notch. Is there something from within Xcode I need to set regarding the app itself? I see when creating a storyboard you can set the 'safe zone/area` - is there something like that for the rest of the app too?

revie commented 3 years ago

Not that I know of, no. I just set my storyboards back when the iPhone X was released in 2017 to get safe zones working in my app, as per this Medium article:

https://medium.com/@robnorback/the-5-most-important-changes-you-need-to-make-for-the-iphone-x-ba5cdc7b5811

I just manage my launch storyboards in the Resources section of Xcode. I'm not seeing any "safe zone" settings there, but maybe it's being activated automatically when they're listed. From what I can tell, storyboards affect the rest of the app; there aren't any separate settings that I know of.

The only idea I have left is migrating off of UIWebView. Apple no longer accepts apps with references UIWebView, and although you mentioned you use cordova-plugin-ionic-webview, there are still references in there as well as cordova-ios that need to be removed, and were only recently fixed a month or so ago. Have you tried upgrading to the latest cordova-ios and cordova-plugin-ionic-webview? It's unlikely this is causing the issues you're seeing, but it's something you have to do anyways if you want your app in the app store, if you haven't already.

Good luck.

rolinger commented 3 years ago

@revie - turns out my v1 app was already using CDVLaunchScreen.storyboard - it was buried down in the resources and didn't know it was there. I recall months ago (on old Mac with Xcode 10) that I had to go through some new launchscreen gymnastics to get things working right. In Xcode looking at the storyboard View Controller - View the default view was using:

Top Layout Guide & Bottom Layout Guide - the Interface Builder document was not set to use Safe Area Layout Guides - so I checked that and held my breath thinking it might provide the boundaries on the iPhoneX. I deployed to Simulator and NOPE - it didn't help.

But the fact that I do have storyboards in place is good. I think maybe it came from cordova-res. However I removed the UIWebView (webview-plus) and replaced with cordova-plugin-ionic-webview and again it had no impact or change on the safe-area issue.

Losing my mind on this one!

revie commented 3 years ago

"Use Safe Area Layout Guides" is unchecked in my apps, and when I check it, it gives me an "Illegal Configuration" error, saying "Safe Area Layout Guide before iOS 9.0". Maybe under "Deployment Info" you have a newer iOS target specified? Ionic targets the lowest by default, which for Xcode 11 is "iOS 8.0".

rolinger commented 3 years ago

@revie - gotta tell ya, was hoping to make it one or two more rev's of my Ionic v1 app which would give me the time I need to finally take the plunge into Ionic 4/5. The fact that your Ionic v1 app isn't having this issue encourages me there is a solution to my Xcode 11 problem. Still working on it. Thanks for your help, I have def learned a few things as a result of your input. Gonna take a break for a good day and let my brain reboot - maybe I can tackle this better with a fresh mind.

rolinger commented 3 years ago

@revie - well, I had a bit of progress. My meta tag was off...in Xcode 10 though the same meta tag worked, but not in Xcode 11, when I updated the meta tag to the proper syntax it moved the app down, but it left the ion-nav-title section still up behind the notch - with a 20px gap between the ion-nav-title and the rest of the app. Its like something else is pinning the title-bar to the top. You can see more of what I am talking about in the images I added to this stackoverflow post: https://stackoverflow.com/questions/62946011/xcode-11-simulator-window-height-and-notch-safe-areas-not-working-properly

Thoughts?!

rolinger commented 3 years ago

@revie - at my wits end on why this is happening. If I apply position:relative to the <ion-nav-bar> the status bar moves down to where it should be (referencing picture #2 in that stackoverflow in previous message). Outside of finding the root cause for this, I am almost on the verge of using JS to ID the phone type and if iPhoneX/iPhone11 (or devices with the notch) than apply position:relative; to the ion-nav-bar. Not certain what else to do at this point!

rolinger commented 3 years ago

@revie - so, in my app.js I had to add:

    if (ionic.Platform.isIOS()) {
      if (document.getElementById('ionNavBar')) {
        var ionNavBar = document.getElementById('ionNavBar') ;
        ionNavBar.style.position = 'relative' ;
      }
   }

I have tested on multiple iPhone simulators with and without the notch, and adding this code does not seem to impact anything else. Until I can find what is pinning the <ion-nav-bar> up behind the notch/safe-area I am just going to have to go with this.

revie commented 3 years ago

Or instead you could just set this in your CSS:

.platform-ios #ion-nav-bar { position: relative; }

rolinger commented 3 years ago

@revie - losing my mind.

Can you share all the exact locations you had to append for iOS detection. At this point I think the root of all my issues has to do with Xcode 11.5. On older mac with Xcode 10, everything deploys just fine to both iPhone 8 (no notch) and to iPhoneX (notch). But on new Mac with Xcode 11 the <meta> tag and the padding-top: env(safe-area-inset-top) ; are screwing up notch and notchless iPhones. On iPhone 8/7/6 its (running iOS12.x) its causing a gap between the ion-nav-bar and the rest of the app and on iPhoneX/11 its pinning the ion-nav-bar up behind the notch, and the same gap between ion-nav-bar and the rest of the app. The gap is the "safe-area" size of about 20px.

In my index.html: <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">

And in my css:

body {
  padding-top: constant(safe-area-inset-top) ;
  padding-top: env(safe-area-inset-top) ;
}

Should there be anything else?

revie commented 3 years ago

If you have an extra 20px gap in iPhone 8/7/6, that means you're running an old version of cordova-plugin-statusbar or cordova-plugin-splashscreen, or you're missing the following in your config.xml:

   <platform name="ios">
      <preference name="StatusBarOverlaysWebView" value="true" />
   </platform>
rolinger commented 3 years ago

@revie - first off, thanks for all your help. I checked my plugin versions and statusbar is the current version (v2.4.3) but my splashscreen was on v5.0.2 - so I updated it to the latest v6.0.0. I also did not have that preference set so I added it to my config.xml file - and after all that, no change. Still have gap on both phone types, however the gap on the iPhoneX is twice as tall/height as the one on the iPhone8.

Upon further inspection, on the iPhone8, the padding-top:env(safe-area-inset-top) is being applied and that is what is causing the gap - my understanding is that wouldn't be applied to non-notch phones but for some reason it is. Is that supposed to be added to non-notch phones? Which brings me back to wondering if Xcode 11 is the source. But the fact its not happening on your Ionic v1 apps means there is a fix for this - but what it is I have no idea. I feel that whatever the issue is, that the fix for one phone type will also fix the other phone type.

revie commented 3 years ago

Any iPhone running 11 or newer sets safe-area-inset-top, whether a notched phone or not, so this isn't an Xcode issue, but rather the statusbar. A notched phone does have safe-area-inset-top set to a different value than a non-notched phone (40px vs 20px), but that's it.

All signs point to cordova-plugin-statusbar. Maybe your setting wasn't recognized by your test build? Make sure it's set correctly, as per the plugin docs, and then maybe reinstall the plugin?

https://github.com/apache/cordova-plugin-statusbar/

If all else fails, then it's probably your CSS. Use Safari and walk through the DOM to make sure the spacing is correct.

rolinger commented 3 years ago

@revie - throwing my hands up....for now.

To deal with this, I wrote a function that detects phones with a notch, if true, then apply CSS to BODY and to ION-NAV-BAR:

I DO NOT like doing this but at the moment I have wasted several days tracking down this problem and I am plum outta ideas.

function hasNotch() {
  if (CSS.supports('padding-bottom: env(safe-area-inset-bottom)')) {
    let div = document.createElement('div');
    div.style.paddingBottom = 'env(safe-area-inset-bottom)';
    document.body.appendChild(div);
    let calculatedPadding = parseInt(window.getComputedStyle(div).paddingBottom, 10);
    document.body.removeChild(div);
    if (calculatedPadding > 0) {
      return true;
    }
  }
  return false;
}

And in app.js:

    if (ionic.Platform.isIOS()) {
      ionic.Platform.fullScreen();
      if (hasNotch() == true) {
        console.log("NOTCH FOUND") ;
        document.getElementById("body").style.paddingTop = "env(safe-area-inset-top)" ;
        document.getElementById("ionNavBar").className += " ioNavBar" ;
      }
  }

CSS:

.ionNavBar {
  position: relative;
}

While researching this issue I came across android devices that now have the notch too - probably going to move the above outside the isIOS() function and make it global.

raedweb commented 3 years ago

Hi Folks, Do you have a similar solution for Cordova hybrid mobile app to fix the notch issue on a design using kWebview