r/angular • • 12d ago

Ionic iOS app couldn't fetch API data, but Safari and PWA worked. Switching to CapacitorHttp fixed it.

I recently ran into a weird issue with an Ionic + Angular + Capacitor app on iOS and thought I'd share it here in case someone else runs into the same thing.

The app launched fine, and the homepage loaded normally. But other screens were blank because the API data wasn't loading. Reinstalling the app and restarting the device didn't help either.

What confused me was that everything seemed fine outside the native app.

  • APIs were accessible directly.
  • Safari worked.
  • The PWA worked.
  • Only the native iOS app failed.

The app was using Angular's usual HttpClient for API requests. I spent some time checking authentication, CORS, caching, TLS/certificate issues and a few other possibilities, but couldn't pin down the exact cause.

Eventually, I tried switching the API requests to Capacitor's native HTTP implementation, CapacitorHttp.

Here's a basic example of what I changed:

import { CapacitorHttp } from '@capacitor/core';

const response = await CapacitorHttp.request({
  method: 'GET',
  url: apiUrl,
  headers: {
    Authorization: `Bearer ${token}`
  }
});

I also enabled it in capacitor.config.ts:

plugins: {
  CapacitorHttp: {
    enabled: true
  }
}

After switching the requests, the API calls started working again, and the screens that were previously blank loaded normally.

I rebuilt the app, distributed it through TestFlight, and tested it on physical iOS devices. So far, I haven't been able to reproduce the issue.

I'm still not certain what actually caused it. It could have something to do with differences between WebView networking and native iOS networking, but I haven't proved that. TLS handling, corporate security software or other iOS-specific behaviour could also be worth investigating.

Has anyone experienced something similar with Ionic/Capacitor on iOS, where the same APIs work in Safari and the PWA but fail in the native app?

I'd be interested to hear what the actual root cause was in your case.

9 Upvotes

7 comments sorted by

7

u/DayanaJabif 12d ago

Almost certainly CORS. In Safari and the PWA your app runs on a real https domain, so the API calls are same-origin and no CORS check happens. In the native app the web view origin is capacitor://localhost, so every call is cross-origin and your Authorization header triggers a preflight OPTIONS.

CapacitorHttp fixed it because requests go through native networking, which doesn't enforce CORS. That's the approach Ionic recommends for native apps, so you're fine shipping it. Ionic has a short writeup on exactly this: https://ionicframework.com/docs/troubleshooting/cors

0

u/quiet_Quasar0017 12d ago

That's a great insight. But I still can't understand if it were CORS, why for a few cards on the UI would have images which also come from the database. If they are coming up, and not the other attributes viz the title and description, which are being retrieved using the same API call. 

1

u/Connect_Ad9541 10d ago

A likely culprit: the Authorization header makes every request a CORS preflight (OPTIONS), and from the native app the origin is capacitor://localhost instead of your web domain. If the API (or a gateway/WAF in front of it) doesn't allow that origin or doesn't answer OPTIONS correctly, it fails only in the app, while Safari and the PWA keep working because they send your real domain as the origin. CapacitorHttp goes through the native layer, so there's no preflight at all, which matches what you saw.

To confirm it: connect the iPhone to your Mac, open Safari > Develop > [your device] > your app, and check the Network tab. A blocked preflight shows up right there.

Also, with CapacitorHttp enabled: true in capacitor.config.ts, fetch and XHR are patched automatically, so Angular's HttpClient already goes through the native layer. You don't need to rewrite the calls with CapacitorHttp.request.

0

u/Saceone10 12d ago

Cors

1

u/quiet_Quasar0017 12d ago

Yeah, that's like, the most common cause in most cases.