Skip to content

[WIP] Add in-app migration to the new Home Assistant app - #5511

Draft
bgoncal wants to merge 2 commits into
mainfrom
app-migration
Draft

[WIP] Add in-app migration to the new Home Assistant app#5511
bgoncal wants to merge 2 commits into
mainfrom
app-migration

Conversation

@bgoncal

@bgoncal bgoncal commented Aug 24, 2026

Copy link
Copy Markdown
Member

AI Policy

Select exactly one option that describes AI usage in this contribution:

  • I have not used AI for this contribution.
  • AI assistance was used for this contribution.
  • AI fully generated the code for this contribution, but I've reviewed and understood it before submitting and will respond without AI during review.

Summary

Apple's App Transfer is not available for this app, so the replacement ships under a new developer account with a new bundle ID. This adds the in-app flow that moves a user's servers and configuration from the old app to the new one.

The old app packages its servers (connection details and tokens) and its configuration (widgets, watch, CarPlay, quick actions, kiosk, notification categories, NFC tags, reminders sync, app settings), compresses it, and hands it to the new app in a URL fragment. The new app restores the servers first, then the configuration, then tells the old app it can stand down. Payloads too large for a single link are handed over a slice at a time.

Every identifier for the new app is a placeholder in AppMigrationConstants, and the whole flow stays hidden until they are filled in, so this has no effect on the current app.

Screenshots

Recorded as snapshot tests in light and dark mode: Tests/App/Container/AppMigration/__Snapshots__/.
CleanShot 2026-08-25 at 10 09 21@2x (1)

Link to pull request in Documentation repository

Documentation: home-assistant/companion.home-assistant#

Any other notes

Copilot AI lite review requested due to automatic review settings August 24, 2026 21:15
@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

⚠️ Unused L10n strings detected

Found 1 unused localization strings in the codebase.

Click to see details
Parsing Strings.swift...
Found 2691 L10n strings

Reading all Swift source code...
Read 10703102 characters of Swift code

Checking for unused strings...
Checked 100/2691 strings...
Checked 200/2691 strings...
Checked 300/2691 strings...
Checked 400/2691 strings...
Checked 500/2691 strings...
Checked 600/2691 strings...
Checked 700/2691 strings...
Checked 800/2691 strings...
Checked 900/2691 strings...
Checked 1000/2691 strings...
Checked 1100/2691 strings...
Checked 1200/2691 strings...
Checked 1300/2691 strings...
Checked 1400/2691 strings...
Checked 1500/2691 strings...
Checked 1600/2691 strings...
Checked 1700/2691 strings...
Checked 1800/2691 strings...
Checked 1900/2691 strings...
Checked 2000/2691 strings...
Checked 2100/2691 strings...
Checked 2200/2691 strings...
Checked 2300/2691 strings...
Checked 2400/2691 strings...
Checked 2500/2691 strings...
Checked 2600/2691 strings...

================================================================================
UNUSED STRINGS REPORT
================================================================================

Found 1 unused strings:


WIDGETS:
  - L10n.Widgets.Energy.electricityTotal
    Key: widgets.energy.electricity_total
    Line: 9178

================================================================================
Total unused: 1
================================================================================

================================================================================
Copy-paste these keys into the "Lokalise: Delete Keys" workflow (keys input):
================================================================================
widgets.energy.electricity_total

To remove them, run the
Lokalise: Delete Keys
workflow — it deletes the keys from Lokalise and opens a PR removing them from
Localizable.strings and regenerating Strings.swift. Copy-paste these keys into the keys input:

widgets.energy.electricity_total

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an in-app migration flow to move servers (including tokens) and app configuration from the old Home Assistant iOS app (old Apple Developer account / bundle ID) to the new app, using a URL-fragment handoff with optional chunking and a full-screen guided UI on both the source and destination apps.

Changes:

  • Introduces a complete App Migration feature set (payload encoding/decoding + chunking, URL formats, persisted chunk store, status/retirement).
  • Adds SwiftUI flows and presenters for exporting/importing, plus Settings entry points and lifecycle URL handling.
  • Adds localization and snapshot/unit tests covering the migration UI and core encoding/link/chunk behavior.

Reviewed changes

