GuidesRecipesAPI ReferenceChangelog
Log In
Guides

Test Apps with ManagedApp and Blueprints

Deploy iOS and visionOS apps for development and testing that leverage the ManagedApp Framework with Jamf blueprints and Custom Declarations

Overview

Developers that adopt Apple’s ManagedApp Framework within their apps can test their app with Jamf Pro during development, before releasing the app to the App Store for distribution. Blueprints in Jamf Pro can be used to deploy Custom Declaration components that can deploy configurations and secrets such as credentials and identity certificates that can be read and used by apps built to leverage ManagedApp capabilities.

📘

Note

The purpose of this guide is to allow app developers to use device management and blueprints for proof of concept testing during the development and testing phases of an app that has not yet been distributed through the App Store. Using this guide requires self hosting of apps and asset files to use during testing, and it is not recommended to use production identity credentials if they are publicly accessible.

This guide will be updated as feature availability continues to be added to blueprints, such as custom asset hosting and variable substitution capabilities. Consider testing your app's capabilities to work with newer options such as certificate and credential delivery and usage when installed with device management.

About the ManagedApp Framework

Apple’s ManagedApp Framework for iOS and visionOS apps allows for a new type of managed app, where secrets such as identities, certificates, and other credentials can be securely delivered by a device management service such as Jamf Pro. This allows for enhanced and simplified end user experience with your app in managed environments, where an organization can securely provision a credential with an application, allowing for automatic user sign in to the app, as an example.

The app developer must explicitly build their app to support these frameworks for iOS 18.4 or visionOS 2.4 or later, and the app’s configuration and credential assets must be deployed via Declarative Device Management (DDM) to allow the app to read the deployed secrets.

The following types of secrets and credentials can be deployed as asset declarations for an app to access and read:

For more information see Apple documentation and video resources:

Requirements

  • Target device(s) for testing that are running iOS 18.4 or later, or visionOS 2.4 or later, that have their UUID(s) registered in your Apple Developer account.
  • Self-hosted app .ipa file with ManagedApp Framework support
  • A manifest.plist file created and self-hosted to use for enterprise distribution and installation
  • Self-hosted asset files that can define credential requests or AppConfig data
  • Jamf Pro hosted in Jamf Cloud, with Jamf Account SSO (OIDC) enabled to use Blueprints
    • See documentation for more information about enabling Jamf Account SSO authentication in Jamf Pro

Prepare your app and assets for self-hosting

Before deploying declarations with blueprints in Jamf, testing resources like your .ipa file and credential assets for testing need to be prepared and hosted so testing device targets can access and install these resources using the Managed App framework and DDM.

📘

Note

Self-hosted .ipa files, manifest.plist files, and asset files must be at a location that begins with https:// and the content-type metadata for each file must match the expected file types, such as:

  • .ipa files - application/octet-stream
  • .plist files - application/plist or application/xml
  • JSON asset files - application/json

Build your app with an ad-hoc provisioning profile for registered devices in your Developer Account

This guide presumes that the .ipa file built for testing contains an embedded provisioning profile which includes the unique device identifiers (UDIDs) of testing devices registered with the Apple for the developer. For more information, see the following article:

Distributing your app to registered devices | Apple Developer Documentation

Additional documentation from Apple can be found at the Create a Custom Distribution section of the Distributing your app for beta testing and releases article.

For example, in Xcode you can navigate to the Window menu > Organizer > Select Archive > Distribute App > Select Custom > Pick Release Testing > Select Team > check "include manifest for over-the-air installation" > fill in URLs > Automatically manage signing

Prepare your app for Enterprise App distribution

While an app is in testing phases, deploying it independently from App Store distribution is desired for rapid iteration during testing, using a process similar to in-house apps built using the Apple Developer Enterprise Program, however a developer does not need to be a member of that program. This ad hoc distribution process can install an app using an .ipa file that has an embedded provisioning profile for testing devices as noted in the previous step.

Distribution via an app.managed declaration requires the hosting of an app manifest.plist file which contains instructions for downloading the .ipa file for the app. The target testing device needs to be able to access both the hosted .plist file and the .ipa file in order to install successfully.

The contents of the app manifest should look similar to this example:

