The Info.plist keys that decide where an iOS app runs and how it may lay
out: UIDeviceFamily (iPhone 1, iPad 2), UISupportedInterfaceOrientations
(iPhone), UISupportedInterfaceOrientations~ipad, and UIRequiresFullScreen.
mob.exs overrides
Three config :mob_dev keys override the project's ios/Info.plist in the
built app bundle (the dev simulator and device builds and mix mob.release).
The project file is never rewritten, so the setting reaches new and existing
apps alike:
ios_target_devices—[:iphone, :ipad](universal) or[:iphone]. SetsUIDeviceFamily. Without iPad, an iPad runs the app letterboxed in iPhone compatibility mode, and it can't join Split View. An App Store app that has shipped iPad support can't drop it in an update.ios_orientations—:all,:portraitor:landscape. Sets the iPhoneUISupportedInterfaceOrientations(and removes anyUISupportedInterfaceOrientations~iphone). iPad always declares all four (UISupportedInterfaceOrientations~ipad): iPadOS 26 rotates resizable apps freely, and iPad multitasking requires all four.multi_window—trueorfalse(MOB-245).truesetsUIApplicationSceneManifest→UIApplicationSupportsMultipleScenes, so iPad users can open several windows of the app, each with its own navigation (Mob.Scenein mob). It needs the plist's existingUISceneConfigurations→UIWindowSceneSessionRoleApplicationentry (the generatedSceneDelegate); the build refuses a plist without one rather than add a manifest that would switch the app to a scene lifecycle with no delegate.falseremoves the key, which iOS reads asfalse. Needs a mob release withMob.Scene.
Unset keys leave ios/Info.plist as written. UIRequiresFullScreen has no
override: the only supported value is false (or no key), and
mix mob.doctor warns when a plist sets it.
See decisions/2026-10-01-ios-layout-plist-keys.md.
Summary
Functions
Applies plist_commands/1 to the Info.plist at path with PlistBuddy
(macOS). Raises when a command other than Delete fails.
The mix mob.doctor rows for an app's Info.plist text and mob.exs
config: one :ok row when the app can run full-screen on iPad, rotate and
join Split View, otherwise a :warn per problem with the exact fix.
Problems a mob.exs setting chose on purpose (ios_target_devices: [:iphone], ios_orientations: :portrait) aren't warned about.
The PlistBuddy commands that stamp the mob.exs overrides into a bundle's
Info.plist, in order. A Delete of a key the plist lacks fails harmlessly;
every other command must succeed, including the Print that checks a
multi_window: true plist has an application scene configuration. Raises
Mix.Error on an invalid setting.
Reads the layout keys from an XML Info.plist. {:error, reason} when the
text isn't an XML property list (a binary plist, say).
Validates the mob.exs overrides. Returns the resolved settings, nil for
each key that is unset.
Types
One mix mob.doctor row.
@type keys() :: %{ device_family: [integer()] | nil, orientations: [String.t()] | nil, iphone_orientations: [String.t()] | nil, ipad_orientations: [String.t()] | nil, requires_full_screen: boolean() | nil, scene_configurations?: boolean() }
The layout keys of a parsed Info.plist; nil when the key is absent.
Functions
Applies plist_commands/1 to the Info.plist at path with PlistBuddy
(macOS). Raises when a command other than Delete fails.
The mix mob.doctor rows for an app's Info.plist text and mob.exs
config: one :ok row when the app can run full-screen on iPad, rotate and
join Split View, otherwise a :warn per problem with the exact fix.
Problems a mob.exs setting chose on purpose (ios_target_devices: [:iphone], ios_orientations: :portrait) aren't warned about.
The PlistBuddy commands that stamp the mob.exs overrides into a bundle's
Info.plist, in order. A Delete of a key the plist lacks fails harmlessly;
every other command must succeed, including the Print that checks a
multi_window: true plist has an application scene configuration. Raises
Mix.Error on an invalid setting.
Reads the layout keys from an XML Info.plist. {:error, reason} when the
text isn't an XML property list (a binary plist, say).
@spec settings(keyword()) :: {:ok, %{ device_family: [integer()] | nil, orientations: [String.t()] | nil, multi_window: boolean() | nil }} | {:error, String.t()}
Validates the mob.exs overrides. Returns the resolved settings, nil for
each key that is unset.