Copilot reviewed 74 out of 110 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Tests/App/Container/AppMigration/AppMigrationAwaitingConfirmationView.test.swift Snapshot coverage for the “awaiting confirmation” screen.
Tests/App/Container/AppMigration/AppMigrationChunk.test.swift Unit tests for chunk wire format parsing/encoding.
Tests/App/Container/AppMigration/AppMigrationChunkStore.test.swift Unit tests for persisted chunk assembly and session isolation.
Tests/App/Container/AppMigration/AppMigrationCompletedView.test.swift Snapshot coverage for the source-app completion screen.
Tests/App/Container/AppMigration/AppMigrationFailureView.test.swift Snapshot coverage for the source-app failure screen.
Tests/App/Container/AppMigration/AppMigrationImportCompletedView.test.swift Snapshot coverage for the destination-app completion screen.
Tests/App/Container/AppMigration/AppMigrationImportFailureView.test.swift Snapshot coverage for the destination-app failure screen.
Tests/App/Container/AppMigration/AppMigrationIntroView.test.swift Snapshot coverage for the intro screen (server-count pluralization).
Tests/App/Container/AppMigration/AppMigrationLink.test.swift Unit tests for handoff/continuation/completion URL round-trips and safety properties.
Tests/App/Container/AppMigration/AppMigrationNeedsInstallView.test.swift Snapshot coverage for “needs install” screen.
Tests/App/Container/AppMigration/AppMigrationPayloadCoder.test.swift Unit tests for chunking thresholds and payload decoding errors.
Tests/App/Container/AppMigration/AppMigrationProgressView.test.swift Snapshot coverage for export/import progress step lists and transfer bar.
Tests/App/Container/AppMigration/AppMigrationStepRow.test.swift Snapshot coverage for step-row visual states.
Sources/App/Container/AppMigration/AppMigrationAwaitingConfirmationView.swift Source-app “waiting for destination app to finish” UI.
Sources/App/Container/AppMigration/AppMigrationBottomActions.swift Shared bottom action buttons for list-based migration screens.
Sources/App/Container/AppMigration/AppMigrationCompletedView.swift Source-app completion UI and messaging.
Sources/App/Container/AppMigration/AppMigrationCompletionKey.swift Notification key + notification name for completion acknowledgements.
Sources/App/Container/AppMigration/AppMigrationContinuationKey.swift Notification keys + notification names for chunk continuation flow.
Sources/App/Container/AppMigration/AppMigrationCoverModifier.swift Window-root full-screen cover routing for export/import flows.
Sources/App/Container/AppMigration/AppMigrationDisclosureRow.swift Row component for intro “included/excluded” lists.
Sources/App/Container/AppMigration/AppMigrationExportStep.swift Export-side step definitions for the progress list.
Sources/App/Container/AppMigration/AppMigrationExporter.swift Source-app packaging (servers + configuration + metadata) into migration payload.
Sources/App/Container/AppMigration/AppMigrationFailureView.swift Source-app failure UI with retry/later actions and Settings shortcut.
Sources/App/Container/AppMigration/AppMigrationFlowView.swift Source-app full migration flow coordinator view.
Sources/App/Container/AppMigration/AppMigrationHaptics.swift Shared haptics for step progress, chunk transfer, success/failure.
Sources/App/Container/AppMigration/AppMigrationHeaderRow.swift Common header (illustration + title + descriptions) for migration screens.
Sources/App/Container/AppMigration/AppMigrationIllustration.swift Shared symbol illustration component for the flow.
Sources/App/Container/AppMigration/AppMigrationImportCompletedView.swift Destination-app completion UI.
Sources/App/Container/AppMigration/AppMigrationImportFailureView.swift Destination-app failure UI.
Sources/App/Container/AppMigration/AppMigrationImportFlowView.swift Destination-app full-screen import flow wrapper.
Sources/App/Container/AppMigration/AppMigrationImporter.swift Destination-side application of servers/config and callback acknowledgement.
Sources/App/Container/AppMigration/AppMigrationImportPause.swift Control-flow error used to pause import while awaiting more chunks.
Sources/App/Container/AppMigration/AppMigrationImportPhase.swift Destination-side phase model.
Sources/App/Container/AppMigration/AppMigrationImportStep.swift Destination-side step definitions for the progress list.
Sources/App/Container/AppMigration/AppMigrationImportSummary.swift Summary of what was imported for destination completion UI.
Sources/App/Container/AppMigration/AppMigrationImportViewModel.swift Destination-side import state machine, chunk ingestion, and continuation requests.
Sources/App/Container/AppMigration/AppMigrationIntroView.swift Source-side intro/explainer UI before export begins.
Sources/App/Container/AppMigration/AppMigrationNeedsInstallView.swift Source-side UI when destination app isn’t installed yet.
Sources/App/Container/AppMigration/AppMigrationPhase.swift Source-side phase model.
Sources/App/Container/AppMigration/AppMigrationPresenter.swift Singleton presenter routing URLs and deciding which migration flow to show.
Sources/App/Container/AppMigration/AppMigrationPresentation.swift Identifiable presentation state for full-screen covers.
Sources/App/Container/AppMigration/AppMigrationProgressView.swift Shared progress-list UI for export/import steps + optional transfer bar.
Sources/App/Container/AppMigration/AppMigrationRetirement.swift Source-app retirement behavior after destination confirms import.
Sources/App/Container/AppMigration/AppMigrationRowIcon.swift Shared leading icon layout for migration rows.
Sources/App/Container/AppMigration/AppMigrationScreenLock.swift Idle-timer disabling counter for long-running migrations.
Sources/App/Container/AppMigration/AppMigrationScreenLockModifier.swift View modifier hooking screen-lock acquire/release to view lifetime.
Sources/App/Container/AppMigration/AppMigrationSettingsSection.swift Settings entry point for migration (only on source + when configured).
Sources/App/Container/AppMigration/AppMigrationSettingsShortcutButton.swift Settings shortcut shown on failure screen.
Sources/App/Container/AppMigration/AppMigrationStepDescribing.swift Shared protocol for step models shown in progress lists.
Sources/App/Container/AppMigration/AppMigrationStepRow.swift Step-row UI with animated indicator and accessibility status.
Sources/App/Container/AppMigration/AppMigrationStepState.swift Step state enum for progress UI.
Sources/App/Container/AppMigration/AppMigrationTransferProgress.swift Transfer progress model (completed/total + fraction).
Sources/App/Container/AppMigration/AppMigrationTransferProgressView.swift Transfer bar shown when chunking is in play.
Sources/App/Container/AppMigration/AppMigrationViewModel.swift Source-side export state machine (packaging + handoff + confirmation).
Sources/App/Container/AppMigration/View+AppMigrationCover.swift Convenience modifier to attach migration cover at window root.
Sources/App/Container/AppMigration/View+AppMigrationHeaderRowStyle.swift List-row styling helper for migration header row.
Sources/App/Container/AppMigration/View+AppMigrationKeepsScreenAwake.swift Convenience modifier to keep screen awake during migration views.
Sources/App/HAApp.swift Hooks migration routing into onOpenURL / universal link handling and applies window-root cover.
Sources/App/Resources/en.lproj/Localizable.strings Adds all English strings for the migration UI and errors.
Sources/App/Resources/Info.plist Adds destination URL scheme to LSApplicationQueriesSchemes for install-detection.
Sources/App/Settings/ConfigurationTransfer/AppConfigurationTransfer.swift Adds import/export helpers for in-memory (Data) configuration transfer for migration.
Sources/App/Settings/Settings/SettingsView.swift Adds migration section entry point into Settings (source-only, when configured).
Sources/Shared/Common/AppMigration/AppMigrationChunk.swift Defines chunk wire format for sliced payload handoff.
Sources/Shared/Common/AppMigration/AppMigrationChunkStore.swift Persists and assembles received chunks across app switches.
Sources/Shared/Common/AppMigration/AppMigrationCodingError.swift Localized error types for payload encoding/decoding and size limits.
Sources/Shared/Common/AppMigration/AppMigrationConstants.swift Central identifiers + safety limits + “configured” gate.
Sources/Shared/Common/AppMigration/AppMigrationLink.swift Constructs/parses handoff, continuation, and completion URLs.
Sources/Shared/Common/AppMigration/AppMigrationPayload.swift Defines the migration payload envelope.
Sources/Shared/Common/AppMigration/AppMigrationPayloadCoder.swift Compresses/encodes payload to base64url, slices into chunks, and decodes обратно.
Sources/Shared/Common/AppMigration/AppMigrationRole.swift Determines whether the running build is source vs destination.
Sources/Shared/Common/AppMigration/AppMigrationStatus.swift Persists migration state (prompt snooze, handed-off, imported) in shared prefs.
Sources/Shared/Common/Extensions/Data+Base64URL.swift Adds base64url encode/decode helpers used by migration payload transport.
Sources/Shared/Resources/Swiftgen/Strings.swift SwiftGen output updated with L10n.AppMigration.* accessors.
APP_MIGRATION.md End-to-end operational checklist and rationale for moving to a new Apple Developer account.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +14 to +16
public static var current: AppMigrationRole {
AppConstants.BundleID.hasPrefix(AppMigrationConstants.sourceBundleID) ? .source : .destination
}
Comment on lines +106 to +110
let value = components.queryItems?
.first { $0.name == AppMigrationConstants.importedServerCountQueryItem }?
.value
return value.flatMap(Int.init) ?? 0
}
Comment on lines +64 to +68
func run() async {
stepStates = [:]
phase = .running

transfer = chunk.total > 1 ? .init(completed: chunk.index, total: chunk.total) : nil
@bgoncal
bgoncal marked this pull request as draft August 24, 2026 22:06
Apple's App Transfer is not available for this app, so the replacement
ships under a new developer account with a new bundle ID. This adds the
in-app flow that moves a user's servers and configuration across.

The flow is hidden until the new app's identifiers are filled in, so it
has no effect on the current app.
@bgoncal bgoncal changed the title Add in-app migration to the new Home Assistant app [WIP] Add in-app migration to the new Home Assistant app Aug 25, 2026
@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 48.39961% with 532 lines in your changes missing coverage. Please review.
✅ Project coverage is 32.98%. Comparing base (08bf9c7) to head (44165ca).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...Container/AppMigration/AppMigrationViewModel.swift 0.00% 138 Missing ⚠️
...ner/AppMigration/AppMigrationImportViewModel.swift 0.00% 95 Missing ⚠️
.../Container/AppMigration/AppMigrationFlowView.swift 0.00% 47 Missing ⚠️
...Container/AppMigration/AppMigrationPresenter.swift 14.81% 46 Missing ⚠️
...ner/AppMigration/AppMigrationSettingsSection.swift 8.33% 33 Missing ⚠️
...iner/AppMigration/AppMigrationImportFlowView.swift 0.00% 29 Missing ⚠️
.../Container/AppMigration/AppMigrationImporter.swift 0.00% 22 Missing ⚠️
.../Container/AppMigration/AppMigrationExporter.swift 0.00% 20 Missing ⚠️
...ontainer/AppMigration/AppMigrationScreenLock.swift 0.00% 11 Missing ⚠️
...p/Container/AppMigration/AppMigrationHaptics.swift 0.00% 10 Missing ⚠️
... and 16 more
Additional details and impacted files
@@            Coverage Diff             @@
##            main    #5511       +/-   ##
==========================================
+ Coverage   0.81%   32.98%   +32.16%     
==========================================
  Files        635     1020      +385     
  Lines      37088    72741    +35653     
==========================================
+ Hits         302    23993    +23691     
- Misses     36786    48748    +11962     
Files with missing lines Coverage Δ
...gration/AppMigrationAwaitingConfirmationView.swift 100.00% <100.00%> (ø)
...ainer/AppMigration/AppMigrationBottomActions.swift 100.00% <100.00%> (ø)
...ainer/AppMigration/AppMigrationCompletedView.swift 100.00% <100.00%> (ø)
...ainer/AppMigration/AppMigrationDisclosureRow.swift 100.00% <100.00%> (ø)
...ontainer/AppMigration/AppMigrationExportStep.swift 100.00% <100.00%> (ø)
...ntainer/AppMigration/AppMigrationFailureView.swift 100.00% <100.00%> (ø)
...Container/AppMigration/AppMigrationHeaderRow.swift 100.00% <100.00%> (ø)
...tainer/AppMigration/AppMigrationIllustration.swift 100.00% <100.00%> (ø)
...AppMigration/AppMigrationImportCompletedView.swift 100.00% <100.00%> (ø)
...r/AppMigration/AppMigrationImportFailureView.swift 100.00% <100.00%> (ø)
... and 39 more

... and 1195 files with indirect coverage changes

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants