Skip to content
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

[expo-screen-orientation] Screen orientation does not lock or trigger with EAS Build #15009

Closed
brycnguyen opened this issue Nov 2, 2021 · 92 comments
Assignees

Comments

@brycnguyen
Copy link

Summary

On a built app with EAS build, calling https://docs.expo.dev/versions/latest/sdk/screen-orientation/#screenorientationlockasyncorientationlock does not trigger the screen to rotate and lock on iOS.
When the app isn't built with EAS build, and created with expo build, the screen orientation lock async function works.

Could possibly be related to: #11558

Managed or bare workflow? If you have ios/ or android/ directories in your project, the answer is bare!

managed

What platform(s) does this occur on?

iOS

SDK Version (managed workflow only)

43

Environment

Expo CLI 4.12.10 environment info:
System:
OS: macOS 11.6
Shell: 5.8 - /bin/zsh
Binaries:
Node: 14.15.1 - ~/.nvm/versions/node/v14.15.1/bin/node
Yarn: 3.0.2 - ~/.nvm/versions/node/v14.15.1/bin/yarn
npm: 6.14.8 - ~/.nvm/versions/node/v14.15.1/bin/npm
Watchman: 2021.06.07.00 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.11.2 - /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4
Android SDK:
API Levels: 30, 31
Build Tools: 29.0.2, 30.0.2, 31.0.0
System Images: android-30 | Google APIs Intel x86 Atom, android-30 | Google Play Intel x86 Atom, android-31 | Android TV Intel x86 Atom, android-31 | ARM 64 v8a, android-31 | Intel x86 Atom_64, android-31 | Google TV Intel x86 Atom, android-31 | Google APIs ARM 64 v8a, android-31 | Google APIs Intel x86 Atom_64, android-31 | Google Play ARM 64 v8a, android-31 | Google Play Intel x86 Atom_64
IDEs:
Android Studio: 4.1 AI-201.8743.12.41.6953283
Xcode: 12.5.1/12E507 - /usr/bin/xcodebuild
npmPackages:
expo: ^43.0.0 => 43.0.1
react: 17.0.1 => 17.0.1
react-dom: 17.0.1 => 17.0.1
react-native: 0.64.2 => 0.64.2
react-native-web: 0.17.1 => 0.17.1
npmGlobalPackages:
expo-cli: 4.12.10
Expo Workflow: bare

Reproducible demo or steps to reproduce from a blank project

  1. Create a build with EAS Build for iOS
  2. Call the function https://docs.expo.dev/versions/latest/sdk/screen-orientation/#screenorientationlockasyncorientationlock
  3. Foregrounding/backgrounding the app and calling the function again does not trigger the screen to lock orientation.
@brycnguyen brycnguyen added the needs validation Issue needs to be validated label Nov 2, 2021
@brycnguyen brycnguyen changed the title Screen orientation does not lock or trigger with EAS Build [expo-screen-orientation] Screen orientation does not lock or trigger with EAS Build Nov 2, 2021
@ironforward
Copy link

ironforward commented Nov 22, 2021

also using EAS and experiencing this behavior.

i can call ScreenOrientation.unlockAsync() and then ScreenOrientation.getPlatformOrientationLockAsync() will return

{
  screenOrientationArrayIOS: [
    1, // Orientation.PORTRAIT_UP
    3, // Orientation.LANDSCAPE_LEFT
    4, // Orientation.LANDSCAPE_RIGHT
  ]
}

however, the screen will not rotate when tilting the phone -- made sure portrait lock was turned off on the phone too.

calling ScreenOrientation.lockAsync(OrientationLock.LANDSCAPE_RIGHT) does not have any effect either, but no errors are thrown.

app.json does have "orientation": "portrait"; however, the expo-screen-orientation docs say it will override this and, at least from what it's returning in the getPlatformOrientationLockAsync, it does seem to think it's overriding it.

edit: also did set expo.ios.requireFullScreen = true as the expo-screen-orientation docs say to do.

@ironforward
Copy link

a quick update, setting the expo.ios.infoPlist option in app.json to support landscape like so:

