◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Expo SDK 58 is out of beta as of 10/15 (beta since 09/15). Check your dependencies before upgrading●SDK 58 ISSUE — Early reports include Android widgets not refreshing on a schedule and Stripe linking statically●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Expo SDK 58 is out of beta as of 10/15 (beta since 09/15). Check your dependencies before upgrading●SDK 58 ISSUE — Early reports include Android widgets not refreshing on a schedule and Stripe linking statically●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/App Dev
◇ App Dev/2026-10-21Intermediate

expo-widgets Works on iOS but Fails Only in the Android Build — Pin the Version or Exclude It?

Reports say expo-widgets 58.0.17 and later stops at Kotlin compilation on Android only. How to recognize it, when to pin versus exclude from autolinking, and a script that checks your project.

expo-widgetsExpo SDK 583Android58Gradle3Troubleshooting48

The widget shows up fine in the iOS simulator, but the moment you run npx expo run:android, a wall of Kotlin errors appears. You only bumped a dependency, and yesterday's build is suddenly stopped.

This is a walkthrough of the expo-widgets Android problem currently reported on GitHub, written as a way to narrow things down. I have not reproduced the failure myself. What follows rests on the issue text and on a script I did run against mock projects.

The symptom: which errors point here

The report is expo/expo issue #51653, opened on October 16, 2026 and still open when I read it on October 20.

  • It affects expo-widgets 58.0.17 and later (the reporter also saw it on 58.0.18). 58.0.16 is reported as unaffected
  • It happens only in native Android builds; iOS is unaffected
  • Kotlin compilation prints lines such as Unresolved reference 'jakex7', Unresolved reference 'PeekNotificationViews' and Unresolved reference 'setPeekContent', coming from CustomNotificationBuilder.kt and CustomNotificationRenderer.kt

According to the reporter, the cause is a naming mismatch between dependencies. The new notification code imports io.github.jakex7.peek, while build.gradle actually pulls in io.github.expo.peek (0.3.2). The jakex7 artifacts stop at 0.3.0 on Maven Central and are not declared as a dependency.

So nothing in your own app code will explain it. A specific package version is broken on Android only. If your error contains those names, treat this as the first suspect.

Two ways out: pin the version, or leave Android out

The issue itself names the autolinking exclusion as the workaround. Pinning is an inference from the report that 58.0.16 lacks the broken imports, not something the issue recommends.

SituationWhat to doWhat happens
You want widgets on Android tooPin to 58.0.16You return to the version reported as unaffected. The newer notification features wait until you move up again
Widgets only need to exist on iOSExclude from Android autolinkingexpo-widgets stays out of the Android build, and you can keep the latest version
You have not adopted it yetHold offAdding it after the issue is resolved costs you nothing

I would first decide whether Android really needs the widget. When a widget is an extra on the iOS side, as it is in my wallpaper apps, exclusion leaves less to clean up later.

If you pin the version

With ^ or ~ still in place, the next npm install can move you back to 58.0.17 or later. Remove the range and use an exact version.

npm install expo-widgets@58.0.16 --save-exact

Then confirm that package.json shows "58.0.16" without a prefix, and run the compile task from the issue's reproduction steps to see whether Android passes.

npx expo prebuild -p android
cd android && ./gradlew :expo-widgets:compileDebugKotlin

If you exclude it from Android

When widgets are iOS-only, add the following to package.json. This is the workaround the reporter shows in the issue.

{
  "expo": {
    "autolinking": {
      "android": {
        "exclude": ["expo-widgets"]
      }
    }
  }
}

After adding it, regenerate the Android folder.

npx expo prebuild -p android --clean

--clean deletes the existing android folder before regenerating it, so take a backup first if you have edited native files by hand. If any Android code path calls expo-widgets functions, guard them with Platform.OS. I have not checked how a project behaves after exclusion, so please verify that part in your own project.

Check whether your project is affected

Comparing package.json with node_modules every time is tedious, so here is a small script that only judges. It needs just Node and makes no network calls.

// check-expo-widgets-android.mjs
// Usage: node check-expo-widgets-android.mjs [project path]
import { readFileSync, existsSync } from "node:fs";
import { join, resolve } from "node:path";
 
const root = resolve(process.argv[2] ?? ".");
const readJson = (p) => JSON.parse(readFileSync(p, "utf8"));
 
