From 511224bcd406bf35c575c1a6062f9d10811033c5 Mon Sep 17 00:00:00 2001 From: dirtydishes Date: Mon, 25 May 2026 00:24:13 -0400 Subject: [PATCH] fix native playback cocoa pods build --- .beads/interactions.jsonl | 1 + .beads/issues.jsonl | 1 + Dreamio.xcodeproj/project.pbxproj | 75 +++++- Dreamio.xcworkspace/contents.xcworkspacedata | 10 + Dreamio/DreamioWebViewController.swift | 16 ++ Dreamio/VLCNativePlaybackBackend.swift | 8 + Podfile.lock | 16 ++ README.md | 46 +++- ...25-guard-native-playback-availability.html | 218 ++++++++++++++++++ 9 files changed, 386 insertions(+), 5 deletions(-) create mode 100644 Dreamio.xcworkspace/contents.xcworkspacedata create mode 100644 Podfile.lock create mode 100644 docs/turns/2026-05-25-guard-native-playback-availability.html diff --git a/.beads/interactions.jsonl b/.beads/interactions.jsonl index 9b76e6a..503e0cc 100644 --- a/.beads/interactions.jsonl +++ b/.beads/interactions.jsonl @@ -6,3 +6,4 @@ {"id":"int-3dbe205a","kind":"field_change","created_at":"2026-05-25T03:23:00.515861Z","actor":"dirtydishes","issue_id":"dreamio-2lp","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Fixed Swift raw string escaping and guarded MobileVLCKit import for builds before pod install."}} {"id":"int-23df9e14","kind":"field_change","created_at":"2026-05-25T03:41:03.811099Z","actor":"dirtydishes","issue_id":"dreamio-vxs","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Resolved native playback stream URLs before opening VLC, added resolver selection tests, and documented validation limits."}} {"id":"int-76aa54ba","kind":"field_change","created_at":"2026-05-25T03:51:39.198446Z","actor":"dirtydishes","issue_id":"dreamio-8vi","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}} +{"id":"int-74805ffd","kind":"field_change","created_at":"2026-05-25T04:21:42.440755Z","actor":"dirtydishes","issue_id":"dreamio-2k5","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Added native backend availability guard, installed CocoaPods, generated workspace metadata, documented setup, and validated available checks."}} diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 5f2e4d6..14a1d76 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,3 +1,4 @@ +{"_type":"issue","id":"dreamio-2k5","title":"Guard native playback when MobileVLCKit is unavailable","description":"Dreamio can currently present its native player from raw xcodeproj builds where MobileVLCKit is not linked, which leads to the fallback backend message instead of an actionable setup path. Add a runtime/build availability check, document the CocoaPods workspace requirement, and validate the fallback remains buildable.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T04:15:47Z","created_by":"dirtydishes","updated_at":"2026-05-25T04:21:42Z","started_at":"2026-05-25T04:15:56Z","closed_at":"2026-05-25T04:21:42Z","close_reason":"Added native backend availability guard, installed CocoaPods, generated workspace metadata, documented setup, and validated available checks.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"dreamio-8vi","title":"Fix URL redaction crash on percent-encoded paths","description":"## Why\nDreamio can crash while logging WebKit navigation and playback URLs because URLRedactor writes raw replacement text back into URLComponents.percentEncodedPath.\n\n## What needs to be done\n- Update URL redaction to avoid assigning invalid characters to percentEncodedPath\n- Preserve token/path redaction behavior for diagnostics\n- Add a regression test covering percent-encoded path input similar to the Stremio crash logs\n\n## Acceptance criteria\n- Redacting a URL with percent-encoded path segments does not crash\n- Diagnostics still remove query strings/fragments and redact token-like path segments\n- Tests cover the regression","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T03:50:04Z","created_by":"dirtydishes","updated_at":"2026-05-25T03:51:39Z","started_at":"2026-05-25T03:50:08Z","closed_at":"2026-05-25T03:51:39Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"dreamio-vxs","title":"Resolve final media URLs before native playback","description":"Dreamio native playback can pass addon resolver URLs into VLC instead of the final direct media URL. Resolve known Stremio addon stream responses before presenting the native player, preserve needed headers, and make startup failure recoverable.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T03:36:14Z","created_by":"dirtydishes","updated_at":"2026-05-25T03:41:04Z","started_at":"2026-05-25T03:36:19Z","closed_at":"2026-05-25T03:41:04Z","close_reason":"Resolved native playback stream URLs before opening VLC, added resolver selection tests, and documented validation limits.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"dreamio-2lp","title":"Fix native playback build blockers","description":"Correct Swift string escaping for the injected stream bridge and allow the VLC backend source to compile before MobileVLCKit is installed by guarding the import with canImport.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-25T03:22:52Z","created_by":"dirtydishes","updated_at":"2026-05-25T03:23:00Z","started_at":"2026-05-25T03:23:00Z","closed_at":"2026-05-25T03:23:00Z","close_reason":"Fixed Swift raw string escaping and guarded MobileVLCKit import for builds before pod install.","dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/Dreamio.xcodeproj/project.pbxproj b/Dreamio.xcodeproj/project.pbxproj index 37a31d6..d006627 100644 --- a/Dreamio.xcodeproj/project.pbxproj +++ b/Dreamio.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 2771CB8C5035D4D119051FEA /* Pods_Dreamio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 908FA15B08AB341C116BAB46 /* Pods_Dreamio.framework */; }; 6F2A2B362C00100100DREAMIO /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2A2B332C00100100DREAMIO /* AppDelegate.swift */; }; 6F2A2B372C00100100DREAMIO /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2A2B342C00100100DREAMIO /* SceneDelegate.swift */; }; 6F2A2B382C00100100DREAMIO /* DreamioWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F2A2B352C00100100DREAMIO /* DreamioWebViewController.swift */; }; @@ -28,6 +29,9 @@ 6F2A2B482C00100100DREAMIO /* VLCNativePlaybackBackend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VLCNativePlaybackBackend.swift; sourceTree = ""; }; 6F2A2B492C00100100DREAMIO /* NativePlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativePlayerViewController.swift; sourceTree = ""; }; 6F2A2B512C00100100DREAMIO /* StreamResolver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StreamResolver.swift; sourceTree = ""; }; + 701702B9C2BFBEDE36E7F0A3 /* Pods-Dreamio.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Dreamio.release.xcconfig"; path = "Target Support Files/Pods-Dreamio/Pods-Dreamio.release.xcconfig"; sourceTree = ""; }; + 908FA15B08AB341C116BAB46 /* Pods_Dreamio.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Dreamio.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BF0A4D5BAC9400AEEF3B0181 /* Pods-Dreamio.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Dreamio.debug.xcconfig"; path = "Target Support Files/Pods-Dreamio/Pods-Dreamio.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -35,17 +39,38 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2771CB8C5035D4D119051FEA /* Pods_Dreamio.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 5DEC645FC7F60E33F3A4E21E /* Frameworks */ = { + isa = PBXGroup; + children = ( + 908FA15B08AB341C116BAB46 /* Pods_Dreamio.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 6593E172E04E344E08B5CAA8 /* Pods */ = { + isa = PBXGroup; + children = ( + BF0A4D5BAC9400AEEF3B0181 /* Pods-Dreamio.debug.xcconfig */, + 701702B9C2BFBEDE36E7F0A3 /* Pods-Dreamio.release.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 6F2A2B272C00100100DREAMIO = { isa = PBXGroup; children = ( 6F2A2B322C00100100DREAMIO /* Dreamio */, 6F2A2B312C00100100DREAMIO /* Products */, + 6593E172E04E344E08B5CAA8 /* Pods */, + 5DEC645FC7F60E33F3A4E21E /* Frameworks */, ); sourceTree = ""; }; @@ -80,9 +105,11 @@ isa = PBXNativeTarget; buildConfigurationList = 6F2A2B412C00100100DREAMIO /* Build configuration list for PBXNativeTarget "Dreamio" */; buildPhases = ( + 9F808EDAD2C69568A9142D10 /* [CP] Check Pods Manifest.lock */, 6F2A2B2C2C00100100DREAMIO /* Sources */, 6F2A2B2D2C00100100DREAMIO /* Frameworks */, 6F2A2B2E2C00100100DREAMIO /* Resources */, + F26EA81D312D2AA38B06CF11 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -136,6 +163,48 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 9F808EDAD2C69568A9142D10 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Dreamio-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + F26EA81D312D2AA38B06CF11 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Dreamio/Pods-Dreamio-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Dreamio/Pods-Dreamio-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Dreamio/Pods-Dreamio-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 6F2A2B2C2C00100100DREAMIO /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -191,7 +260,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -252,7 +321,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -272,6 +341,7 @@ }; 6F2A2B3E2C00100100DREAMIO /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = BF0A4D5BAC9400AEEF3B0181 /* Pods-Dreamio.debug.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -293,6 +363,7 @@ }; 6F2A2B3F2C00100100DREAMIO /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 701702B9C2BFBEDE36E7F0A3 /* Pods-Dreamio.release.xcconfig */; buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; diff --git a/Dreamio.xcworkspace/contents.xcworkspacedata b/Dreamio.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..312399b --- /dev/null +++ b/Dreamio.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Dreamio/DreamioWebViewController.swift b/Dreamio/DreamioWebViewController.swift index 6d5399e..97da38e 100644 --- a/Dreamio/DreamioWebViewController.swift +++ b/Dreamio/DreamioWebViewController.swift @@ -368,6 +368,12 @@ final class DreamioWebViewController: UIViewController { @MainActor private func resolveAndPresentNativePlayback(_ request: NativePlaybackRequest) async { + guard VLCNativePlaybackBackend.isAvailable else { + lastNativePlaybackURL = nil + showNativePlaybackUnavailableAlert() + return + } + do { let resolved = try await streamResolver.resolve(request: request) #if DEBUG @@ -407,6 +413,16 @@ final class DreamioWebViewController: UIViewController { present(alert, animated: true) } + private func showNativePlaybackUnavailableAlert() { + let alert = UIAlertController( + title: "Native playback needs CocoaPods", + message: "This build was opened from Dreamio.xcodeproj or built before MobileVLCKit was installed. Run pod install, open Dreamio.xcworkspace, then build again to play MKV, AVI, and WebM streams.", + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "Close", style: .cancel)) + present(alert, animated: true) + } + #if DEBUG private func logDiagnostic(type: String, payload: Any, pageURL: String?) { let redactedPageURL = pageURL.map(redactedURLString) ?? "unknown" diff --git a/Dreamio/VLCNativePlaybackBackend.swift b/Dreamio/VLCNativePlaybackBackend.swift index 2390133..2d8e67a 100644 --- a/Dreamio/VLCNativePlaybackBackend.swift +++ b/Dreamio/VLCNativePlaybackBackend.swift @@ -5,6 +5,14 @@ import MobileVLCKit #endif final class VLCNativePlaybackBackend: NSObject, NativePlaybackBackend { + static var isAvailable: Bool { +#if canImport(MobileVLCKit) + true +#else + false +#endif + } + let view = UIView() var onReady: (() -> Void)? var onFailure: ((Error) -> Void)? diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..f409370 --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,16 @@ +PODS: + - MobileVLCKit (3.7.3) + +DEPENDENCIES: + - MobileVLCKit + +SPEC REPOS: + trunk: + - MobileVLCKit + +SPEC CHECKSUMS: + MobileVLCKit: 73d7ddb52238b6885b70b0f281cae75a0a6e3ac0 + +PODFILE CHECKSUM: 1e4ca4475e4e798e59c235cee9233ad9691c3bee + +COCOAPODS: 1.16.2 diff --git a/README.md b/README.md index ddf7daf..750a4f9 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,51 @@ WebKit commonly cannot play, especially MKV, AVI, and WebM debrid URLs. Keep using `Dreamio.xcworkspace` after installing pods so Xcode links the native playback backend. +If the app says "Native playback needs CocoaPods" or a player screen says +"Native playback is not available in this build," the binary was built without +MobileVLCKit linked. To resolve it, install CocoaPods, run `pod install` from +this repository, open `Dreamio.xcworkspace` instead of `Dreamio.xcodeproj`, and +build the workspace. Direct MKV, AVI, and WebM playback depends on that +workspace build because the raw project intentionally keeps a fallback compile +path for environments where CocoaPods has not been installed yet. + +On macOS, install CocoaPods with RubyGems: + +```bash +sudo gem install cocoapods +pod --version +pod install +open Dreamio.xcworkspace +``` + +If the gem install fails because of a local Ruby or permissions issue, another +common macOS option is Homebrew: + +```bash +brew install cocoapods +pod --version +pod install +open Dreamio.xcworkspace +``` + +The official CocoaPods getting started guide documents the RubyGems install +path: https://guides.cocoapods.org/using/getting-started.html + ## Validation Notes -The repository machine currently has Command Line Tools selected instead of full -Xcode, and CocoaPods is not installed, so command-line `pod install` and -`xcodebuild` validation are not available here. +CocoaPods 1.16.2 was installed with Homebrew on this repository machine, and +`pod install` generated `Dreamio.xcworkspace` plus `Podfile.lock` with +MobileVLCKit 3.7.3. The workspace builds from the command line when full Xcode +is selected for that command: + +```bash +DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer \ + xcodebuild -workspace Dreamio.xcworkspace \ + -scheme Dreamio \ + -configuration Debug \ + -sdk iphonesimulator \ + build +``` ## Playback Validation Checklist diff --git a/docs/turns/2026-05-25-guard-native-playback-availability.html b/docs/turns/2026-05-25-guard-native-playback-availability.html new file mode 100644 index 0000000..1c33230 --- /dev/null +++ b/docs/turns/2026-05-25-guard-native-playback-availability.html @@ -0,0 +1,218 @@ + + + + + + Guard Native Playback Availability + + + +
+
+

Guard Native Playback Availability

+

Dreamio now checks whether the MobileVLCKit-backed native player is actually linked before presenting the full-screen native player. Raw project builds stay buildable, but they now show a setup alert instead of opening a black player that can only fail.

+
+ Beads: dreamio-2k5 + Native playback + CocoaPods setup + 2026-05-25 +
+
+ +
+

Summary

+

Fixed the unavailable native playback build path by exposing a build-time availability check on VLCNativePlaybackBackend and using it before Dreamio presents native playback. CocoaPods was installed through Homebrew, pod install was run, and the generated workspace now links MobileVLCKit.

+
+ +
+

Changes Made

+
    +
  • Added VLCNativePlaybackBackend.isAvailable, backed by the same canImport(MobileVLCKit) compile condition as the real VLC implementation.
  • +
  • Updated DreamioWebViewController to check native backend availability before resolving and presenting the native player.
  • +
  • Added an actionable setup alert for builds that do not link MobileVLCKit.
  • +
  • Updated the README to explain that the exact unavailable-build message means the binary was built without the CocoaPods workspace.
  • +
  • Installed CocoaPods 1.16.2 with Homebrew and ran pod install, generating Dreamio.xcworkspace and Podfile.lock with MobileVLCKit 3.7.3.
  • +
  • Disabled Xcode user script sandboxing for the project so CocoaPods can embed MobileVLCKit during the framework copy phase.
  • +
+
+ +
+

Context

+

The repository has a Podfile declaring MobileVLCKit, but this checkout did not have a generated Pods/ directory or Dreamio.xcworkspace. In that state, Swift takes the fallback compile path where canImport(MobileVLCKit) is false. Before this change, Dreamio could still present the native player, which then displayed the generic fallback error.

+
+ +
+

Important Implementation Details

+
    +
  • The fallback backend remains intact so opening Dreamio.xcodeproj directly still compiles.
  • +
  • The guard runs before stream resolution, avoiding unnecessary resolver network work when native playback cannot succeed in the current build.
  • +
  • The duplicate playback key is cleared when the guard blocks playback, so the user can retry after rebuilding the app correctly.
  • +
  • The generated workspace references Dreamio.xcodeproj and Pods/Pods.xcodeproj. The Pods/ directory remains ignored, while Podfile.lock and workspace metadata are tracked.
  • +
  • ENABLE_USER_SCRIPT_SANDBOXING is set to NO because the CocoaPods embed frameworks script uses rsync to copy the MobileVLCKit framework into the app bundle.
  • +
  • No public app-facing API changed.
  • +
+
+ +
+

Relevant Diff Snippets

+

@pierre/diffs is installed as a library dependency, but its package does not expose a runnable CLI in this checkout, and npx @pierre/diffs --help failed with "could not determine executable to run." The plain diff below is the fallback snippet for the core behavior change.

+
diff --git a/Dreamio/DreamioWebViewController.swift b/Dreamio/DreamioWebViewController.swift
+@@ -368,6 +368,12 @@ final class DreamioWebViewController: UIViewController {
+     @MainActor
+     private func resolveAndPresentNativePlayback(_ request: NativePlaybackRequest) async {
++        guard VLCNativePlaybackBackend.isAvailable else {
++            lastNativePlaybackURL = nil
++            showNativePlaybackUnavailableAlert()
++            return
++        }
++
+         do {
+             let resolved = try await streamResolver.resolve(request: request)
+
+diff --git a/Dreamio/VLCNativePlaybackBackend.swift b/Dreamio/VLCNativePlaybackBackend.swift
+@@ -5,6 +5,14 @@ import MobileVLCKit
+ #endif
+
+ final class VLCNativePlaybackBackend: NSObject, NativePlaybackBackend {
++    static var isAvailable: Bool {
++#if canImport(MobileVLCKit)
++        true
++#else
++        false
++#endif
++    }
++
+     let view = UIView()
+     var onReady: (() -> Void)?
+     var onFailure: ((Error) -> Void)?
+
+ +
+

Expected Impact for End-Users

+

Users who accidentally run a raw .xcodeproj build will see a clear CocoaPods setup message instead of a black native player with an unavailable-build failure. Users who build from Dreamio.xcworkspace with MobileVLCKit linked should continue into VLC-backed direct-file playback.

+
+ +
+

Validation

+
    +
  • Ran swiftc Dreamio/StreamCandidate.swift Dreamio/StreamResolver.swift Tests/StreamResolverTests.swift -o /tmp/dreamio-stream-tests && /tmp/dreamio-stream-tests: passed.
  • +
  • Ran swiftc -typecheck Dreamio/StreamCandidate.swift Dreamio/StreamResolver.swift: passed.
  • +
  • Ran git diff --check: passed.
  • +
  • Ran HOMEBREW_NO_AUTO_UPDATE=1 brew install cocoapods: passed, installing CocoaPods 1.16.2.
  • +
  • Ran pod --version && pod install: passed, installing MobileVLCKit 3.7.3 and generating the workspace.
  • +
  • Ran DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer xcodebuild -workspace Dreamio.xcworkspace -scheme Dreamio -configuration Debug -sdk iphonesimulator build: passed.
  • +
+
+ +
+

Issues, Limitations, and Mitigations

+
The simulator workspace build passes. Real-device playback validation is still required for the actual VLC-backed stream behavior.
+
    +
  • The global xcode-select value still points at Command Line Tools because changing it requires sudo. Command-line builds can use DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer.
  • +
  • The Pods/ directory is intentionally ignored by git, so another checkout should run pod install after pulling.
  • +
  • The native player still depends on MobileVLCKit behavior once the workspace build is available.
  • +
+
+ +
+

Follow-up Work

+
    +
  • On device, select a direct MKV, AVI, or WebM stream and confirm the VLC-backed player starts.
  • +
+
+
+ +