"infoPlist": {
    "UISupportedInterfaceOrientations": [
        "UIInterfaceOrientationLandscapeRight",
        "UIInterfaceOrientationLandscapeLeft",
        "UIInterfaceOrientationPortrait"
    ],
    "UISupportedInterfaceOrientations~ipad": [
      "UIInterfaceOrientationLandscapeRight",
      "UIInterfaceOrientationLandscapeLeft",
      "UIDeviceOrientationPortrait",
      "UIDeviceOrientationPortraitUpsideDown"
    ]
}

does enable rotating the screen into landscape.

however, expo-screen-orientation still fails to override the orientation locks at runtime to disable landscape orientation when it is not wanted.

so, i think this at least rules out landscape being disabled in the build settings as the reason that expo-screen-orientation could not allow landscape orientation, since it now cannot disallow landscape at runtime either.

@fwidtmann
Copy link

fwidtmann commented Nov 30, 2021

Is there any update? We need to lock orientation to landscape in one view! (expo go works, but with expo run:ios or eas build its not working)

Or are there any workarounds?

@silberistgold
Copy link

Experiencing the same issue. Used to work before transitioning to eas build, but now calling ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT) does nothing.

@fwidtmann
Copy link

@silberistgold if you remove orientation option in app.json, it will work again... but its no good solution

@silberistgold
Copy link

I see. Could be viable workaround to remove "orientation": "portrait" from app.json and then do ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP) immediately after app start (e.g. in an effect in App.tsx). I will test this and share my findings.

@richardwu
Copy link

The issue I'm experiencing is that while removing "orentation": "portrait" allows you to lock on first load, it fails to work after backgrounding/foregrounding the app, as noted here #11558. A fix seemed to have pushed out and should be live in SDK 43, but it doesn't seem to be working for me.

@ironforward
Copy link

ironforward commented Dec 13, 2021

Surprisingly even though the expo-screen-orientation library fails to detect orientation changes, DeviceMotion does not.

So, as a workaround for now if you only need 1 or a few screens to rotate like i did, you can listen for orientation changes from DeviceMotion in the expo-sensors library and rotate the screen yourself using reanimated (or whatever your animation library of choice is).

@richardwu
Copy link

richardwu commented Dec 13, 2021

Surprisingly even though the expo-screen-orientation library fails to detect orientation changes, DeviceMotion does not.

So, as a workaround for now if you only need 1 or a few screens to rotate like i did, you can listen for orientation changes from DeviceMotion in the expo-sensors library and rotate the screen yourself using reanimated (or whatever your animation library of choice is).

My current workaround does exactly this (rotate the content), but the downside is the status/notif bar remains in portrait mode, which is annoying for some users.

@silberistgold
Copy link

I can confirm that the workaround mentioned above is working for me. App correctly stays locked in PORTRAIT_UP until I unlock or lock to a different orientation. Also no issues after backgrounding/foregrounding the app. I am using SDK 43 managed.

@fwidtmann
Copy link

@silberistgold can you provide a code example? you use https://docs.expo.dev/versions/latest/sdk/devicemotion/ ?

@watchinharrison
Copy link

watchinharrison commented Dec 14, 2021

@fwidtmann I think @silberistgold was referring to their workaround which I can also confirm works, removing the orientation config from app.json/app.config.js. And controlling the lock from within the app using expo-screen-orientation. Seems having the config is what breaks the functionality of expo-screen-orientation on EAS build.

@fwidtmann
Copy link

@watchinharrison but if we remove orientation from app.json, there is no lock.

i think @silberistgold got it work with orientation in app.json, just switching from expo-screen-orientation to DeviceMotion?

@silberistgold
Copy link

@watchinharrison exactly.

I removed "orientation": "portrait" from app.json and lock the orientation on app start using ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP). Then later I unlock/relock again using ScreenOrientation as needed.

@fwidtmann
Copy link

@silberistgold ah ok, thank you

@mercpls
Copy link
Contributor

mercpls commented Jan 31, 2022

Still seeing this issue in Expo SDK44. Did an upgrade from 42 -> 43 -> 44. Readded Expo updates and still do not have any orientation working.

@brycnguyen
Copy link
Author

Another alternative if you are using eas is to create a config-plugin to work with https://github.com/yamill/react-native-orientation. I've moved completely off expo-screen-orientation because of this bug.

@ErikTromp
Copy link

I am having this issue too. @brycnguyen I also wasn't able to turn this into a config-plugin properly, do you have some pointers?

@navuyi
Copy link

navuyi commented Feb 9, 2022

I was having issues with changing screen orientation as well. For me it was related to switching between background and foreground and rebooting the app after some time of inactivity (spent in background). The goal was to switch from landscape (which was desired only for one view - video playback) back to portrait mode. Switching the screen orientation combined with app reload resulted in weird and undesired changes of screen orientation to landscape where it should be portrait.

I removed "orientation" key from app.json and updated expo SDK from 42 to 43. It helped.
I also use orientation lock in on the app load so it stays in portrait mode. Then I switch to landscape during the video playback.

@brycnguyen
Copy link
Author

brycnguyen commented Feb 17, 2022

@ErikTromp, you can try my attempt at the plugin here: https://github.com/LyraHealth/react-native-orientation-plugin
or modify it so that it works for your app. Let me know if it works for you. Thanks!

@ErikTromp
Copy link

@brycnguyen thanks, that helps!

@Livijn
Copy link

Livijn commented Mar 30, 2022

I tried adding this and got an error when running eas:

        "UISupportedInterfaceOrientations": [
          "UIInterfaceOrientationPortrait"
        ],
        "UISupportedInterfaceOrientations~ipad": [
          "UIDeviceOrientationPortrait"
        ]

ios.requireFullScreen: iPad multitasking requires all UISupportedInterfaceOrientations~ipad orientations to be defined in the Info.plist. The Info.plist currently defines values that are incompatible with multitasking, these will be overwritten to prevent submission failure. Existing: UIDeviceOrientationPortrait

@jennkirchner
Copy link

We've seen screen orientation issues in 42, resolved in 43, and then reintroduced in 44. In our case we set app.config.js orientation: 'landscape' and lock the position in App.js using AppLoading component startAsync prop. In this case, we see the screen rotate erratically

@hugoh59
Copy link

hugoh59 commented May 25, 2022

Same issue here in 44.

@lewis221
Copy link

lewis221 commented May 30, 2022

facing the same issue in 44

@tenfef
Copy link

tenfef commented May 30, 2022

Same issue here in 44...

@seba9999
Copy link

Still got this too 👍

@blixit
Copy link

blixit commented Feb 23, 2023

I have the same issue.
It looks like the problem disappears when you build a release application

@lordprana
Copy link

Same here.

@linkeddg
Copy link

Also encountering this issue with our latest build.

@singlecolor
Copy link

singlecolor commented Feb 28, 2023

Also encountering this on SDK 47 with Expo Go and EAS builds on iPad 6, since upgrading it to iPadOS 16.1.1. The issue does not occur on our iPhone running iOS 15.5.

Has this been fixed in SDK 48? If so we will upgrade.

@lordprana
Copy link

lordprana commented Mar 5, 2023

There are repro steps with a snack for this issue in this other issue I filed: #21044

@yohamta
Copy link

yohamta commented Mar 8, 2023

Same here. It seems to be not working properly since v44. #19690

@mvanroon
Copy link

mvanroon commented Mar 8, 2023

These "same here"/"me too" comments aren't helpful at all. Please consider only replying to issues with new information.

And for those who feel like it's taking the maintainers too long to fix this: keep in mind that this is open-source software. Expo is a complex piece of software. If you want it fixed ASAP, create a pull request.

@ulascanerturk
Copy link

The problem occurs when you try to change the screen orientation to landscape when switching to another page while the screen orientation is portrait. If you change the screen orientation on the same page (or screen) there would be no error. So my fix is to call the new page in portrait mode and put a timer. After the timer finish turn the screen. The error will be fixed.

