RORK LABJP
DEADLINE — Five days remain before Google Play requires Android 16 (API level 36). From August 31 it applies to new apps and updates alikeEXTENSION — If you qualify, you can request an extension through November 1 via a Play Console form, but the request itself has to be filed before the deadlineEXPO — Expo SDK 57 reached 57.0.9 with React Native 0.86.2. SDK 57 is primarily the jump from React Native 0.85 to 0.86HERMES — The Hermes V1 memory regression introduced in SDK 56 has been fixed, which matters most for apps pulling in react-native-worklets or react-native-reanimatedIOS — The seventh iOS 27 developer beta shipped on August 24. The public release lands in September and finally lets you reply to an individual message from an Android senderRORK — Rork Max generates native Swift and compiles on a cloud Mac fleet, targeting iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessageDEADLINE — Five days remain before Google Play requires Android 16 (API level 36). From August 31 it applies to new apps and updates alikeEXTENSION — If you qualify, you can request an extension through November 1 via a Play Console form, but the request itself has to be filed before the deadlineEXPO — Expo SDK 57 reached 57.0.9 with React Native 0.86.2. SDK 57 is primarily the jump from React Native 0.85 to 0.86HERMES — The Hermes V1 memory regression introduced in SDK 56 has been fixed, which matters most for apps pulling in react-native-worklets or react-native-reanimatedIOS — The seventh iOS 27 developer beta shipped on August 24. The public release lands in September and finally lets you reply to an individual message from an Android senderRORK — Rork Max generates native Swift and compiles on a cloud Mac fleet, targeting iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessage
Articles/App Dev
App Dev/2026-08-26Intermediate

What Android 16 ignores on tablets, and why app.json gives you no way out

Targeting API level 36 means screenOrientation is ignored on displays at least 600dp wide. Here is how to check your project without a tablet, why app.json cannot express a fix, and what the opt-out property actually restores.

Android 162Expo185config plugin6AndroidManifestGoogle Play30

Premium Article

I opened a tablet emulator only after noticing that August 31 was five days out.

The wallpaper apps I run as an indie developer are all built around a portrait grid. Bumping targetSdkVersion to 36 for the Play deadline was already done. What was left was checking what changes once you are actually on 36.

I rotated the emulator, and the grid I had locked to portrait spread sideways. I had not touched the manifest.

Eight values stop being honored

For apps targeting Android 16 (API level 36), orientation, aspect ratio, and resizability restrictions are ignored on displays whose smallest width is at least 600dp. That covers tablets, the inner displays of large-screen foldables, and desktop windowing.

Here is what gets ignored:

Attribute or APIIgnored values
screenOrientationportrait / landscape / reversePortrait / reverseLandscape / sensorPortrait / sensorLandscape / userPortrait / userLandscape
resizeableActivityall
minAspectRatioall
maxAspectRatioall
setRequestedOrientation()same eight values

The part I missed on first read was what the table leaves out. unspecified, locked, nosensor, sensor, user, and fullSensor are not on the ignore list.

There are exceptions. Displays smaller than sw600dp — most phones, and the outer displays of foldables — are unaffected. Apps flagged as games through android:appCategory are excluded. So are cases where the user has explicitly opted into your app's default behavior through the device's aspect ratio settings.

Which means "I checked on my phone" proves nothing here. That is exactly why I did not notice until I opened an emulator.

Predictive back is a separate Android 16 default change with a different opt-out mechanism. I covered that one in the predictive back decision for Android 16. Treating both as one task tends to leave both half-done.

Check your project before you touch a device

Before borrowing a tablet, read your own configuration. In a Rork or Expo project, the orientation value lives in two places: app.json, and the AndroidManifest.xml produced by prebuild.

Those two can disagree. If you edit the manifest by hand after prebuild, app.json no longer tells you the truth. If you regenerate native directories every time, app.json is authoritative.

I wrote a small script that reads both and reports the value that actually applies.

// check-orientation.mjs — run with: node check-orientation.mjs
import { readFileSync, existsSync } from 'node:fs';
 
// screenOrientation values Android 16 (API 36) ignores at sw600dp and above
const IGNORED = new Set([
  'portrait', 'landscape',
  'reversePortrait', 'reverseLandscape',
  'sensorPortrait', 'sensorLandscape',
  'userPortrait', 'userLandscape',
]);
 
function fromAppJson(path) {
  if (!existsSync(path)) return null;
  const json = JSON.parse(readFileSync(path, 'utf8'));
  const cfg = json.expo ?? json;
  // app.json only accepts 'default' | 'portrait' | 'landscape'
  // 'default' becomes android:screenOrientation="unspecified"
  const o = cfg.orientation;
  if (!o) return null;
  return o === 'default' ? 'unspecified' : o;
}
 
function fromManifest(path) {
  if (!existsSync(path)) return null;
  const xml = readFileSync(path, 'utf8');
  // if you hand-edit after prebuild, this is the real value
  const m = xml.match(/android:screenOrientation="([^"]+)"/);
  return m ? m[1] : null;
}
 
const manifestPath = 'android/app/src/main/AndroidManifest.xml';
const manifestValue = fromManifest(manifestPath);
const appJsonValue = fromAppJson('app.json') ?? fromAppJson('app.config.json');
const effective = manifestValue ?? appJsonValue ?? 'unspecified (not set)';
const source = manifestValue ? manifestPath : (appJsonValue ? 'app.json' : 'not set anywhere');
 
console.log(`screenOrientation = ${effective}  (source: ${source})`);
 
if (manifestValue && appJsonValue && manifestValue !== appJsonValue) {
  console.log(`Warning: app.json says ${appJsonValue}, manifest says ${manifestValue}`);
}
 
if (IGNORED.has(effective)) {
  console.log('Affected: this value is ignored on displays at or above sw600dp');
  process.exitCode = 1;
} else {
  console.log('Not on the ignore list');
}

With only "orientation": "portrait" in app.json, you get:

screenOrientation = portrait  (source: app.json)
Affected: this value is ignored on displays at or above sw600dp

On a prebuilt project where the manifest has been rewritten to unspecified:

screenOrientation = unspecified  (source: android/app/src/main/AndroidManifest.xml)
Warning: app.json says portrait, manifest says unspecified
Not on the ignore list

It sets an exit code, so if you maintain several apps you can loop over directories and get the affected list in one pass. That is what I did before touching any hardware.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Determine whether your project is affected by Android 16's orientation override without buying or borrowing a tablet
Know before you submit that the opt-out property does not bring your portrait lock back
Move a setting from app.json into a config plugin without confusing property with meta-data
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

Related Articles

App Dev2026-08-23
Bumping targetSdk to 36 surfaced a 16 KB warning. These are two different deadlines
The August 31 target API 36 requirement and the February 1, 2027 16 KB page size requirement are separate conditions. Here is how to inspect your AAB without installing the NDK, and why a LOAD misalignment and a zip boundary miss need completely different fixes.
App Dev2026-08-18
The three places I had to fix before a Rork project actually targeted API level 36
My app.json said targetSdkVersion 36. The value my build actually read was 35. Here is the script that reports the effective value, and how I split my apps between raising, leaving alone, and requesting an extension.
Dev Tools2026-08-23
Predictive back on Android 16: what to fix before August 31, and what can wait
Targeting API 36 turns predictive back on by default and stops onBackPressed from firing. Here is how I split the work that the deadline actually requires from the work that does not, and how I kept the opt-out from disappearing on the next prebuild.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →