| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 04d4a92 commit bc1e4ea
28 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -140,6 +140,7 @@ declare const __COMMONJS__: boolean; | |||
| 140 | 140 | declare const __ANDROID__: boolean; | |
| 141 | 141 | declare const __IOS__: boolean; | |
| 142 | 142 | declare const __VISIONOS__: boolean; | |
| 143 | + declare const __TVOS__: boolean; | ||
| 143 | 144 | declare const __APPLE__: boolean; | |
| 144 | 145 | ||
| 145 | 146 | declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): number; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -37,7 +37,7 @@ export { ModuleNameResolver } from './module-name-resolver'; | |||
| 37 | 37 | export { _setResolver } from './module-name-resolver/helpers'; | |
| 38 | 38 | export type { PlatformContext } from './module-name-resolver'; | |
| 39 | 39 | export type { ModuleListProvider } from './module-name-resolver/helpers'; | |
| 40 | - export { isAndroid, isIOS, isVisionOS, isApple, Screen, Device, platformNames } from './platform'; | ||
| 40 | + export { isAndroid, isIOS, isVisionOS, isTvOS, isApple, Screen, Device, platformNames } from './platform'; | ||
| 41 | 41 | export type { IDevice } from './platform'; | |
| 42 | 42 | export { profile, enable as profilingEnable, disable as profilingDisable, time as profilingTime, uptime as profilingUptime, start as profilingStart, stop as profilingStop, isRunning as profilingIsRunning, dumpProfiles as profilingDumpProfiles, resetProfiles as profilingResetProfiles, startCPUProfile as profilingStartCPU, stopCPUProfile as profilingStopCPU } from './profiling'; | |
| 43 | 43 | export type { InstrumentationMode, TimerInfo } from './profiling'; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -87,15 +87,24 @@ const minHeightQualifier: QualifierSpec = { | |||
| 87 | 87 | ||
| 88 | 88 | const platformQualifier: QualifierSpec = { | |
| 89 | 89 | isMatch: function (path: string): boolean { | |
| 90 | - return path.includes('.android') || path.includes('.ios'); | ||
| 90 | + return path.includes('.android') || path.includes('.ios') || path.includes('.tvos'); | ||
| 91 | 91 | }, | |
| 92 | 92 | getMatchOccurences: function (path: string): Array<string> { | |
| 93 | - return path.match(new RegExp('\\.android|\\.ios', 'g')); | ||
| 93 | + return path.match(new RegExp('\\.android|\\.ios|\\.tvos', 'g')); | ||
| 94 | 94 | }, | |
| 95 | 95 | getMatchValue(value: string, context: PlatformContext): number { | |
| 96 | 96 | const val = value.substring(1); | |
| 97 | + const os = context.os.toLowerCase(); | ||
| 98 | + if (val === os) { | ||
| 99 | + // exact platform: .tvos on tvOS, .ios on iOS, .android on Android | ||
| 100 | + return 2; | ||
| 101 | + } | ||
| 102 | + if (val === 'ios' && os === 'tvos') { | ||
| 103 | + // tvOS falls back to .ios files, below an explicit .tvos candidate | ||
| 104 | + return 1; | ||
| 105 | + } | ||
| 97 | 106 | ||
| 98 | - return val === context.os.toLowerCase() ? 1 : -1; | ||
| 107 | + return -1; | ||
| 99 | 108 | }, | |
| 100 | 109 | }; | |
| 101 | 110 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,27 @@ | |||
| 1 | + import { afterEach, describe, expect, it, vi } from 'vitest'; | ||
| 2 | + | ||
| 3 | + afterEach(() => { | ||
| 4 | + vi.unstubAllGlobals(); | ||
| 5 | + vi.resetModules(); | ||
| 6 | + }); | ||
| 7 | + | ||
| 8 | + describe('tvOS platform identity', () => { | ||
| 9 | + it('loads with bundlers that do not define the new tvOS flag', async () => { | ||
| 10 | + delete (globalThis as any).__TVOS__; | ||
| 11 | + const platform = await import('./common'); | ||
| 12 | + expect(platform.isTvOS).toBe(false); | ||
| 13 | + const { Device } = await import('./device/index.ios'); | ||
| 14 | + expect(Device.os).toBe('iOS'); | ||
| 15 | + }); | ||
| 16 | + | ||
| 17 | + it('recognizes tvOS as both tvOS and iOS-compatible', async () => { | ||
| 18 | + vi.stubGlobal('__TVOS__', true); | ||
| 19 | + vi.stubGlobal('__IOS__', false); | ||
| 20 | + vi.stubGlobal('__VISIONOS__', false); | ||
| 21 | + const platform = await import('./common'); | ||
| 22 | + expect(platform.isTvOS).toBe(true); | ||
| 23 | + expect(platform.isIOS).toBe(true); | ||
| 24 | + const { Device } = await import('./device/index.ios'); | ||
| 25 | + expect(Device.os).toBe('tvOS'); | ||
| 26 | + }); | ||
| 27 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,10 +5,12 @@ export const platformNames = { | |||
| 5 | 5 | android: 'Android', | |
| 6 | 6 | ios: 'iOS', | |
| 7 | 7 | visionos: 'visionOS', | |
| 8 | + tvos: 'tvOS', | ||
| 8 | 9 | apple: 'apple', | |
| 9 | 10 | }; | |
| 10 | 11 | ||
| 11 | 12 | export const isAndroid = !!__ANDROID__; | |
| 12 | - export const isIOS = !!__IOS__ || !!__VISIONOS__; | ||
| 13 | + export const isTvOS = typeof __TVOS__ !== 'undefined' && !!__TVOS__; | ||
| 14 | + export const isIOS = !!__IOS__ || !!__VISIONOS__ || isTvOS; | ||
| 13 | 15 | export const isVisionOS = !!__VISIONOS__; | |
| 14 | 16 | export const isApple = !!__APPLE__; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,4 +1,4 @@ | |||
| 1 | - import { platformNames } from '../common'; | ||
| 1 | + import { isTvOS, platformNames } from '../common'; | ||
| 2 | 2 | ||
| 3 | 3 | type DeviceType = 'Phone' | 'Tablet' | 'Vision'; | |
| 4 | 4 | ||
@@ -15,6 +15,8 @@ class DeviceRef { | |||
| 15 | 15 | get os(): string { | |
| 16 | 16 | if (__VISIONOS__) { | |
| 17 | 17 | return platformNames.visionos; | |
| 18 | + } else if (isTvOS) { | ||
| 19 | + return platformNames.tvos; | ||
| 18 | 20 | } else { | |
| 19 | 21 | return platformNames.ios; | |
| 20 | 22 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,6 +24,11 @@ export const isApple: boolean; | |||
| 24 | 24 | */ | |
| 25 | 25 | export const isVisionOS: boolean; | |
| 26 | 26 | ||
| 27 | + /** | ||
| 28 | + * Gets a value indicating if the app is running on the tvOS platform. | ||
| 29 | + */ | ||
| 30 | + export const isTvOS: boolean; | ||
| 31 | + | ||
| 27 | 32 | export * from './common'; | |
| 28 | 33 | export * from './device'; | |
| 29 | 34 | export * from './screen'; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -10,7 +10,7 @@ var hasMainInit = false | |||
| 10 | 10 | var hasMainBoot = false | |
| 11 | 11 | var hasMainSetMainScene = false | |
| 12 | 12 | ||
| 13 | - @available(iOS 14.0, *) | ||
| 13 | + @available(iOS 14.0, tvOS 14.0, *) | ||
| 14 | 14 | struct NativeScriptMainWindow: Scene { | |
| 15 | 15 | ||
| 16 | 16 | #if os(visionOS) | |
@@ -144,7 +144,7 @@ final class NativeScriptWindowCommandCoordinator { | |||
| 144 | 144 | } | |
| 145 | 145 | #endif | |
| 146 | 146 | ||
| 147 | - @available(iOS 13.0, *) | ||
| 147 | + @available(iOS 13.0, tvOS 13.0, *) | ||
| 148 | 148 | struct NativeScriptAppView: UIViewRepresentable { | |
| 149 | 149 | /// A closure that's called when the window is found. | |
| 150 | 150 | var found: ((UIWindowScene?) -> Void) | |
@@ -173,7 +173,7 @@ struct NativeScriptAppView: UIViewRepresentable { | |||
| 173 | 173 | } | |
| 174 | 174 | } | |
| 175 | 175 | ||
| 176 | - @available(iOS 13.0, *) | ||
| 176 | + @available(iOS 13.0, tvOS 13.0, *) | ||
| 177 | 177 | @objc public class NativeScriptViewFactory: NSObject, NativeScriptEmbedderDelegate { | |
| 178 | 178 | @objc static var shared: NativeScriptViewFactory? | |
| 179 | 179 | @objc static var app: NativeScriptContainerCtrl? | |
@@ -195,7 +195,7 @@ struct NativeScriptAppView: UIViewRepresentable { | |||
| 195 | 195 | return views!.object(forKey: id) as! UIView | |
| 196 | 196 | } | |
| 197 | 197 | ||
| 198 | - @available(iOS 15.0, *) | ||
| 198 | + @available(iOS 15.0, tvOS 15.0, *) | ||
| 199 | 199 | @objc public static func getKeyWindow() -> UIWindow? { | |
| 200 | 200 | return UIApplication | |
| 201 | 201 | .shared | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -40,6 +40,7 @@ if (typeof global.__metadata === 'undefined') { | |||
| 40 | 40 | export const ios = platformNames.ios.toLowerCase(); | |
| 41 | 41 | export const android = platformNames.android.toLowerCase(); | |
| 42 | 42 | export const visionos = platformNames.visionos.toLowerCase(); | |
| 43 | + export const tvos = platformNames.tvos.toLowerCase(); | ||
| 43 | 44 | export const apple = platformNames.apple.toLowerCase(); | |
| 44 | 45 | export const defaultNameSpaceMatcher = /tns\.xsd$/i; | |
| 45 | 46 | ||
@@ -439,7 +440,7 @@ export namespace xml2ui { | |||
| 439 | 440 | if (value) { | |
| 440 | 441 | const toLower = value.toLowerCase(); | |
| 441 | 442 | ||
| 442 | - return toLower === android || toLower === ios || toLower === visionos || toLower === apple; | ||
| 443 | + return toLower === android || toLower === ios || toLower === visionos || toLower === tvos || toLower === apple; | ||
| 443 | 444 | } | |
| 444 | 445 | ||
| 445 | 446 | return false; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,7 +8,8 @@ import { booleanConverter } from '../core/view-base'; | |||
| 8 | 8 | ||
| 9 | 9 | @NativeClass | |
| 10 | 10 | class WKNavigationDelegateImpl extends NSObject implements WKNavigationDelegate { | |
| 11 | - public static ObjCProtocols = [WKNavigationDelegate]; | ||
| 11 | + // WebKit does not exist on tvOS; keep this module loadable there (ui/index imports it eagerly). | ||
| 12 | + public static ObjCProtocols = typeof WKNavigationDelegate !== 'undefined' ? [WKNavigationDelegate] : []; | ||
| 12 | 13 | public static initWithOwner(owner: WeakRef<WebView>): WKNavigationDelegateImpl { | |
| 13 | 14 | const handler = <WKNavigationDelegateImpl>WKNavigationDelegateImpl.new(); | |
| 14 | 15 | handler._owner = owner; | |
@@ -99,7 +100,7 @@ class WKNavigationDelegateImpl extends NSObject implements WKNavigationDelegate | |||
| 99 | 100 | ||
| 100 | 101 | @NativeClass | |
| 101 | 102 | class WKUIDelegateImpl extends NSObject implements WKUIDelegate { | |
| 102 | - public static ObjCProtocols = [WKUIDelegate]; | ||
| 103 | + public static ObjCProtocols = typeof WKUIDelegate !== 'undefined' ? [WKUIDelegate] : []; | ||
| 103 | 104 | public static initWithOwner(owner: WeakRef<WebView>): WKUIDelegateImpl { | |
| 104 | 105 | const handler = <WKUIDelegateImpl>WKUIDelegateImpl.new(); | |
| 105 | 106 | handler._owner = owner; | |
@@ -179,6 +180,9 @@ export class WebView extends WebViewBase { | |||
| 179 | 180 | } | |
| 180 | 181 | ||
| 181 | 182 | createNativeView() { | |
| 183 | + if (typeof WKWebView === 'undefined') { | ||
| 184 | + throw new Error('WebView is not available on this platform (WebKit is missing, e.g. tvOS).'); | ||
| 185 | + } | ||
| 182 | 186 | const jScript = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'initial-scale=1.0'); document.getElementsByTagName('head')[0].appendChild(meta);"; | |
| 183 | 187 | const wkUScript = WKUserScript.alloc().initWithSourceInjectionTimeForMainFrameOnly(jScript, WKUserScriptInjectionTime.AtDocumentEnd, true); | |
| 184 | 188 | const wkUController = WKUserContentController.new(); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments