Files
element-x-ios/ElementX/SupportingFiles/target.yml
T
joel.poyet 1da4c0302e Point the classic app identifiers at HealthChat rather than Element (#1)
ClassicAppManager migrates an existing user's session and encryption keys by
reading the legacy app's app-group container and keychain. Those identifiers
defaulted to Element's own, which this team cannot provision, so loadAccounts()
threw invalidAppGroupIdentifier — caught and logged, never surfaced. Since both
apps share a bundle id, the result would be every existing user silently logged
out and losing local history when they update.

The legacy identifiers belong to HealthChat and are provisionable under the same
team, so repoint them rather than dropping them.

Also stop sending accounts without key backup to a dead end. Upstream shows those
users a sheet asking them to open Element Classic and set up backup first, but this
update replaces that app and nothing registers its URL scheme, so the sheet's only
button does nothing. Sign in directly instead: the user re-verifies the device and
loses only history that by definition has no backup.
2026-10-19 09:17:29 +02:00

304 lines
11 KiB
YAML

name: ElementX
schemes:
ElementX:
analyze:
config: Debug
archive:
config: Release
build:
targets:
ElementX:
- running
- testing
- profiling
- analyzing
- archiving
profile:
config: Release
run:
config: Debug
environmentVariables:
- variable: HTTPS_PROXY
value: localhost:9090
isEnabled: false
- variable: HTTP_PROXY
value: localhost:9090
isEnabled: false
- variable: UI_TESTS_SCREEN
value: ""
isEnabled: false
- variable: RESET_APP_SETTINGS
value: "true"
isEnabled: false
test:
config: Debug
gatherCoverageData: true
coverageTargets:
- ElementX
testPlans:
- path: ../../UnitTests/SupportingFiles/UnitTests.xctestplan
defaultPlan: true
targets:
ElementX:
type: application
platform: iOS
info:
path: Info.plist
properties:
UILaunchScreen:
UIColorName: colors/background-color
CFBundleDisplayName: $(APP_DISPLAY_NAME)
# HealthChat: without this CFBundleName defaults to $(PRODUCT_NAME) (ElementX, kept for the module
# name), which is what the web authentication session's sign-in alert shows — not CFBundleDisplayName.
CFBundleName: $(APP_DISPLAY_NAME)
CFBundleShortVersionString: $(MARKETING_VERSION)
CFBundleVersion: $(CURRENT_PROJECT_VERSION)
CFBundleURLTypes: [
{
CFBundleTypeRole: Editor,
CFBundleURLName: "Application",
CFBundleURLSchemes: [
$(BASE_BUNDLE_IDENTIFIER), # The app's own scheme for custom routes
"matrix" # Matrix URI scheme for permalinks
]
}
]
UIApplicationSceneManifest: {
UIApplicationSupportsMultipleScenes: true
}
UISupportedInterfaceOrientations: [
UIInterfaceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft,
UIInterfaceOrientationLandscapeRight
]
appGroupIdentifier: $(APP_GROUP_IDENTIFIER)
baseBundleIdentifier: $(BASE_BUNDLE_IDENTIFIER)
keychainAccessGroupIdentifier: $(KEYCHAIN_ACCESS_GROUP_IDENTIFIER)
classicAppGroupIdentifier: $(CLASSIC_APP_GROUP_IDENTIFIER)
classicAppKeychainServiceIdentifier: $(CLASSIC_APP_KEYCHAIN_SERVICE_IDENTIFIER)
classicAppKeychainAccessGroupIdentifier: $(CLASSIC_APP_KEYCHAIN_ACCESS_GROUP_IDENTIFIER)
classicAppDeepLinkURL: $(CLASSIC_APP_DEEP_LINK_URL)
productionAppName: $(PRODUCTION_APP_NAME)
isNightlyBuild: $(IS_NIGHTLY_BUILD)
ITSAppUsesNonExemptEncryption: false
NSUserActivityTypes: [
INSendMessageIntent,
INStartCallIntent,
]
NSCameraUsageDescription: To take pictures or videos and send them as a message $(APP_DISPLAY_NAME) needs access to the camera.
NSMicrophoneUsageDescription: To record and send messages with audio, $(APP_DISPLAY_NAME) needs to access the microphone.
NSPhotoLibraryAddUsageDescription: This lets you save images and videos to your photo library.
NSLocationWhenInUseUsageDescription: Grant location access so that $(APP_DISPLAY_NAME) can share your location.
NSLocationAlwaysAndWhenInUseUsageDescription: To share your live location, $(APP_DISPLAY_NAME) needs location access when the app is in the background.
NSFaceIDUsageDescription: Face ID is used to access your app.
UIBackgroundModes: [
audio,
fetch,
processing,
voip,
location
]
BGTaskSchedulerPermittedIdentifiers: [
io.element.elementx.background.refresh,
io.element.elementx.background.search-backfill
]
UTExportedTypeDeclarations:
- UTTypeConformsTo: [public.text]
UTTypeDescription: Mention Pills
UTTypeIdentifier: $(PILLS_UT_TYPE_IDENTIFIER)
CFBundleDocumentTypes:
- CFBundleTypeName: Mention Pills
CFBundleTypeRole: Viewer
LSHandlerRank: Owner
LSItemContentTypes: $(PILLS_UT_TYPE_IDENTIFIER)
LSSupportsOpeningDocumentsInPlace: false
entitlements:
path: ElementX.entitlements
properties:
aps-environment: development
com.apple.developer.associated-domains:
# HealthChat: app.healthchat.ch universal links + webcredentials (OAuth/autofill). matrix.to kept for permalinks.
- applinks:app.healthchat.ch
- applinks:matrix.to
- webcredentials:*.healthchat.ch
com.apple.developer.usernotifications.communication: true
com.apple.security.app-sandbox: true
com.apple.security.application-groups:
# HealthChat: dropped $(CLASSIC_APP_GROUP_IDENTIFIER) — not because it is un-provisionable,
# but because it resolves to group.ch.healthchat, the same value as $(APP_GROUP_IDENTIFIER)
# below. The legacy container is already entitled; listing it twice would duplicate the entry.
- $(APP_GROUP_IDENTIFIER)
com.apple.security.network.client: true
keychain-access-groups:
- $(KEYCHAIN_ACCESS_GROUP_IDENTIFIER)
# HealthChat: the legacy app's keychain group. ClassicAppManager reads the account and
# crypto-store keys from here to migrate existing users. Same team prefix, so it is
# provisionable — unlike Element's im.vector.app.* default in app.yml.
- $(CLASSIC_APP_KEYCHAIN_ACCESS_GROUP_IDENTIFIER)
settings:
base:
PRODUCT_NAME: $(APP_NAME)
PRODUCT_BUNDLE_IDENTIFIER: $(BASE_BUNDLE_IDENTIFIER)
MARKETING_VERSION: $(MARKETING_VERSION)
CURRENT_PROJECT_VERSION: $(CURRENT_PROJECT_VERSION)
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
DEVELOPMENT_TEAM: $(DEVELOPMENT_TEAM)
SWIFT_OBJC_BRIDGING_HEADER: ElementX/SupportingFiles/ElementX-Bridging-Header.h
SWIFT_OBJC_INTERFACE_HEADER_NAME: GeneratedInterface-Swift.h
PILLS_UT_TYPE_IDENTIFIER: $(BASE_BUNDLE_IDENTIFIER).pills
DEVELOPMENT_ASSET_PATHS: Components/DevelopmentAssets/Media
SWIFT_VERSION: 6
SWIFT_APPROACHABLE_CONCURRENCY: YES
SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor
OTHER_SWIFT_FLAGS:
- "-DIS_MAIN_APP"
preBuildScripts:
- name: 🛠 SwiftGen
runOnlyWhenInstalling: false
basedOnDependencyAnalysis: false
shell: /bin/sh
script: |
export PATH="$PATH:/opt/homebrew/bin"
if which swiftgen >/dev/null; then
swiftgen config run --config Tools/SwiftGen/swiftgen-config.yml
else
echo "warning: SwiftGen not installed, download from https://github.com/SwiftGen/SwiftGen"
fi
- name: 🧙 Sourcery - Generate mocks
runOnlyWhenInstalling: false
basedOnDependencyAnalysis: false
shell: /bin/sh
script: |
export PATH="$PATH:/opt/homebrew/bin"
if which sourcery >/dev/null; then
sourcery --config Tools/Sourcery/AutoMockableConfig.yml
else
echo "warning: Sourcery not installed, run swift run tools setup-project"
fi
- name: 🧙 Sourcery - Generate preview tests
runOnlyWhenInstalling: false
basedOnDependencyAnalysis: false
shell: /bin/sh
script: |
export PATH="$PATH:/opt/homebrew/bin"
if which sourcery >/dev/null; then
sourcery --config Tools/Sourcery/PreviewTestsConfig.yml
else
echo "warning: Sourcery not installed, run swift run tools setup-project"
fi
- name: 🧙 Sourcery - Generate Accessibility Tests
runOnlyWhenInstalling: false
basedOnDependencyAnalysis: false
shell: /bin/sh
script: |
export PATH="$PATH:/opt/homebrew/bin"
if which sourcery >/dev/null; then
sourcery --config Tools/Sourcery/TestablePreviewsDictionary.yml
sourcery --config Tools/Sourcery/AccessibilityTests.yml
else
echo "warning: Sourcery not installed, run swift run tools setup-project"
fi
postBuildScripts:
- name: ⚠️ SwiftLint
runOnlyWhenInstalling: false
basedOnDependencyAnalysis: false
shell: /bin/sh
script: |
export PATH="$PATH:/opt/homebrew/bin"
if which swiftlint >/dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
- name: 🧹 SwiftFormat
runOnlyWhenInstalling: false
basedOnDependencyAnalysis: false
shell: /bin/sh
script: |
export PATH="$PATH:/opt/homebrew/bin"
if which swiftformat >/dev/null; then
swiftformat --lint --lenient "$PROJECT_DIR"
else
echo "warning: SwiftFormat not installed, download from https://github.com/nicklockwood/SwiftFormat"
fi
dependencies:
- target: NSE
- target: ShareExtension
- target: MatrixRustSDKMocks
- package: MatrixRustSDK
embed: true
- package: Compound
- package: BuildExtensions
product: Macros
- package: Algorithms
- package: AsyncAlgorithms
- package: AnalyticsEvents
- package: Collections
- package: DeviceKit
- package: EmbeddedElementCall
- package: KeychainAccess
- package: Kingfisher
- package: KZFileWatchers
- package: LoremSwiftum
- package: LRUCache
- package: Mantis
- target: MapLibreInterface
embed: true
# Embedded but not linked, dlopen'd on first map use
- target: MapLibreShim
link: false
embed: true
# The app just embeds the framework so it's in the bundle for the shim's load
# command to resolve against.
- framework: ../../MapLibre.framework
implicit: true
link: false
embed: true
- package: ElementCall
product: ElementCall
- package: PostHog
- package: SwiftState
- package: GZIP
- package: Sentry
products:
- Sentry
- SentrySwiftUI
- package: Version
- package: Emojibase
- package: WysiwygComposer
- package: SwiftOGG
- package: SwiftSoup
- package: SwiftFlow
product: Flow
- package: DSWaveformImage
product: DSWaveformImageViews
sources:
- path: ../Sources
excludes:
- Other/Extensions/XCTestCase.swift
- Other/Extensions/XCUIElement.swift
- path: ../../Components/Secrets/Secrets.swift
- path: ../Resources
- path: ../SupportingFiles
- path: ../../Tools/Scripts/Templates/SimpleScreenExample/ElementX
- path: ../../Components/DevelopmentAssets/Media
# This is required for testing purposes... The problem with unit tests is that if you
# try to `@testable import NSE` you can only get the definition of files, but due to a
# limitation in how they work, they can only compile files that are part of the main test
# target, so linking will fail. The solution is to just have the main app to reference the
# extension code, and test it directly.
- path: ../../NSE/Sources