native_device_orientation

2.1.3

A Flutter plugin for reading device's native orientation, either from UI orientation or from sensors

Download archive

Readme

Native Device Orientation

pub package

This is a plugin project that allows for getting the native device orientation.

NOTE for Swift Package Manager

After switching to Swift Package Manager, if you're going to run the example you have to make sure that the folder name of the entire repository is "native_device_orientation" rather than the default of flutter_native_device_orientation from when you do a clone. This is because in their infinite wisdom, Apple made the directory name the root source of naming rather than the Package.swift or something else.

Why?

Flutter provides a couple of way to get the 'orientation', but they all amount to basically checking whether the screen is taller or wider. This could fail for a strangely shaped device, but that isn't the primary issue.

The primary issue is that this method doesn't differentiate between landscape left and landscape right (what you get from rotation an upright phone left or right).

This isn't an issue for most applications, but when I was writing a plugin which displays a camera image, it became a problem as I need to know which way the screen is rotated.

Updating to 2.*

Due to the objective c code being removed from the project, updating to 2.0 can sometimes result in a build error, something like the following:

Definition of 'NativeDeviceOrientationPlugin' must be imported from module 'nativeDeviceOrientation.Swift' before it is required

Unfortunately, this is a build-system issue and as such cannot be fixed easily by the developer. To resolve the issue, you can simply follow these steps:

  • Update to flutter_native_device_orientation version 2.*
  • remove your Podfile.lock
  • run flutter clean
  • run flutter build ios or run for an iOS device

UseSensor

When using either the build-in widget or the plugin directly, there is an option you can pass in which is called useSensor. When it is true, the device's sensors are used directly rather than simply using the window/page orientation. By default it is false, which means the plugin doesn't to much more than simply tell you whether the window is oriented landscapeLeft or landscapeRight.

This has been tested less thoroughly than other parts of the plugin so your mileage may vary and if you run into any issues please open an issue!

Using the plugin - built-in "reader" widget

There are three ways of using the plugin. The simplest entails encapsulating your code in a NativeDeviceOrientationReader widget, and then using NativeDeviceOrientationReader.orientation(context); in a widget encapsulated within the context.

This allows you to control when the device starts listening for orientation changes (which could use a bit of energy) by deciding where the NativeDeviceOrientationReader is instantiated, while being able to access the orientation in a simple way.

Note that there could be a very slight time between when the NativeDeviceOrientationReader widget is instantiated and when the orientation is read where the widget could be built with an incorrect orientation; it uses flutter's method of size until the first message it receives back from the native code (which should be fairly immediate anyways). It assumes that landscape is right and portrait is upright during this time.

See the source code for more details.

Using the plugin - built-in "oriented" widget

The second approach is more involved, but involves slightly less boilerplate, and may be a bit more obvious to use. It wraps the NativeDeviceOrientationReader widget, then automatically checks the orientation for you. Instead of passing in a single builder function, you pass one for each orientation you wish to define: landscapeLeft, landscapeRight, portraitUp, and portaitDown are the most obvious, followed by simply landscape and portrait for situations where you don't care to define different layouts for either of those, and finally the (required) fallback, used in cases where either you don't have a more specific builder defined, or something goes horribly horribly wrong.

You sacrifice a bit of control over when to actually retrieve the orientation info in exchange for the plugin handling orientation updates automatically. Since this approach does a bit more hand holding, processing things like NativeDeviceOrientation.unknown for you, it's the approach in the example app.

See example and source code for more details.

Using the plugin - directly

It is also possible to bypass the helper widget to access the native calls directly. This is done by using the NativeDeviceOrientationCommunicator class. It is a singleton but can be instantiated like a normal class, and handles the communication between the ios/android code and the flutter code.

This class has two interesting methods:

  1. Future<NativeDeviceOrientation> orientation(useSensor: false): This can be called to get the orientation asynchronously.

  2. Stream<NativeDeviceOrientation> onOrientationChanged(useSensor: false): This can be called to get a stream which receives new events whenever the orientation changes. It should also get an initial value pretty much immediately.

Changelog

[2.1.3] - Sept 6, 2026

  • Ignore null sensor orientation event in android callback

