When users create walks in PlanPal, they sync to Google Calendar with a deep link: https://planpal-ai.app/open/walk/255. Tapping it should open the app. Instead, Safari opened.

Issue 1: Missing AASA Path

iOS Universal Links require an Apple App Site Association file listing which URL paths open in the app. Mine was missing /open/*:

{
  "applinks": {
    "details": [{
      "appID": "6FUHTSC77Y.com.planpal.mobile",
      "paths": ["/app/*", "/subscription/success", "/subscription/cancel"]
    }]
  }
}

The /open/* paths used by Google Calendar links weren't listed. iOS had no idea these URLs should open in the app. Fix:

'paths' => ['/app/*', '/open/*', '/subscription/success', '/subscription/cancel'],

Issue 2: URL Scheme Collision

Even after fixing the AASA, the planpal:// custom URL scheme wasn't working. Expo's scheme property in app.json was being silently ignored because I had a manual CFBundleURLTypes entry for Google OAuth:

"CFBundleURLTypes": [{
  "CFBundleURLSchemes": ["com.googleusercontent.apps.xxx"]
}]

Expo's prebuild logged a warning I initially missed:

» ios: scheme: "ios.infoPlist.CFBundleURLTypes" is set in config.
  Ignoring abstract property "scheme": planpal

Fix: add planpal to the existing array instead of relying on the abstract property:

"CFBundleURLSchemes": ["planpal", "com.googleusercontent.apps.xxx"]

Then npx expo prebuild --platform ios --clean to regenerate.

Gotcha: AASA Caching

Apple's CDN caches AASA files for up to 24 hours. After updating, delete and reinstall the app to force a re-fetch -- or wait. URL scheme changes also require a full native rebuild since they're baked into the iOS binary at build time.