<?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>items</key>
	<array>
		<dict>
			<key>assets</key>
			<array>
				<dict>
					<key>kind</key>
					<string>software-package</string>
					<key>url</key>
					<string>https://your-hosting-URL.com/YourApp.ipa</string>
				</dict>
				<dict>
					<key>kind</key>
					<string>display-image</string>
					<key>url</key>
					<string>https://your-hosting-URL.com/YourApp.png</string>
				</dict>
				<dict>
					<key>kind</key>
					<string>full-size-image</string>
					<key>url</key>
					<string>https://your-hosting-URL.com/YourApp_background.png</string>
				</dict>
			</array>
			<key>metadata</key>
			<dict>
				<key>bundle-identifier</key>
				<string>com.yourorg.yourapp</string>
				<key>bundle-version</key>
				<string>1.0</string>
				<key>kind</key>
				<string>software</string>
				<key>platform-identifier</key>
				<string>com.apple.platform.iphoneos</string>
				<key>title</key>
				<string>YourApp</string>
			</dict>
		</dict>
	</array>
</dict>
</plist>

Build and host a credential asset for deploying secrets to your app (optional)

Credentials for testing require your organization to host a JSON file that is accessible to your test devices. The contents and format requirements of these credential files is outlined in Apple’s Github repository for device management. Note that $VARIABLE substitution is not supported when self-hosting credential assets for testing deployment.

Below is an example ACME credential:

{
  "Subject": [
    [
      [
        "CN",
        "SERIALNUMBER"
      ]
    ]
  ],
  "Attest": true,
  "DirectoryURL": "https://your-acme-ca.org/acme/acme-da/directory",
  "KeySize": 384,
  "HardwareBound": true,
  "KeyType": "ECSECPrimeRandom",
  "ExtendedKeyUsage": [
    "1.3.6.1.5.5.7.3.2"
  ],
  "ClientIdentifier": "SERIALNUMBER"
}

Below is an example SCEP credential:

{
  "URL": "https://your-scep-ca.org/pki/scep",
  "Name": "Your SCEP Identity",
  "Challenge": "2791b3f40ff00b57e7c8b959a92cd217",
  "KeyType": "RSA",
  "Keysize": 2048,
  "KeyUsage": 5,
  "Retries": 3,
  "RetryDelay": 10,
  "Subject": [
    [
      [
        "CN",
        "Jamf-iOS-App-Identity"
      ]
    ]
  ]
}

Build and host a data asset for AppConfig (optional)

If your app uses custom settings, the ManagedApp Framework allows for key/value pairs to be defined in a .plist XML file. This file must be self-hosted to test in a Custom Declaration for app.managed with blueprints. If your app requires AppConfig to define device hardware identifiers, consider hard-coding the identifier values for your test device into your .plist file, as $VARIABLE substitution is not supported in this context.

Below is an example of an AppConfig.plist file:

<?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>
    <!-- The welcome message to display in the app -->
    <key>welcomeMessage</key>
    <string>Welcome from your MDM server!</string>
    
    <!-- Whether a specific feature is enabled or not -->
    <key>isFeatureEnabled</key>
    <true/>
    
    <!-- The maximum number of items allowed -->
    <key>maxItems</key>
    <integer>15</integer>
</dict>
</plist>

Deploy a Custom Declaration in Jamf blueprints to include both an app.managed configuration and associated Credential or Data assets

The Custom Declaration component in blueprints supports the creation and deployment of both Asset and Configuration types of declarations. The blueprints service assigns unique identifiers to each declaration object, and these identifiers can be included and defined with a variable substitution within a configuration to reference associated assets.

For more information, see current product documentation: Creating a Custom Declaration Blueprint.

When deploying an app.managed declaration and a credential asset, the app.managed configuration must reference an asset’s unique identifier within its JSON payload. Jamf blueprints allows for the use of the variable $PAYLOAD_# to represent the asset, where the number used in the variable is relative to the asset’s placement and object order within the custom declaration.

For example, if the asset is configured as the second declaration payload object, the variable would read as $PAYLOAD_2 within the configuration.

Consider the following example of deploying an app.managed configuration which references an ACME credential:

