DeviceActivity Report Extension cannot pass App Store Connect validation without becoming un-installable on device

I'm running into a contradictory requirement involving the DeviceActivity Report extension (com.apple.deviceactivityui.report-extension) that makes it impossible to both:

upload the app to App Store Connect, and

install the app on a physical device.

This creates a complete catch-22.

📌 Overview

My extension:

Path: Runner.app/PlugIns/LoADeviceActivityReport.appex

Extension point: com.apple.deviceactivityui.report-extension

Implementation (SwiftUI):

import SwiftUI import DeviceActivity

@main struct LoADeviceActivityReport: DeviceActivityReportExtension { var body: some DeviceActivityReportScene { // ... } }

This is the standard SwiftUI @main DeviceActivityReportExtension template.

🟥 Side A — iOS runtime behavior (device installer)

If I add either of these keys to the extension's Info.plist:

NSExtensionPrincipalClass

NSExtensionMainStoryboard

then the app cannot be installed on a real iPhone/iPad.

The device installer fails with:

Error 3002 AppexBundleContainsClassOrStoryboard

NSExtensionPrincipalClass and NSExtensionMainStoryboard are not allowed for extension point com.apple.deviceactivityui.report-extension.

To make the app install and run, I must remove both keys completely.

This leaves the extension Info.plist like:

<key>NSExtension</key> <dict> <key>NSExtensionPointIdentifier</key> <string>com.apple.deviceactivityui.report-extension</string> </dict>

With this, the app installs and runs correctly.

🟥 Side B — App Store Connect upload validator

However, when I upload the IPA with the runtime-correct Info.plist, App Store Connect rejects it:

State: STATE_ERROR.VALIDATION_ERROR (HTTP 409)

Missing Info.plist values. No values for NSExtensionMainStoryboard or NSExtensionPrincipalClass found in extension Info.plist for Runner.app/PlugIns/LoADeviceActivityReport.appex.

So ASC requires that at least one of those keys be present.

💥 The catch-22 If I add PrincipalClass / MainStoryboard:

✔ App Store Connect validation passes

❌ But the app can NOT be installed on any device (Error 3002)

If I remove PrincipalClass / MainStoryboard:

✔ The app installs and runs correctly

❌ ASC rejects the upload with “Missing Info.plist values”

There is currently NO Info.plist configuration that satisfies both:

Runtime:

"NSExtensionPrincipalClass and NSExtensionMainStoryboard are not allowed."

App Store Connect:

"You must include NSExtensionPrincipalClass or NSExtensionMainStoryboard."

📌 Expected behavior

For SwiftUI @main DeviceActivityReportExtension, the documentation and examples suggest the correct configuration is:

<key>NSExtensionPointIdentifier</key> <string>com.apple.deviceactivityui.report-extension</string>

with no principal class or storyboard at all.

If that is correct for runtime, ASC seems to need updated validation rules for this extension type.

❓My Questions

What is the officially correct Info.plist configuration for a SwiftUI DeviceActivityReportExtension?

Should principal class / storyboard not be required for this extension type?

Is this a known issue with App Store Connect validation?

Is there currently a workaround that allows:

installation on device and

successful App Store Connect upload, without violating runtime restrictions?

Running into the same thing - following.

Have the exact same issue - please help with a solution

@yosuke65 @cbcb After extensive debugging, I found a configuration that passes both App Store Connect validation AND works on device.

The Problem:

  • Embedding in PlugIns folder (dstSubfolderSpec = 13) → ASC rejects with "Missing NSExtensionPrincipalClass"
  • Adding NSExtensionPrincipalClass → Device install fails with "not allowed for this extension point"

The Solution:

Use ExtensionKit extension type embedded in the Extensions folder (not PlugIns), with explicit dstPath:

project.pbxproj - Embed Phase: /* Embed ExtensionKit Extensions / = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "$(EXTENSIONS_FOLDER_PATH)"; dstSubfolderSpec = 16; files = ( / YourReportExtension.appex in Embed ExtensionKit Extensions */, ); name = "Embed ExtensionKit Extensions"; runOnlyForDeploymentPostprocessing = 0; };

Key settings:

  • dstSubfolderSpec = 16 (Extensions folder, NOT 13/PlugIns)
  • dstPath = "$(EXTENSIONS_FOLDER_PATH)" ← Critical!
  • productType = "com.apple.product-type.extensionkit-extension"
  • explicitFileType = "wrapper.extensionkit-extension"

Info.plist (EXAppExtensionAttributes only, no NSExtension): <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>EXAppExtensionAttributes</key> <dict> <key>EXExtensionPointIdentifier</key> <string>com.apple.deviceactivityui.report-extension</string> </dict> </dict> </plist>

The missing piece for me was the explicit dstPath = "$(EXTENSIONS_FOLDER_PATH)" - without it, the extension wouldn't render properly even when in the Extensions folder.

Hope this helps others hitting this wall!

DeviceActivity Report Extension cannot pass App Store Connect validation without becoming un-installable on device
 
 
Q