is_tv_ffi 0.7.1 copy "is_tv_ffi: ^0.7.1" to clipboard
is_tv_ffi: ^0.7.1 copied to clipboard

Detects whether a Flutter app is running on a TV: Android TV, tvOS, webOS, Tizen and TV-mode Linux and Windows, using FFI and JNI rather than platform channels.

is_tv_ffi #

A Flutter plugin to detect if the current device is a TV.

Platform Support #

Android iOS MacOS Web Linux Windows

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
    is_tv_ffi: ^0.7.1

Usage #

import 'package:is_tv_ffi/is_tv_ffi.dart';

// Check if the device is a TV
final isTv = const IsTvFfi().isTv;
if (isTv) {
  print('Running on a TV');
} else {
  print('Not running on a TV');
}

isTv is a synchronous native call, so there is nothing to await.

iOS and macOS: Swift Package Manager only #

The iOS and macOS implementations ship as Swift packages (ios/is_tv_ffi/, macos/is_tv_ffi/) with no podspec, so they require Flutter 3.44 or newer, where Swift Package Manager is enabled by default.

If Swift Package Manager is disabled, your build stops with:

The following plugin(s) are only compatible with Swift Package Manager:
  - is_tv_ffi

To fix it, re-enable Swift Package Manager:

flutter config --enable-swift-package-manager

Make sure it is not disabled per-project either — check for this in your app's pubspec.yaml and remove it if present:

flutter:
  config:
    enable-swift-package-manager: false

Desktop Usage #

For Linux and Windows, the plugin determines if it's a TV environment by checking for specific environment variables. This allows you to force "TV Mode" for your application when running on a media center PC, or for testing.

Forcing TV Mode #

Before running your app, set the following environment variable:

  • Variable: FLUTTER_IS_TV
  • Value: 1, true, yes or on (matched case-insensitively)

Linux / macOS Terminal

FLUTTER_IS_TV=1 flutter run

Windows PowerShell

$env:FLUTTER_IS_TV="1"
flutter run -d windows

Windows Command Prompt

set FLUTTER_IS_TV=1
flutter run -d windows

On Linux the plugin additionally recognises Steam Big Picture and SteamOS gaming sessions. Windows has no such heuristic: FLUTTER_IS_TV is the only signal it uses.

Implementation Details #

Android #

Uses UiModeManager to check if the current OS is Android TV, falling back to the leanback system feature for TV boxes that report a non-television UI mode.

fun isTv(context: Context): Boolean {
  val uiModeManager = context.getSystemService(Context.UI_MODE_SERVICE) as? UiModeManager
  if (uiModeManager?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION) {
    return true
  }

  return context.packageManager?.hasSystemFeature(PackageManager.FEATURE_LEANBACK) == true
}

iOS / tvOS #

Uses UIDevice to check if the current device's user interface idiom is .tv.

public func isTV() -> Bool {
  return device.userInterfaceIdiom == .tv
}

macOS #

Always returns false. macOS never reports a TV user interface idiom; the native symbol exists so that the FFI surface stays uniform across Apple platforms.

public func isTV() -> Bool {
    return false
}

Linux #

Checks the FLUTTER_IS_TV environment variable, then the variables that indicate a Steam Big Picture or SteamOS gaming session. Which of those is set depends on the distribution and compositor, so several are checked.

bool is_tv() {
  return IsTruthy(std::getenv("FLUTTER_IS_TV")) || IsSteamBigPictureSession();
}

bool IsSteamBigPictureSession() {
  const char* session_desktop = std::getenv("XDG_SESSION_DESKTOP");
  const char* current_desktop = std::getenv("XDG_CURRENT_DESKTOP");

  return EqualsIgnoreCase(session_desktop, "steam") ||
         EqualsIgnoreCase(session_desktop, "steamos") ||
         EqualsIgnoreCase(current_desktop, "gamescope") ||
         IsTruthy(std::getenv("SteamDeck"));
}

Windows #

Checks the FLUTTER_IS_TV environment variable.

bool is_tv() {
  char* env_value = nullptr;
  size_t len = 0;

  if (_dupenv_s(&env_value, &len, "FLUTTER_IS_TV") != 0) {
    return false;
  }

  const bool result = IsTruthy(env_value);
  free(env_value);

  return result;
}

Web #

Checks for the JavaScript globals that smart-TV runtimes inject (tizen, webOS, webOSSystem) — these are harder to spoof than a user agent — then falls back to matching the user agent against a list of TV keywords and patterns.

bool isTv() =>
    _hasTvPlatformGlobal() || matchesTvUserAgent(window.navigator.userAgent);

static bool matchesTvUserAgent(String userAgent) {
  final normalized = userAgent.toLowerCase();

  return _tvPatterns.any((pattern) => pattern.hasMatch(normalized)) ||
      _tvKeywords.any(normalized.contains);
}

The keyword list covers webOS, Tizen, Google TV, Chromecast, Fire TV, Apple TV, Bravia, VIDAA, Roku, HbbTV, NetCast, Net TV, CE-HTML and Opera TV. Patterns are used where a bare substring would misfire — Fire TV model codes (AFTB, AFTMM) are matched as whole words so that ordinary user agents containing "aft" are not treated as TVs.

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This project is licensed under the MIT License.

0
likes
160
points
22
downloads

Documentation

API reference

Publisher

verified publishermathiewabbas.dev

Weekly Downloads

Detects whether a Flutter app is running on a TV: Android TV, tvOS, webOS, Tizen and TV-mode Linux and Windows, using FFI and JNI rather than platform channels.

Repository (GitHub)
View/report issues

Topics

#tv #ffi #android-tv #tvos #smart-tv

License

MIT (license)

Dependencies

flutter, flutter_web_plugins, jni, jni_flutter, web

More

Packages that depend on is_tv_ffi

Packages that implement is_tv_ffi