iPhone X support

ios

#1

Just wanted to share a quick tip because I figured out how to do this today.

Don’t target iPhone X specifically
Make sure you don’t specifically optimize for iPhone X (based on its screen size), but rather for the so-called “safe insets” that Apple is now imposing on us (the poor designers and developers that have to cope with this nonsense). Why? Because the next iPad may very well have the same issue (a swipe-indicator instead of a home button… and perhaps even worse: also a notch.).

My approach
I’m using Angular, so non-Angular users may need to ‘transpile’ this approach a bit.

The example I’d like to use here is a button that’s positioned at the bottom of the screen. All those buttons in my app have the same css class button-bottom-nav (note that you can of course add a new class like bottom-inset, but that’s not the point here). The point is: we’re going to alter that css class a bit at runtime in case we’re running on an iPhone X (click the image if you don’t see the green button at the bottom):


The ‘Betalen’ (‘Pay now’) label is almost obscured by the swipe indicator.

NativeScript native access to the rescue
Let’s use the new UIWindow.safeAreaInsets which has a .top and .bottom property. On non-iPhone X devices those insets are 0, but on iPhone X those are 44 and 34 respectively (IIRC).

In app.component.ts I have a ngOnInit which of course runs only once during the app’s lifetime, so that’s an excellent spot to add some iOS tweaks:

export class AppComponent implements OnInit {
  ngOnInit(): void {
    if (isIOS && application.ios.window.safeAreaInsets) {
      const bottomSafeArea: number = application.ios.window.safeAreaInsets.bottom;
      if (bottomSafeArea > 0) {
        application.addCss(`
            Button.button-bottom-nav { padding-bottom: ${bottomSafeArea} !important }
        `);
      }
    }
  }
}

Now the button looks awesome on iPhone X - and no changes were applied to any other device:

One more thing
Is your app hiding the ActionBar and have a fullscreen background? Then also allow the background to span underneath the statusbar. Otherwise you’ll have a white area where the statusbar sits:

this.page.actionBarHidden = true;
this.page.backgroundSpanUnderStatusBar = true; // add this

#2

Thanks @Eddy
Here’s @davecoffin’s way of handling it,
in NS Core
http://www.davecoffin.com/blog/9-25-17-ios-safe-areas


#3

Ah noice! Excellent blog! Seems like Dave’s using the screen dimensions which I wouldn’t advocate though. :kissing_heart:


#4

@eddy Yea I like your approach way better! Mine I threw together days after xcode 9 came out. I’ll update my blog.


#5

Great! This is something we’re almost always gonna need in every iOS app, we should get something like this in the core & docs


#6

@sitefinitysteve I totally agree with you on that


#7

I borrowed from @NathanaelA for my implementation. In my app, all our main views have the same wrapping elements, and their components extend our PageComponent class. So I just setup a boolean to be checked in the constructor:

checkIsiPhoneX(): boolean  {
        if (!isIOS) {
            return false;
        }

        // See: https://github.com/NativeScript/ios-runtime/issues/698
        const _SYS_NAMELEN: number = 256;

        /* tslint:disable-next-line: no-any */
        const buffer: any = interop.alloc(5 * _SYS_NAMELEN);
        uname(buffer);
        let name: string = NSString.stringWithUTF8String(buffer.add(_SYS_NAMELEN * 4)).toString();

        // Get machine name for Simulator
        if (name === 'x86_64' || name === 'i386') {
            name = NSProcessInfo.processInfo.environment.objectForKey('SIMULATOR_MODEL_IDENTIFIER');
        }

        return name.indexOf('iPhone10') === 0;
    }

That’s a reduced version of what I found in the nativescript-platform-css plugin.

Once you have that, you use that boolean to set a class (like “iphonex”) on the topmost wrapping element you have access too. If you’re in an angular app, then you just use the /deep/ rule to add rules specifically for it!

/deep/ .iphonex & {
    margin-top: 30;
}

#8

Or you could wait until this PR is merged into master branch :slight_smile:
https://github.com/NativeScript/NativeScript/pull/4893

There you will get safeAreas for iOS11, layoutGuides for iOS<11 and many more goodies (and changes)


#9

I just upgraded to NS 3.3 and Xcode 9. My splash (launch) screen has white space at the bottom of iPhone X.

I tried creating a default ng app to cross check whether it is just with my app, it was same white space at the bottom even there. Any idea how to fix that, do I need a bigger image at LaunchScreen.AspectFill.imageset, may @3x?


#10

I had this problem and got around it by opening the LaunchScreen.Storyboard file on Xcode, deleting the default Image View in the View, replacing it with a new Image View that uses LaunchImage as its source (rather than LaunchScreen.AspectFill), and then stretching it over the entire View and setting it’s autoresizing to expand along with the screen. However, I doubt that this is best practice and am sure that there’s a better solution.


#11

Can someone help us with iPhone X adaptions? When I run our app in the iPhone Simulator it looks fine and uses the fullscreen of the iPhone X - as soon as I release it via TestFlight it has a border at the top and bottom, so it is not optimized to use fullscreen. We haven’t added something iPhone X specific, do I need to?


#12

If anyone is having problems with a white bar on the bottom of your splashscreen for iPhone X devices, I wrote up a quick blog post on how I fixed it in Xcode with detailed pics: https://blog.angelengineering.com/nativescript-splashscreen-iphonex/


#13

Im getting an error in the console: “CONSOLE ERROR [native code]: ERROR ReferenceError: Can’t find variable: application”, should I be importing something? Sorry, I’m new to this.


#14

Yes, you are suppose to import application.

import * as application from 'application';


#15

Excellent thank you!