-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Comments
also using EAS and experiencing this behavior. i can call
however, the screen will not rotate when tilting the phone -- made sure portrait lock was turned off on the phone too. calling app.json does have edit: also did set |
a quick update, setting the expo.ios.infoPlist option in app.json to support landscape like so:
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. |
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? |
Experiencing the same issue. Used to work before transitioning to eas build, but now calling |
@silberistgold if you remove orientation option in app.json, it will work again... but its no good solution |
I see. Could be viable workaround to remove |
The issue I'm experiencing is that while removing |
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. |
I can confirm that the workaround mentioned above is working for me. App correctly stays locked in |
@silberistgold can you provide a code example? you use https://docs.expo.dev/versions/latest/sdk/devicemotion/ ? |
@fwidtmann I think @silberistgold was referring to their workaround which I can also confirm works, removing the |
@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? |
@watchinharrison exactly. I removed |
@silberistgold ah ok, thank you |
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. |
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. |
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? |
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. |
@ErikTromp, you can try my attempt at the plugin here: https://github.com/LyraHealth/react-native-orientation-plugin |
@brycnguyen thanks, that helps! |
I tried adding this and got an error when running eas:
|
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 |
Same issue here in 44. |
facing the same issue in 44 |
Same issue here in 44... |
Still got this too 👍 |
I have the same issue. |
Same here. |
Also encountering this issue with our latest build. |
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. |
There are repro steps with a snack for this issue in this other issue I filed: #21044 |
Same here. It seems to be not working properly since v44. #19690 |
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. |
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.
You can add ActivityIndicator while the timer is working. |
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 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() {
// ...
}
} |
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. |
About the @PiotrSzlagura implementation of accelerometers, I made a customHook for it and worked for me. useAccelerometer.tsimport { 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]); |
@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). |
@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 |
For those who need a solution that works for both iOS and Android. Here is mine: useAccelerometer.ts
useSetOrientation.ts
|
Thank you |
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 |
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:
If it's working now then the problem is in your native code. Run |
@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)
This code doesn't help UPD. |
I manage to get it working by on SDK 48 with expo-screen-orientation v5.1.1.
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
where Hopefully this will help anyone still struggling with this. |
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. |
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. |
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/
orandroid/
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
The text was updated successfully, but these errors were encountered: