app_spec.json Reference¶
app_spec.json sits at the root of a client app repository and drives
the patch_and_tag_for_xcode_build.py script
(peek_field_app/xcode-cloud-template/). Running the script before
tagging a build stamps all client-specific values into the Angular
project files, the Xcode project, and the server-info defaults asset —
so the built App.ipa is pre-configured for that deployment with no
manual edits required.
Shape¶
{
"appName": "peek",
"appId": "com.synerty.peek",
"appIcon": "resources/icon.png",
"appDotVersion": "0.0.0",
"teamId": null,
"appearance": {
"backgroundColor": "#26abe2",
"environmentName": null
},
"serverConnection": {
"host": null,
"useSsl": false,
"httpPort": 8000,
"websocketPort": 8000,
"hasConnected": false
},
"oauth2": {
"appId": null,
"tenantId": null
}
}
Field Reference¶
Field |
Description |
|---|---|
|
iOS bundle identifier, e.g.
|
|
Apple Developer team ID for code signing |
|
Hex colour used as the app’s primary / splash colour |
|
Short label shown on the config screen; must match the git branch name |
|
Peek backend hostname (no scheme or port) |
|
|
|
HTTP port — |
|
WebSocket port — typically same as
|
|
|
|
Azure Entra Application (client) ID |
|
Azure Entra Directory (tenant) ID |
What the Script Writes¶
The script writes the following server-info-tuple-defaults.json
asset (peek_field_app/src/assets/peek_core_device/):
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
It also updates:
ios/App/App.xcodeproj/project.pbxproj—PRODUCT_BUNDLE_IDENTIFIERandDEVELOPMENT_TEAMsrc/environments/peek-app-environment.ts— version stringapp_spec.json—appDotVersionbumped to the new git tag
Azure Application Proxy — host and oauth2.appId¶
When the Peek backend is published through Azure Application Proxy,
serverConnection.host and oauth2.appId must belong to the same
Entra app registration.
hostThe Application Proxy external hostname (without scheme), e.g.
peekfieldapp-synerty.msappproxy.net. The field app connects to this host for both HTTP and WebSocket traffic.oauth2.appIdThe Application (client) ID of the Entra app registration that owns the Application Proxy endpoint at
host. The iOS app uses this ID to drive the MSAL authentication flow against Entra before the proxy grants access.oauth2BundleId(derived fromappId)The iOS bundle identifier is used by MSAL to construct the redirect URI
msauth.<bundleId>://auth. That exact URI must be registered on the Entra app registration under the iOS / macOS platform — see Azure Proxy — App Setup. Becauseoauth2BundleIdis derived from the top-levelappId, changing the bundle ID requires updating both the Xcode project and the Entra registration.
The OAuth2 scope the app requests depends on the identifier URI configured on the Entra app registration:
https://<external-host>(recommended for Application Proxy) → scopehttps://<host>/user_impersonationapi://<clientId>→ scopeapi://<clientId>/user_impersonation
The https:// format is recommended because it keeps the scope
human-readable and ties it directly to the proxy URL.
Example¶
app_spec.json for the PeekFieldApp Azure proxy deployment:
{
"appName": "peek",
"appId": "com.synerty.peek",
"teamId": "Q55F59LQD3",
"appearance": {
"backgroundColor": "#26abe2",
"environmentName": "PROD"
},
"serverConnection": {
"host": "peekfieldapp-synerty.msappproxy.net",
"useSsl": true,
"httpPort": 443,
"websocketPort": 443,
"hasConnected": true
},
"oauth2": {
"appId": "908c7b2f-e757-46be-9c6c-03da026a4159",
"tenantId": "253aed61-d766-447d-8c13-44d7e0daeeb9"
}
}
Running the script produces the following
server-info-tuple-defaults.json:
{
"host": "peekfieldapp-synerty.msappproxy.net",
"useSsl": true,
"httpPort": 443,
"websocketPort": 443,
"hasConnected": true,
"oauth2AppId": "908c7b2f-e757-46be-9c6c-03da026a4159",
"oauth2TenantId": "253aed61-d766-447d-8c13-44d7e0daeeb9",
"oauth2BundleId": "com.synerty.peek"
}
On first launch the iOS app reads this asset, skips the Connect screen
(hasConnected: true), and immediately starts the MSAL flow against
the Entra tenant. The redirect URI msauth.com.synerty.peek://auth
must be registered under iOS / macOS on the app registration —
see Azure Proxy — App Setup.
Running the Script¶
From the repo root (the directory that contains app_spec.json
and peek_field_app/):
pip install gitpython
python peek_field_app/xcode-cloud-template/patch_and_tag_for_xcode_build.py
The script validates that the active git branch name matches
appearance.environmentName, then stamps all project files, commits,
and creates a version tag. Xcode Cloud detects the new tag and starts
a build automatically.
Troubleshooting¶
“Safari cannot open the page because the address is invalid” after Microsoft login.
The CFBundleURLSchemes entry in Info.plist does not match the
iOS bundle identifier. After a successful Entra login, MSAL constructs
the redirect URI as msauth.<bundleId>://auth using the runtime
bundle ID. If Info.plist still registers the base bundle ID (e.g.
msauth.com.synerty.peek) instead of the client-specific one (e.g.
msauth.com.synerty.peek.nzor1pek6), iOS has no handler for the
redirect URI and Safari shows this error.
Fix — update the MSAL entry in
peek_field_app/ios/App/App/Info.plist to match the bundle ID:
<!-- Before -->
<dict>
<key>CFBundleURLName</key>
<string>com.synerty.peek</string>
<key>CFBundleURLSchemes</key>
<array>
<string>msauth.com.synerty.peek</string>
</array>
</dict>
<!-- After (bundle ID = com.synerty.peek.nzor1pek6) -->
<dict>
<key>CFBundleURLName</key>
<string>com.synerty.peek.nzor1pek6</string>
<key>CFBundleURLSchemes</key>
<array>
<string>msauth.com.synerty.peek.nzor1pek6</string>
</array>
</dict>
patch_and_tag_for_xcode_build.py performs this update automatically
using plistlib — it finds the CFBundleURLTypes entry whose
scheme starts with msauth. and replaces both the scheme and the
CFBundleURLName with msauth.<appId> and <appId>
respectively. This only requires the appId field in
app_spec.json to be correct.