Payload 1Value
KindConfiguration
ChannelSystem
Typecom.apple.configuration.app.managed
{
  "AppConfig": {
    "Identities": [
      {
        "Identifier": "device-identity",
        "AssetReference": "$PAYLOAD_2"
      }
    ]
  },
  "ManifestURL": "https://s3.us-west-2.amazonaws.com/your_bucket/app_manifest.plist",
  "InstallBehavior": {
    "Install": "Required"
  }
}
Payload 2Value
KindAsset
ChannelSystem
Typecom.apple.asset.credential.acme
{
  "Reference": {
    "DataURL": "https://your_bucket.s3.us-east-2.amazonaws.com/Acme.json",
    "ContentType": "application/json"
  }
}

Example in Blueprints when saved:

After building the Custom Declaration, select a Smart or Static Group to target the Scope, then press the Deploy button to initiate sending it to target devices.

Verify declaration installation status via the Jamf Pro API

Once the blueprint is deployed to a target group, the blueprints interface will make live updates to show deployed, pending, or failed status. When a custom declaration shows as “failed,” it can be for a number of reasons, including the following:

  • Invalid JSON configuration and formatting of the configuration or asset
  • Inability to retrieve or install the app using the supplied manifest.plist
  • Invalid content-type metadata headers for hosted assets or manifest files

Nuanced error information is sent autonomously by target devices using the declarative device management Status Channel, and this data – including full status channel reports – can be retrieved from the Jamf Pro API for your test device.

Use the endpoint located at this location to retrieve status channel data. https://yourServer.jamfcloud.com/api/v1/ddm/\{clientManagementId}/status-items

https://developer.jamf.com/jamf-pro/reference/get_v1-ddm-clientmanagementid-status-items

The relevant Reasons message for any failed declarations will show in one of the following sections of the status report:

  • "management.declarations.assets"
  • "management.declarations.configurations"

Successfully installed and activated declarations should have a status that includes active=true and valid=valid within the report sent by the device.

Use the Jamf Pro API documentation page for a simplified status query

The Jamf Pro API has a documentation page which allows you to query and GET a managed device’s status report to view specific error messages during troubleshooting. This page is accessible at https://yourServer.jamfcloud.com/api/doc and DDM status reports can be viewed with the following steps:

  • Navigate to the page in your web browser
  • Authenticate with a local Jamf Pro User or Client ID and Secret, then click Authorize button to receive a token
  • When successfully authenticated, this message will appear: Authorized. Token successfully generated!
  • Expand the declarative-device-management object by clicking the disclosure triangle to its right, then expand the GET object for /v1/ddm/{clientManagementId}/status-items
  • Click the Try it out button
  • Enter the clientManagementId of your test device, then click Execute
    • The clientManagementId of your device can be obtained from the General category of the device’s inventory record in Jamf Pro, labeled there as Jamf Pro Management ID:

The server should respond with a 200 message and a full status report, such as shown in the example below:


Best practices for testing

Below are several tips to help test individual components without needing to troubleshoot an error of a combined Configuration and Asset declarations and their dependencies.

Install any required Root CA or Intermediate CA certificates via a configuration profile before installing credential assets

To establish trust for the certificate authority used to issue identity credentials, you may need to install the chain of trust on the testing device before installing credential assets that request SCEP or ACME certificates. While this could be done using a certificate asset declaration, it may be easier for testing to install these certificates using a Configuration Profile with a Certificate payload from Jamf Pro.

Consider testing asset validation independently of the app.managed configuration

Successfully deployed app.managed configurations and their associated asset declarations relies on the target device being able to install and activate both components simultaneously. For example, if there is an error in how the asset was designed, it can make both it and the app.managed configuration to present themselves as failed or invalid via the DDM status channel responses.

An asset declaration cannot be validated on its own if it’s not reference properly from a configuration, which can make it difficult to assess whether a credential asset was configured correctly for a certificate request. To simplify this verification, consider deploying a com.apple.configuration.security.identity configuration which references the credential asset.

Example of Identity configuration referencing an ACME asset

Once the certificate is installed successfully, this configuration and certificate information can be observed on the managed device in the Settings app. Navigate to: General > VPN & Device Management > MDM Profile > Configurations > Certificates to view the certificate.

Example of certificate within Device Management Configurations

Consider testing your application’s manifest.plist in a simplified app.managed configuration

Confirming that your app can be deployed using your hosted manifest with a simple app.managed configuration allows you to confirm it is configured and hosted correctly. This can be done as a test before adding more complex settings and related assets to your configuration.

Example app.managed declaration with a simple configuration