const pkgPath = join(root, "package.json");
if (!existsSync(pkgPath)) {
  console.error(`package.json not found: ${pkgPath}`);
  process.exit(2);
}
const pkg = readJson(pkgPath);
const declared = { ...pkg.dependencies, ...pkg.devDependencies }["expo-widgets"];
if (!declared) {
  console.log("expo-widgets is not a dependency. This issue does not apply.");
  process.exit(0);
}
 
const installedPath = join(root, "node_modules", "expo-widgets", "package.json");
if (!existsSync(installedPath)) {
  console.error("expo-widgets is missing from node_modules. Run npm install first.");
  process.exit(2);
}
const installed = readJson(installedPath).version;
const [major, minor, patch] = installed.split(/[.-]/).map(Number);
 
const excluded = (pkg.expo?.autolinking?.android?.exclude ?? []).includes("expo-widgets");
const pinned = /^\d+\.\d+\.\d+$/.test(declared); // no ^ or ~ means pinned
const brokenRange = major === 58 && minor === 0 && patch >= 17;
 
console.log(`Declared: ${declared} (${pinned ? "pinned" : "range"})`);
console.log(`Installed: ${installed}`);
console.log(`Excluded from Android autolinking: ${excluded ? "yes" : "no"}`);
 
if (excluded) {
  console.log("Verdict: OK (expo-widgets is kept out of the Android build)");
} else if (!brokenRange) {
  console.log(
    pinned
      ? "Verdict: OK (not in the reported 58.0.17+ range, and the version is pinned)"
      : "Verdict: WARN (safe version now, but the range may move to 58.0.17+ on the next install)"
  );
  process.exit(pinned ? 0 : 1);
} else {
  console.log("Verdict: ACTION NEEDED (58.0.17+; Kotlin compile errors are reported on Android)");
  process.exit(1);
}

The exit code is 0 for fine, 1 for action or a warning, and 2 when prerequisites are missing. Placed as the first CI step, it can stop an automated dependency bump to 58.0.17 or later before Gradle even starts. Noticing in a few seconds beats failing after several minutes of build.

I built four mock projects (58.0.18, 58.0.16, a range specifier, and one with the exclusion) and confirmed that each returned the expected verdict.

A second report from the same period: no time-based updates on Android

Another issue (#51633) says that on Android, updateTimeline() in expo-widgets does nothing, and the generated XML hardcodes updatePeriodMillis to 0. In the reporter's summary, the display changes only when the running app calls updateSnapshot(). It was also open when I looked, with no maintainer reply.

The practical reading: for now, avoid designing a time-driven widget on Android, such as one that swaps the wallpaper at midnight, around expo-widgets. Both issues may change, so look at their latest state before you act.

For how updates work on the iOS side, see Designing WidgetKit Timelines Around the Refresh Budget: Why My Wallpaper Widgets Stopped.

What to do today

  1. Run node check-expo-widgets-android.mjs to see where you stand
  2. Pin to 58.0.16 if Android needs the widget; otherwise exclude it from autolinking
  3. Before upgrading dependencies, also run through Before Moving to Expo SDK 58, List What Disappears in Your Own Code

If your Android failure looks cache-related instead, When Only EAS Build Fails with "No matching variant", Check Your Local android/build First may fit better.

Decide first whether your app or one specific dependency version is breaking the build. That alone saves a lot of wandering.

Sources: expo/expo issues #51653 and #51633 (both read on October 20, 2026).

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 $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

◇ App Dev2026-10-15
When Only EAS Build Fails with "No matching variant", Check Your Local android/build First
Gradle passes on your machine, but the Android build on EAS stops at "No matching variant of project". Reading the reports on GitHub, I traced how a Windows-generated autolinking cache can reach the Linux builder, and wrote a small script that checks for it before you queue a build.
⬡ Dev Tools2026-10-21
A Widget That Updates on Time in iOS Stays on "Initial" in Android
In expo-widgets, updateTimeline does nothing on Android and the generated XML hardcodes updatePeriodMillis to 0. How to recognize it, what updateSnapshot can cover, and a script to check your project.
◇ App Dev2026-10-18
It Ran Fine in Debug, but the Release Build Died on Launch with a Resource Not Found. A File I Looked Up by Name Had Been Shrunk Away
A release-only crash at launch, caused by images and sounds looked up by a name string being removed by resource shrinking. A keep.xml written at prebuild, plus a post-build check that confirms it worked.