const { withMainActivity } = require("expo/config-plugins"); // The top-level `orientation: "portrait"` writes android:screenOrientation="portrait" // into the manifest, which locks every Android device — including tablets — to // portrait. iOS doesn't have this problem: iPads must support all orientations // because the app is multitasking-capable, so only iPhones end up portrait-only. // Mirror that split on Android: keep the manifest lock for phones and lift it at // runtime on tablets (smallest width >= 600dp, the standard tablet breakpoint), // since requestedOrientation set at runtime overrides the manifest value. // FULL_USER allows all four orientations while still respecting the user's // auto-rotate lock, matching iPad behavior. Foldables change // smallestScreenWidthDp on fold/unfold without recreating the activity // (smallestScreenSize is in the manifest's configChanges), so the policy is // re-evaluated in onConfigurationChanged: unfolding past the tablet breakpoint // unlocks rotation, and folding back restores the portrait lock. const ORIENTATION_METHODS = ` // Applied in onCreate and re-applied on fold/unfold; added by // withAndroidTabletOrientation. override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) applyTabletOrientation() } private fun applyTabletOrientation() { requestedOrientation = if (resources.configuration.smallestScreenWidthDp >= 600) { ActivityInfo.SCREEN_ORIENTATION_FULL_USER } else { ActivityInfo.SCREEN_ORIENTATION_PORTRAIT } } `; const ORIENTATION_ON_CREATE_CALL = ` applyTabletOrientation()`; function insertAfter(contents, anchor, insertion, description) { const index = contents.indexOf(anchor); if (index === -1) { throw new Error( `withAndroidTabletOrientation: could not find ${description} in MainActivity — the Expo template changed; update the plugin anchors.`, ); } const end = index + anchor.length; return contents.slice(0, end) + insertion + contents.slice(end); } module.exports = function withAndroidTabletOrientation(config) { return withMainActivity(config, (nextConfig) => { let contents = nextConfig.modResults.contents; if (nextConfig.modResults.language !== "kt") { throw new Error("withAndroidTabletOrientation: MainActivity must be Kotlin."); } if (contents.includes("SCREEN_ORIENTATION_FULL_USER")) { return nextConfig; } contents = insertAfter( contents, "import android.os.Bundle", "\nimport android.content.pm.ActivityInfo\nimport android.content.res.Configuration", "the android.os.Bundle import", ); contents = insertAfter( contents, "class MainActivity : ReactActivity() {", ORIENTATION_METHODS, "the MainActivity class declaration", ); contents = insertAfter( contents, "super.onCreate(null)", ORIENTATION_ON_CREATE_CALL, "the super.onCreate call", ); nextConfig.modResults.contents = contents; return nextConfig; }); };