Skip to content

Add WidgetKit extension target support for plugins#174

Draft
Matildevoldsen wants to merge 1 commit into
NativePHP:mainfrom
Matildevoldsen:codex/ios-widget-extension-targets
Draft

Add WidgetKit extension target support for plugins#174
Matildevoldsen wants to merge 1 commit into
NativePHP:mainfrom
Matildevoldsen:codex/ios-widget-extension-targets

Conversation

@Matildevoldsen

Copy link
Copy Markdown

Summary

  • add a validated ios.extension_targets manifest API, initially scoped to WidgetKit app extensions
  • isolate extension Swift sources from the host target and generate deterministic Xcode targets, dependencies, products, entitlements, Info.plists, and embed phases
  • share App Group entitlements with the host and widget extension while preserving existing host entitlement values
  • support automatic local signing and per-bundle manual provisioning profiles for archive/export builds
  • clean only compiler-owned sources and Xcode blocks, including safe recovery after interrupted compilation

Why

WidgetKit code runs in a separate process and must be built as its own com.apple.product-type.app-extension target. Plugins can currently copy Swift into the host app, but they cannot declare or embed that additional target. This implements the core portion requested in NativePHP discussion #669.

Manifest API

{
  "ios": {
    "min_version": "17.0",
    "entitlements": {
      "com.apple.security.application-groups": [
        "group.${APP_ID}.widgets"
      ]
    },
    "extension_targets": [
      {
        "name": "NativePHPWidgetsExtension",
        "type": "widget-extension",
        "bundle_id_suffix": "widgets",
        "sources_dir": "extension",
        "info_plist": {
          "CFBundleDisplayName": "NativePHP Widgets"
        }
      }
    ]
  }
}

deployment_target is optional and falls back to ios.min_version, then iOS 17. The compiler injects the WidgetKit extension point and owns bundle/version/package plist keys so manifests cannot create signing mismatches.

For manual distribution signing, IOS_EXTENSION_PROVISIONING_PROFILES accepts a JSON object keyed by each full extension bundle ID. Values may be readable .mobileprovision paths or strict base64. Profiles are CMS-decoded, checked against the exact application-identifier, installed by UUID, applied to the generated target, and added to ExportOptions.plist.

Safety and packaging

  • generated target directories are recorded in an ownership manifest; unrelated ios/Extensions content is preserved
  • stale extension entry points are removed from the host compiler output
  • project edits use deterministic managed blocks and are byte-idempotent, including after pod install
  • archives containing .appex bundles use xcodebuild -exportArchive so Xcode preserves nested signatures and entitlements
  • cleanup restores generated extension targets to automatic signing without touching unrelated custom targets

Verification

  • PHP 8.3 and PHP 8.4: 326 passed, 3 skipped, 4 pre-existing risky tests, 978 assertions
  • Laravel Pint: passed
  • targeted PHPStan over every changed production path: no errors
  • plutil validation: generated host/extension entitlements and extension Info.plist passed
  • pod install after target injection: target preserved and repeated compilation remained byte-identical
  • Xcode 26.6 / iOS 26.5 SDK:
    • full NativePHP-simulator workspace build passed on iPhone 17 Pro Max simulator
    • extension embedded at PlugIns/NativePHPWidgetsExtension.appex
    • PluginKit registered com.matildeene.laraloom.widgets
    • widget appeared in the gallery and rendered on the simulator Home Screen
    • unsigned Release iphoneos extension build produced an arm64 Mach-O

The manual profile installation/export boundary is integration-tested with decoded profile fixtures. A live App Store export was not attempted because that requires matching production host and extension profiles.

Scope

This draft intentionally covers iOS WidgetKit target support only. The Android receiver metadata and resource-copy primitives described by the original widget proposal are already present in current core. Once the manifest shape is agreed, I can follow with the separate documentation PR requested by the contribution guide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant