Local Push Connectivity API - Got 'Provisioning profile failed qualification' while distributing an app to the store

I have an app which uses the Local Push Connectivity API.

I have requested and received the entitlement and everything is working in dev-mode, but once I try to distribute the app to the AppStore I got the following error:

Provisioning profile failed qualification

Profile doesn't match the entitlements file's value for the com.apple.developer.networking.networkextension entitlement.

I was wondering if I need an other entitlement for this, mine is called Local Push Provider iOS Dev which makes me feel like there should be a Store counterpart - but I did not see how to request it on the Entitlement Request Page.

Thanks for any hints!

Are you using the old (template) model or the new (capability) process?

Using the Multicast Networking Additional Capability describes what each of these processes looks like.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I am still using the old one (I didn't see a app-push-provider-capability anywhere)

So like in the example I added the Network-Extension-Capability to the targets and afterwards I manually added app-push-provider to the Entitlement.

In the details of the provisioning-profile I also can see the selected Entitlement:

I checked the development-.app-file like described in the linked article and it looks ok. (It also works properly by the way)

But once I try to validate or distribute an AppStore-Archive, i got the Provisioning profile failed qualification-Error.

I am still using the old one

That’s fine. Some managed capabilities have moved over and some haven’t.

In the details of the provisioning-profile I also can see the selected Entitlement [Local Push Provider iOS Dist]

That looks promising. If you manually generate a profile using that template and then dump the entitlement allowlist in that profile, what do you see?

See TN3125 Inside Code Signing: Provisioning Profiles for the commands to dump your profile.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

That looks promising. If you manually generate a profile using that template and then dump the entitlement allowlist in that profile, what do you see?

It looks like this:

<?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>application-identifier</key>

	<string>WZVT3WRZLQ.de.getslash.localpush.app</string>

	<key>beta-reports-active</key>

	<true/>

	<key>com.apple.developer.networking.networkextension</key>

	<array>

		<string>app-push-provider</string>

	</array>

	<key>com.apple.developer.team-identifier</key>

	<string>WZVT3WRZLQ</string>

	<key>com.apple.security.application-groups</key>

	<array>

		<string>group.de.getslash.localpush</string>

	</array>

	<key>get-task-allow</key>

	<false/>

	<key>keychain-access-groups</key>

	<array>

		<string>WZVT3WRZLQ.*</string>

		<string>com.apple.token</string>

	</array>

</dict>

</plist>

And the Profile of the Extension has also the entitlement:

<?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>application-identifier</key>
	<string>WZVT3WRZLQ.de.getslash.localpush.app.provider</string>
	<key>beta-reports-active</key>
	<true/>
	<key>com.apple.developer.networking.networkextension</key>
	<array>
		<string>app-push-provider</string>
	</array>
	<key>com.apple.developer.team-identifier</key>
	<string>WZVT3WRZLQ</string>
	<key>com.apple.security.application-groups</key>
	<array>
		<string>group.de.getslash.localpush</string>
	</array>
	<key>get-task-allow</key>
	<false/>
	<key>keychain-access-groups</key>
	<array>
		<string>WZVT3WRZLQ.*</string>
		<string>com.apple.token</string>
	</array>
</dict>
</plist>

For me it looks like a match to the entitlement

<?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>com.apple.developer.networking.networkextension</key>
	<array>
		<string>app-push-provider</string>
	</array>
	<key>com.apple.security.application-groups</key>
	<array>
		<string>group.de.getslash.localpush</string>
	</array>
</dict>
</plist>

There is no Cache for PPs or something like that, is there?

For me it looks like a match to the entitlement

Yep.

There is no Cache for PPs or something like that, is there?

Oh there absolutely is, in ~/Library/MobileDevice/Provisioning Profiles.

When you try to distribute from Xcode organiser, are you manually signing? I think that’s still required for these old process managed capabilities.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Oh there absolutely is, in ~/Library/MobileDevice/Provisioning Profiles.

I already purged it. In fact I created a complete new set of App-IDs and Profiles. But still the same result...

When you try to distribute from Xcode organiser, are you manually signing? I think that’s still required for these old process managed capabilities.

Yes, as I am just Prototyping it is very handson:

  • Auto is disabled,
  • the Profiles are selected and up to date
  • Afterwards I create an Archive via Product>Archive and try to distribute to the AppStore from the organiser...

I have had a look at IDEDistributionProvisioning.log:

2023-12-05 13:08:49 +0000  2023-12-05 13:08:49 +0000 IDEProvisioningRepair(SimplePushWL.app): 2023-12-05 13:08:49 +0000 IDEProvisioningRepair(SimplePushWL.app): Created provisioning profile: <DVTEmbeddedProvisioningProfile 0x60004f89a100: name: iOS Team Store Provisioning Profile: de.getslash.cc.babyphone.wl, UUID: 3dcaebae-aeeb-418d-a01b-e0d8f65679f8, teamName: Getslash GmbH, teamIdentifierPrefixes: (
    WZVT3WRZLQ
), entitlements: {
    "application-identifier" = "WZVT3WRZLQ.de.getslash.cc.babyphone.wl";
    "aps-environment" = production;
    "beta-reports-active" = 1;
    "com.apple.developer.networking.networkextension" =     (
        "app-proxy-provider",
        "content-filter-provider",
        "packet-tunnel-provider",
        "dns-proxy",
        "dns-settings",
        relay
    );
    "com.apple.developer.team-identifier" = WZVT3WRZLQ;
    "com.apple.security.application-groups" =     (
        "group.de.getslash.localpush"
    );
    "get-task-allow" = 0;
    "keychain-access-groups" =     (
        "WZVT3WRZLQ.*",
        "com.apple.token"
    );
}, appIdentifierName: CC Babyphone WL, applicationIdentifierPrefixes: (
    WZVT3WRZLQ
), dateCreated: 2023-12-05 13:08:49 +0000, dateExpired: 2024-08-06 14:52:14 +0000, certificateKinds: {(
    "1.2.840.113635.100.6.1.7",
    "1.2.840.113635.100.6.1.4"
)}, certificateSHA1Hashes: {(
    7C4CEDFBFB0938A37B771D2C04F093FD0156CC66,
    357D27B1D2A04CF228C792527F61B505AB28CEBC
)}, supportedUDIDs: {(
)}, isUniversal: 0, isXcodeManaged: 1, platforms: {(
    <DVTPlatform:0x600003f4ac70:'com.apple.platform.watchos':<DVTFilePath:0x60000264a920:'/Applications/Xcode.app/Contents/Developer/Platforms/WatchOS.platform'>>,
    <DVTPlatform:0x600003f41830:'com.apple.platform.iphoneos':<DVTFilePath:0x600002664770:'/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform'>>
)}, filePath: (null)>

It look like IDEProvisioningRepair is creating a new Profile during distribution which didn't have the needed app-push-provider entitlement...

Afterwards I create an Archive via Product > Archive

Your Xcode archive should use development signing and configuration profiles. Because you’re stuck using the old process, you’ll need to use manual signing here. When you select a profile, select one you created with the Local Push Provider iOS Dev template.

try to distribute to the AppStore from the organiser...

You need to do manual signing here too. In this case you want to select a profile that you created with the Local Push Provider iOS Dist template.

It look like IDEProvisioningRepair is creating a new Profile during distribution

Yeah, you gotta avoid that when using the old process.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Yeah, you gotta avoid that when using the old process.

I wasn't aware of the fact, that xCode can swap my profile in the background 😮 - instead of using the Distribution-Certificate which is linked in the Profile (and also installed on my machine) it tried an other one and decided to repair my profile...

Is there a way to prevent this repair-mechanism? The project was configured for manual signing, so I did not expect this.

But I have been able to successfully sign the app now! 🙏Thanks a lot @eskimo

I wasn't aware of the fact, that xCode can swap my profile in the background

If you use the Xcode organiser to distribute your app, Xcode has to apply a new profile because the Xcode archive must have a development profile and the product your upload or export must have a distribution one. But in the manual signing case the organiser explicitly asks you what profile to use, which isn’t something I’d characterise as “in the background”.

But I have been able to successfully sign the app now!

Yay!

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Local Push Connectivity API - Got 'Provisioning profile failed qualification' while distributing an app to the store
 
 
Q