[2.1.2] - Sept 6, 2026

  • Bump SPM iOS version to 13 to fix xcode build with most recent flutter versions
  • Also bumped cocoapods version (not sure completely necessary but I'd rather be consistent)

[2.1.1] - May 30, 2026

  • Updates for most recent SPM changes

[2.1.0] - Dec 7, 2025

  • Add support for Swift Package Manager

[2.0.5] - Nov 26, 2025

  • Fix: leaked intent receiver (thanks @Soap-141)

[2.0.4] - Oct 13, 2025

  • Update android & gradle dependencies

[2.0.3] - Feb 2, 2024

  • Fix crash on iOS resulting from returning void value

[2.0.2] - Jan 26, 2024

  • Fixed bug causing orientation widget to continually re-request the orientation stream every time the widget rebuilt.
  • Lowered android compile target to 33 as 34 isn't needed and caused warning

[2.0.1] - Jan 26, 2024

  • Add information in README about updating to 2.*.

[2.0.0] - Jan 26, 2024

  • Major refactoring of code, rebuilt project files from scratch. Should not change interface or what is exposed, but bumping major version anyways just in case.
  • Stops deprecation & unsafe cast checks
  • Exposes DeviceOrientation through NativeDeviceOrientation

[1.2.1] - Oct 16, 2023

  • Remove AppLifecycleState.hidden and use switch default instead

[1.2.0] - Oct 11, 2023

  • Add compatibility with AGP 8 (Android Gradle Plugin).
  • Stop using fastest sensor listener by default as requires additional permission

[1.1.4] - June 6, 2022

  • Fix bug stopping android from compiling

[1.1.3] - June 5, 2202

  • Fix sensos getOrientation on android (for real this time)
  • Make iOS keep last orientation if device is flat

[1.1.2] - May 17, 2022

  • Fix direct sensor getOrientation on android
  • Listen to status bar change on iOS rather than device change (fix for older devices)

[1.1.1] - May 17, 2022

  • Rename unknownSubstitute to defaultOrientation.

[1.1.0] - May 17, 2022

  • Support Flutter 3.0 (should still support 2.x as well)
  • Adds additional, more explicit way to use plugin
  • Allows setting default if "unknown" is returned from native side, previously always defaulted to PortraitUp.

[1.0.0] - March 9, 2021

  • Support null-safety.

[0.4.3] - July 20, 2020

  • Re-add v1 embedding.

[0.4.2] - July 19, 2020

  • Fix package definition & remove iOS i386 block

[0.4.1] - July 17, 2020

  • Fix various pub-specific issues

[0.4.0] - July 17, 2020

  • Fix an issue where the most recent orientation is not always retrieved.
  • Update to use new android embedding.
  • Use pendantic style for dart code

[0.3.0] - November 6th, 2019

  • Breaking change to support the fact that AppLifecycleState.suspended has changed to AppLifecycleState.detached.

[0.2.0] - April 24, 2019

  • Slightly breaking change - on iOS, the sensor was used regardless of what was passed to useSensor due to a bug. This meant that even with UI rotation disabled, rotation events occured.
  • Also switched back to using StatusBarOrientation. It isn't actually deprecated, just not advised for normal iOS usage. However, it does what I want and is consistent with Android - it returns the orientation of the actual window. If you really want to know the orientation of the device, use useSensor
  • Add buttons to explicitly get rotation using sensor or not (UI)

[0.1.2] - March 4, 2019

  • Reduce amount of orientation changes by keeping track of last change.

[0.1.1] - March 4, 2019

  • Fix documentation and re-order changelog.

[0.1.0] - March 4, 2019

  • Integrate PRs updating to AndroidX and implementing useSensor
  • Also made a few changes to do with UseSensor so be careful of that if you're using the NativeDeviceOrientationCommunicator directly; users who simply use the widget shouldn't notice anything.

[0.0.4] - January 2, 2019

  • Switch to using UIDeviceOrientation on iOS

[0.0.2] - June 4, 2018

  • Fix name of package

[0.0.1] - June 4, 2018

  • Implement Android & iOS native code.
  • Implement Flutter code & widget.
  • Write simple example.

Installing

export PUB_HOSTED_URL=https://pub.mirror.p-hatan.com
flutter pub add native_device_orientation
pubspec.yaml
name: native_device_orientation
description: A Flutter plugin for reading device's native orientation, either from UI orientation or from sensors
version: 2.1.3
homepage: https://github.com/rmtmckenzie/flutter_native_device_orientation

environment:
  sdk: ">=3.1.1 <4.0.0"
  flutter: ">=3.41.0"

dependencies:
  flutter:
    sdk: flutter
  plugin_platform_interface: ^2.0.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ">=3.0.0 <7.0.0"

flutter:
  plugin:
    platforms:
      android:
        package: com.github.rmtmckenzie.native_device_orientation
        pluginClass: NativeDeviceOrientationPlugin
      ios:
        pluginClass: NativeDeviceOrientationPlugin

Version history

VersionPublishedArchiveSHA-256
0.0.1On demandDownloade10041a8…4f9af3
0.0.2On demandDownloadffbc7f93…7ee373
0.0.3On demandDownload50ffa46a…79b43a
0.0.4On demandDownload4a7959c2…09eeab
0.1.0On demandDownload0da33249…d9673b
0.1.1On demandDownloada6d9047b…28d6c7
0.1.2On demandDownload8ea9876f…e3283e
0.2.0On demandDownloadaeb22ea4…55a779
0.3.0On demandDownload0fad5178…fa6018
0.4.0On demandDownloadebf0e268…5b08b8
0.4.1On demandDownload80a8707a…88cc73
0.4.2On demandDownload019418fb…ce3a9c
0.4.3On demandDownload4a17190b…b17495
1.0.0On demandDownloadea0b70eb…bf164c
1.1.0On demandDownload1d0031ed…b7886e
1.1.1On demandDownload06fd7351…8967dc
1.1.2On demandDownloadf4a810d2…ca3778
1.1.3On demandDownload23707816…06e1ee
1.1.4On demandDownload7d2fa1a1…356ccc
1.2.0On demandDownloadc0b52f6b…fbd5d5
1.2.1On demandDownload744a0303…af9937
2.0.0On demandDownloadc57edcb5…4b6e20
2.0.1On demandDownload8cedcc5c…81a0c1
2.0.2On demandDownload3834eb93…e09d59
2.0.3On demandDownload0c330c06…3b338c
2.0.4On demandDownloadbc0bcccc…c85e6c
2.0.5On demandDownload39249012…2d2cc7
2.1.0On demandDownload711aabfd…1b041d
2.1.1On demandDownload4751bd86…42f0a4
2.1.2On demandDownload79ca5d63…96dc76
2.1.3Cached · Upstream SHA-256 matchedDownloadddb8addd…d6ccd7

Dependencies

flutter { "sdk": "flutter" }

plugin_platform_interface "^2.0.2"