componentDidMount () {
    setTimeout( async () => {
        await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE_LEFT); 
    }, 1000);
    this.fetchData();
}

You can add ActivityIndicator while the timer is working.

@PiotrSzlagura
Copy link

PiotrSzlagura commented Mar 21, 2023

I'm facing similar problem with Expo 47, but there I have a little twist - if I do:

await ScreenOrientation.lockAsync(
  ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT
);
await ScreenOrientation.lockAsync(
  ScreenOrientation.OrientationLock.DEFAULT
);

then it seems to reset screen orientation lock and from here on everything works as intended, but if I do just

await ScreenOrientation.lockAsync(
  ScreenOrientation.OrientationLock.DEFAULT
);

then it does not. Problem is - locking and unlocking orientation like this results in ugly layout shifts which my client would never accept. I also tried:

await ScreenOrientation.lockAsync(
  ScreenOrientation.OrientationLock.PORTRAIT// also _UP and _DOWN
);
await ScreenOrientation.lockAsync(
  ScreenOrientation.OrientationLock.DEFAULT
);

but doing it like so won't reset orientation locking.

EDIT:

I managed to find an interesting workaround for this issue, it looks like this:

import { Dimensions } from "react-native";
import * as ScreenOrientation from "expo-screen-orientation";

function getIsLandscape(screen) {
  return screen.width > screen.height;
}

async handleDimensionsChange(newDimensions) {
  const isLandscape = getIsLandscape(newDimensions.screen);

  if (isLandscape) {
    await ScreenOrientation.lockAsync(
      ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT
    );
  } else {
    await ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP);
  }
}

Dimensions.addEventListener(
  "change",
  this.handleDimensionsChange
);

Since Dimensions report orientation change just fine (they get updated on orientation change with or without lock), I was able to use it for orientation change detection and use screen width/height ratio to determine how should I lock orientation.

It works nice, though keep in mind that by using it you limit your app to use only one landscape variant.

EDIT 2:

Above fix seemed nice, but it only worked on dev client, turns out this doesn't work in standalone build. I ended up implementing my own screen orientation handler using Accelerometer, it looks like this:

import React from "react";
import * as ScreenOrientation from "expo-screen-orientation";
import { Accelerometer } from "expo-sensors";
import autoBind from "auto-bind";

class ScreenOrientationSetter extends React.Component {
  state = {
    orientation: ScreenOrientation.OrientationLock.PORTRAIT_UP
  };

  constructor(props) {
    super(props);

    autoBind.react(this);
  }

  async handleAccelerometerData(data) {
    let newOrientation = this.state.orientation;
    
    // Thresholds here are set arbitrarily, 
    // but after fiddling with it a little I found them to be quite nice

    if (data.y < -0.8) {
      newOrientation = ScreenOrientation.OrientationLock.PORTRAIT_UP;
    } else if (data.x < -0.8) {
      newOrientation = ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT;
    } else if (data.x > 0.8) {
      newOrientation = ScreenOrientation.OrientationLock.LANDSCAPE_LEFT;
    }

    if (newOrientation !== this.state.orientation) {
      await ScreenOrientation.lockAsync(newOrientation);
      this.setState({ orientation: newOrientation });
    }
  }

  async componentDidMount(): void {
    this.accelerometerListener = Accelerometer.addListener(
      this.handleAccelerometerData
    );
    Accelerometer.setUpdateInterval(1000);
  }

  componentWillUnmount(): void {
    this.accelerometerListener.remove();
  }

  render() {
    // ...
  }
}

@rubrubadubdub
Copy link

For me, adding expo-sensors as a dependency solved the issues I was having with this library

Don't forget to make a new development build after adding the new package

I also deleted the "orientation" param from app.json and instead configured the plugin like so:

    "plugins": [
      [
        "expo-screen-orientation",
        {
          "initialOrientation": "DEFAULT"
        }
      ],
    ],

Using this method I managed to solve our issues with expo-screen-orientation. Interestingly enough just adding expo-sensors as a dependency and removing the expo orientation param solved the problems we were having on ios. We did not test if the issue persisted on Expo GO, but it works on our latest EAS build.

@behenate behenate self-assigned this May 16, 2023
@AntonioGally
Copy link

About the @PiotrSzlagura implementation of accelerometers, I made a customHook for it and worked for me.

useAccelerometer.ts

import { useEffect, useState } from "react";
import { Accelerometer } from 'expo-sensors';
import type { Subscription } from "expo-clipboard";

const useAccelerometer = () => {
    const [{ x, y, z }, setData] = useState({
        x: 0,
        y: 0,
        z: 0,
    });
    const [subscription, setSubscription] = useState<Subscription | null>(null);

    const _slow = () => Accelerometer.setUpdateInterval(1000);
    const _fast = () => Accelerometer.setUpdateInterval(16);

    const _subscribe = () => {
        setSubscription(
            Accelerometer.addListener(setData)
        );
    };

    const _unsubscribe = () => {
        subscription && subscription.remove();
        setSubscription(null);
    };

    useEffect(() => {
        _subscribe();
        _slow();
        return () => _unsubscribe();
    }, []);

    return { screenX: x, screenY: y }
}

export default useAccelerometer;

App.jsx (rip tsx)

    const [orientation, setOrientation] = useState(ScreenOrientation.OrientationLock.PORTRAIT_UP);
    const { screenX, screenY } = useAccelerometer();
    const memoX = useMemo(() => screenX.toFixed(1), [screenX]);
    const memoY = useMemo(() => screenY.toFixed(1), [screenY]);

    useEffect(() => {
        async function handleAccelerometerData() {
            let newOrientation = orientation;
            if (memoY < -0.8) {
                newOrientation = ScreenOrientation.OrientationLock.PORTRAIT_UP;
            } else if (memoX < -0.8) {
                newOrientation = ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT;
            } else if (memoX > 0.8) {
                newOrientation = ScreenOrientation.OrientationLock.LANDSCAPE_LEFT;
            }

            if (newOrientation !== orientation) {
                await ScreenOrientation.lockAsync(newOrientation);
                setOrientation(newOrientation);
            }
        }
        handleAccelerometerData();
    }, [memoX, memoY, orientation]);

@PiotrSzlagura
Copy link

@AntonioGally This hook looks really nice! By the way, one thing I found after finishing my implementation is that positive and negative values for X and Y are flipped between Android and iOS (my implementation is correct for iOS devices).

@AntonioGally
Copy link

@PiotrSzlagura true! Thanks a lot, you saved me here. I was on a rush as usual. Guys, feel free to upgrade this code and stuff. An updated use for the customHook:

App.jsx

    useEffect(() => {
        async function handleAccelerometerData() {
            const androidPortraitUp = (memoX >= -0.8 && memoX <= 0.2) && (memoY >= 0.8 && memoY <= 1.2);
            const androidLandscapeRight = (memoX >= 0.8 && memoX <= 1.2) && (memoY >= -0.8 && memoY <= 0.2);
            const androidLandscapeLeft = (memoX >= -1.2 && memoX <= -0.8) && (memoY >= -0.8 && memoY <= 0.2);

            let newOrientation = orientation;
            if (isIOS ? (memoY < -0.8) : (androidPortraitUp)) {
                newOrientation = ScreenOrientation.OrientationLock.PORTRAIT_UP;
            } else if (isIOS ? (memoX < -0.8) : (androidLandscapeLeft)) {
                newOrientation = ScreenOrientation.OrientationLock[isIOS ? "LANDSCAPE_RIGHT" : "LANDSCAPE_LEFT"];
            } else if (isIOS ? (memoX > 0.8) : (androidLandscapeRight)) {
                newOrientation = ScreenOrientation.OrientationLock[isIOS ? "LANDSCAPE_LEFT" : "LANDSCAPE_RIGHT"];
            }

            if (newOrientation !== orientation) {
                await ScreenOrientation.lockAsync(newOrientation);
                setOrientation(newOrientation);
            }
        }
        handleAccelerometerData();
    }, [memoX, memoY, orientation]);

I've tested on AndroidStudio that can handle the accelerators sensors pretty well. In IOS I tested on my Iphone XR by testFlight and worked as well.

@watadarkstar
Copy link

watadarkstar commented Jun 13, 2023

For those who need a solution that works for both iOS and Android. Here is mine:

useAccelerometer.ts

import { useEffect, useState } from "react"
import { Accelerometer } from "expo-sensors"

const useAccelerometer = () => {
  const [{ x, y }, setData] = useState({
    x: 0,
    y: 0,
  })

  useEffect(() => {
    const subscription = Accelerometer.addListener(setData)

    Accelerometer.setUpdateInterval(1000)

    return () => {
      subscription?.remove()
    }
  }, [])

  return { screenX: x, screenY: y }
}

export default useAccelerometer

useSetOrientation.ts

export const useSetOrientation = () => {
  const { screenX, screenY } = useAccelerometer()
  const memoX = useMemo(() => screenX, [screenX])
  const memoY = useMemo(() => screenY, [screenY])
  const platformOS = Platform.OS
  const isAndroid = platformOS === "android"

  useEffect(() => {
    async function handleAccelerometerData() {
      let newOrientation = ScreenOrientation.OrientationLock.PORTRAIT_UP

      if (memoY < -0.8) {
        newOrientation = ScreenOrientation.OrientationLock.PORTRAIT_UP
      } else if (memoX < -0.8) {
        newOrientation = isAndroid
          ? ScreenOrientation.OrientationLock.LANDSCAPE_LEFT
          : ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT
      } else if (memoX > 0.8) {
        newOrientation = isAndroid
          ? ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT
          : ScreenOrientation.OrientationLock.LANDSCAPE_LEFT
      }

      await ScreenOrientation.lockAsync(newOrientation)
    }

    handleAccelerometerData()
  }, [isAndroid, memoX, memoY])
}

@ycldz
Copy link

ycldz commented Jun 14, 2023

I see. Could be viable workaround to remove "orientation": "portrait" from app.json and then do ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP) immediately after app start (e.g. in an effect in App.tsx). I will test this and share my findings.

Thank you

@kesha-antonov
Copy link
Contributor

kesha-antonov commented Jul 18, 2023

For those who need a solution that works for both iOS and Android. Here is mine:

useAccelerometer.ts

import { useEffect, useState } from "react"
import { Accelerometer } from "expo-sensors"

const useAccelerometer = () => {
  const [{ x, y }, setData] = useState({
    x: 0,
    y: 0,
  })

  useEffect(() => {
    const subscription = Accelerometer.addListener(setData)

    Accelerometer.setUpdateInterval(1000)

    return () => {
      subscription?.remove()
    }
  }, [])

  return { screenX: x, screenY: y }
}

export default useAccelerometer

useSetOrientation.ts

export const useSetOrientation = () => {
  const { screenX, screenY } = useAccelerometer()
  const memoX = useMemo(() => screenX, [screenX])
  const memoY = useMemo(() => screenY, [screenY])
  const platformOS = Platform.OS
  const isAndroid = platformOS === "android"

  useEffect(() => {
    async function handleAccelerometerData() {
      let newOrientation = ScreenOrientation.OrientationLock.PORTRAIT_UP

      if (memoY < -0.8) {
        newOrientation = ScreenOrientation.OrientationLock.PORTRAIT_UP
      } else if (memoX < -0.8) {
        newOrientation = isAndroid
          ? ScreenOrientation.OrientationLock.LANDSCAPE_LEFT
          : ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT
      } else if (memoX > 0.8) {
        newOrientation = isAndroid
          ? ScreenOrientation.OrientationLock.LANDSCAPE_RIGHT
          : ScreenOrientation.OrientationLock.LANDSCAPE_LEFT
      }

      await ScreenOrientation.lockAsync(newOrientation)
    }

    handleAccelerometerData()
  }, [isAndroid, memoX, memoY])
}

How do you use this to lock orientation? I don't get it

I need to lock orientation to portrait mode and forget it until I need to unlock all four on some screen, and then lock it to portrait again

@mvanroon
Copy link

mvanroon commented Jul 18, 2023

