diff --git a/CHANGELOG.md b/CHANGELOG.md index c1a975b..477d265 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,41 @@ All notable changes to flutter-tvos will be documented here. ## [Unreleased] +## [1.4.2] - 2026-07-21 + +### Changed + +- Bumped the pinned Flutter SDK to **3.44.7** (`84fc5cbb223b`). +- Engine artifacts are now `v1.0.1-flutter3.44.7`. These are **byte-identical** + to `v1.0.1-flutter3.44.6`, republished under the new name rather than + rebuilt: nothing in 3.44.7 reaches the tvOS engine. The only functional + change in the range is Android-side (`FlutterRenderer.java`), `DEPS` is + byte-identical, the Dart submodule is unchanged, and `darwin/`, `ios/` and + `impeller/` are untouched. The remaining commits are CI config and changelog + text. + +Verified with these artifacts against the 3.44.7 SDK before shipping: AOT on a +physical Apple TV 4K (tvOS 26.5) keeps platform identity intact +(`operatingSystem=tvos`, `isTvOS=true`), and a JIT/debug run on a tvOS 17.5 +simulator is clean with zero `Target OS is incompatible` errors, so the +metallib fix from 1.4.1 still holds on older runtimes. + +### Fixed + +- `Platform.isTvOS` now compiles in **debug** builds. It previously worked only + in profile/release: debug compiled against the stock Flutter SDK, which does + not declare the getter, so an app using the API the README recommends failed + to build with `Member not found: 'isTvOS'`. Present since the getter was + introduced — reproduced identically on 1.4.1 — and easy to miss because the + *values* (`operatingSystem`, `isIOS`) resolve at runtime from the device + engine in JIT and are correct in every mode; only the new member was missing + from the type checker's view. + + Debug now compiles against the same patched `flutter_patched_sdk` as profile, + which the `host_debug_unopt` artifact already shipped. Verified on a tvOS 17.5 + simulator (`isTvOS=true` in debug, `isAndroid`/`isMacOS` unaffected), AOT on a + physical Apple TV 4K is unchanged, and hot reload still works. + diff --git a/README.md b/README.md index cff284a..b132655 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ A Flutter toolchain for building and running Flutter apps on **Apple TV (tvOS)** ## Current version -- flutter-tvos: `1.4.1` -- Flutter SDK: `3.44.6` (`ee80f08bbf97172ec030b8751ceab557177a34a6`) -- tvOS engine artifacts: `v1.0.1-flutter3.44.6` (origin-signed) +- flutter-tvos: `1.4.2` +- Flutter SDK: `3.44.7` (`84fc5cbb223bc12f83d65b647ff8a56caf779ffd`) +- tvOS engine artifacts: `v1.0.1-flutter3.44.7` (origin-signed) ## Installation diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5eb99a5..e734359 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -v1.0.1-flutter3.44.6 +v1.0.1-flutter3.44.7 diff --git a/bin/internal/flutter.version b/bin/internal/flutter.version index 06222d4..5cf22c6 100644 --- a/bin/internal/flutter.version +++ b/bin/internal/flutter.version @@ -1 +1 @@ -ee80f08bbf97172ec030b8751ceab557177a34a6 \ No newline at end of file +84fc5cbb223bc12f83d65b647ff8a56caf779ffd diff --git a/lib/tvos_artifacts.dart b/lib/tvos_artifacts.dart index 9a956fe..7990b6f 100644 --- a/lib/tvos_artifacts.dart +++ b/lib/tvos_artifacts.dart @@ -53,24 +53,28 @@ class TvosArtifacts extends CachedArtifacts { } } - // For AOT (profile/release) builds, compile the app kernel against OUR - // patched `flutter_patched_sdk` (shipped inside the host engine artifact) - // rather than the stock Flutter checkout's. The patched dart:io - // `platform.dart` defines `isIOS = operatingSystem == "ios" || == "tvos"` - // and adds the `isTvOS` getter, so the un-folded platform-const getters - // evaluate correctly at runtime on tvOS. This is the companion to - // `TvosKernelSnapshot.build()`, which passes `targetOS: null` so those - // getters are not const-folded to "ios" at compile time. + // Compile the app kernel against OUR patched `flutter_patched_sdk` + // (shipped inside the host engine artifact) rather than the stock Flutter + // checkout's. The patched dart:io `platform.dart` defines + // `isIOS = operatingSystem == "ios" || == "tvos"` and adds the `isTvOS` + // getter, so the un-folded platform-const getters evaluate correctly at + // runtime on tvOS. This is the companion to `TvosKernelSnapshot.build()`, + // which passes `targetOS: null` so those getters are not const-folded to + // "ios" at compile time. // - // Debug (JIT) deliberately keeps the stock SDK: platform identity there is - // resolved by the device engine's own (patched) core libraries at runtime, - // so the compile SDK is irrelevant and we avoid disturbing the proven - // debug path. We only need our patched SDK where gen_snapshot bakes the - // SDK code into the app snapshot — i.e. precompiled builds. - if ((mode?.isPrecompiled ?? false) && - (artifact == Artifact.flutterPatchedSdkPath || - artifact == Artifact.platformKernelDill)) { - final String patchedSdkDir = _hostPatchedSdkDirectory(mode!); + // This applies to debug as well, not just AOT. Platform identity *values* + // do resolve at runtime in JIT — dart:io comes from the device engine's + // own patched core libraries — so for `operatingSystem` and `isIOS` the + // compile SDK genuinely is irrelevant there. But `isTvOS` is a member the + // stock SDK does not declare at all, and the frontend server type-checks + // against the compile SDK before anything runs: an app touching + // `Platform.isTvOS` failed to build in debug with + // `Member not found: 'isTvOS'` while compiling fine in profile/release. + // Pointing debug at the same patched SDK (which `host_debug_unopt` already + // ships) makes the getter exist in every mode. + if (artifact == Artifact.flutterPatchedSdkPath || + artifact == Artifact.platformKernelDill) { + final String patchedSdkDir = _hostPatchedSdkDirectory(mode ?? BuildMode.debug); if (artifact == Artifact.platformKernelDill) { return _fileSystem.path.join(patchedSdkDir, 'platform_strong.dill'); } diff --git a/pubspec.yaml b/pubspec.yaml index 4982202..2a472a3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_tvos description: Flutter CLI tool for building and running Flutter apps on Apple TV (tvOS). A custom embedder wrapping Flutter SDK with tvOS-specific build targets, device management, and plugin support. -version: 1.4.1 +version: 1.4.2 homepage: https://fluttertv.dev repository: https://github.com/fluttertv/flutter-tvos publish_to: "none" diff --git a/test/general/tvos_artifacts_test.dart b/test/general/tvos_artifacts_test.dart index 2b4387f..2aef9aa 100644 --- a/test/general/tvos_artifacts_test.dart +++ b/test/general/tvos_artifacts_test.dart @@ -68,23 +68,33 @@ void main() { ); }); - test('debug flutterPatchedSdkPath falls through to stock resolution', () { - // Debug resolves platform identity at runtime via the device engine, so - // the override is intentionally NOT applied — the path must come from - // the stock CachedArtifacts logic, not our engine_artifacts host SDK. - final String path = artifacts.getArtifactPath( - Artifact.flutterPatchedSdkPath, - mode: BuildMode.debug, + test('debug also uses the patched SDK (host_debug_unopt)', () { + // Debug resolves platform identity *values* at runtime via the device + // engine, so for `operatingSystem` and `isIOS` the compile SDK is + // irrelevant. But `isTvOS` is a member the stock SDK does not declare, + // and the frontend server type-checks against the compile SDK before + // anything runs — so with stock resolution an app touching + // `Platform.isTvOS` failed to build in debug with + // `Member not found: 'isTvOS'` while compiling fine in profile/release. + // Debug uses the same non-product SDK as profile. + expect( + artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, mode: BuildMode.debug), + '/engine_artifacts/host_debug_unopt/flutter_patched_sdk', + ); + expect( + artifacts.getArtifactPath(Artifact.platformKernelDill, mode: BuildMode.debug), + '/engine_artifacts/host_debug_unopt/flutter_patched_sdk/platform_strong.dill', ); - expect(path, isNot(contains('engine_artifacts'))); }); - test('debug platformKernelDill falls through to stock resolution', () { - final String path = artifacts.getArtifactPath( - Artifact.platformKernelDill, - mode: BuildMode.debug, + test('a null mode resolves to the debug (non-product) SDK', () { + // getArtifactPath is reachable without a mode; it must not throw and + // must not silently pick the product SDK, which would drop entry-point + // classes the JIT engine looks up natively. + expect( + artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath), + '/engine_artifacts/host_debug_unopt/flutter_patched_sdk', ); - expect(path, isNot(contains('engine_artifacts'))); }); test('handles the nested directory layout from zip extraction', () {