This has been fixed in Expo SDK 49. Unfortunately it still does not work in Expo Go, only in custom development apps. This is because the orientation has to be configured in the native code and not in the JS layer.

Blog
https://blog.expo.dev/expo-sdk-49-c6d398cdf740#:~:text=expo%2Dscreen%2Dorientation%20was%20largely%20rebuilt%20to%20address%20a%20number%20of%20long%2Dstanding%20issues

Changelog
https://github.com/expo/expo/blob/main/CHANGELOG.md#:~:text=%40behenate)-,expo%2Dscreen%2Dorientation,-Fixed%20Android%20build

@kesha-antonov
Copy link
Contributor

This has been fixed in Expo SDK 49. Unfortunately it still does not work in Expo Go, only in custom development apps. This is because the orientation has to be configured in the native code and not in the JS layer.

I'm trying to use expo orientation in bare workflow on real iphone. It doesn't work for now

@mvanroon
Copy link

mvanroon commented Jul 18, 2023

This has been fixed in Expo SDK 49. Unfortunately it still does not work in Expo Go, only in custom development apps. This is because the orientation has to be configured in the native code and not in the JS layer.

I'm trying to use expo orientation in bare workflow on real iphone. It doesn't work for now

What I would advise you to do:

  1. Create a new Expo 49 project and install and configure expo-screen-orientation. Make sure you configure the plugin as per the documentation.
  2. Add JS to lock/unlock your orientation
  3. Create a new development build (eas build --platform ios) and install it on your iPhone
  4. Verify that locking or unlocking of the orientation is working

If it's working now then the problem is in your native code. Run npx expo prebuild and compare this fresh project with your own. If it's still not working, then the problem is likely in your JS code.

@kesha-antonov
Copy link
Contributor

kesha-antonov commented Jul 18, 2023

@mvanroon thanks, I'll try that

Just in case, https://github.com/yamill/react-native-orientation worked as expected for last 2 years almost without issues. Today I saw issue in Crashlytics on android 8 and decided to give expo-orientation another try (I tried to migrate 2 months ago and stumped into this issue that lib didn't work as expected)

    Orientation.lockPlatformAsync({
      screenOrientationArrayIOS: [Orientation.Orientation.PORTRAIT_UP]
    })
    Orientation.lockAsync(Orientation.OrientationLock.PORTRAIT_UP)

This code doesn't help
Orientation still unlocked

UPD.
I switched to https://github.com/wonday/react-native-orientation-locker since couldn't get expo-orientation working

@thatgriffith
Copy link

I manage to get it working by on SDK 48 with expo-screen-orientation v5.1.1.

  1. Install package
  2. Add the following under ios in app.json:
"requireFullScreen": true,
"infoPlist": {
  "EXDefaultScreenOrientationMask": "UIInterfaceOrientationMaskAll"
}
  1. Create new EAS dev build
  2. Lock the orientation in App.tsx or any desired place:
ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.LANDSCAPE);

In my case I wanted to lock the orientation to landscape on tablets and portrait on mobile devices so I ended up with the following solution in App.tsx

  useEffect(() => {
    const lockOrientation = async () => {
      try {
        const result = await getDeviceTypeAsync();
        await ScreenOrientation.lockAsync(
          result === DeviceType.TABLET
            ? ScreenOrientation.OrientationLock.LANDSCAPE
            : ScreenOrientation.OrientationLock.PORTRAIT_UP
        );
      } catch (error) {
        if (__DEV__) {
          console.log('Error locking orientation', error);
        }
      }
    };
    lockOrientation();
  }, []);

where getDeviceTypeAsync comes from expo-device package

Hopefully this will help anyone still struggling with this.

Copy link
Contributor

github-actions bot commented Jan 4, 2024

This issue is stale because it has been open for 90 days with no activity. If there is no activity in the next 7 days, the issue will be closed.

@github-actions github-actions bot added the stale label Jan 4, 2024
Copy link
Contributor

This issue was closed because it has been inactive for 7 days since being marked as stale. Please open a new issue if you believe you are encountering a related problem.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests