This guide covers how to create a Flutter plugin that exposes native tvOS functionality to Dart code.
flutter-tvos create --template=plugin my_tvos_plugin
cd my_tvos_pluginThe generated package contains:
my_tvos_plugin/
├── lib/
│ └── my_tvos_plugin.dart # Dart API
├── tvos/
│ ├── Classes/
│ │ └── MyTvosPlugin.swift # Swift implementation
│ └── my_tvos_plugin.podspec # CocoaPods spec
├── example/ # Example app
└── pubspec.yaml
The pubspec.yaml declares the tvOS platform:
flutter:
plugin:
platforms:
tvos:
pluginClass: MyTvosPluginOpen lib/my_tvos_plugin.dart and define your public API:
class MyTvosPlugin {
static const MethodChannel _channel = MethodChannel('my_tvos_plugin');
static Future<String?> getPlatformVersion() async {
return await _channel.invokeMethod<String>('getPlatformVersion');
}
}Open tvos/Classes/MyTvosPlugin.swift:
import Flutter
public class MyTvosPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(
name: "my_tvos_plugin",
binaryMessenger: registrar.messenger()
)
let instance = MyTvosPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getPlatformVersion":
result("tvOS \(UIDevice.current.systemVersion)")
default:
result(FlutterMethodNotImplemented)
}
}
}The generated tvos/my_tvos_plugin.podspec targets tvOS 13.0. One important rule — do not use s.dependency 'Flutter' because the Flutter pod does not declare tvOS support. Use FRAMEWORK_SEARCH_PATHS instead:
Pod::Spec.new do |s|
s.name = 'my_tvos_plugin'
s.version = '0.0.1'
s.summary = 'A Flutter plugin for tvOS.'
s.homepage = 'https://fluttertv.dev'
s.license = { :type => 'BSD-3-Clause' }
s.author = { 'FlutterTV' => 'info@fluttertv.dev' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.platform = :tvos, '13.0'
# Use FRAMEWORK_SEARCH_PATHS instead of s.dependency 'Flutter'
s.xcconfig = {
'FRAMEWORK_SEARCH_PATHS' => '"${PODS_ROOT}/../Flutter"'
}
endtvOS is more restricted than iOS. Keep these in mind when writing plugins:
| Feature | iOS | tvOS |
|---|---|---|
| WebKit / WKWebView | ✅ | ❌ Not available |
| Clipboard (UIPasteboard) | ✅ | ❌ Not available |
| Haptics (UIFeedbackGenerator) | ✅ | ❌ Not available |
| Status bar | ✅ | ❌ Not available |
| Camera / microphone | ✅ | ❌ Not available |
| Touch input | UITouch | ❌ Use UIPress (Siri Remote) |
| Game controllers | Optional | ✅ GameController.framework |
| Media playback | AVFoundation | ✅ AVFoundation |
Use #if os(tvOS) guards for any tvOS-specific Swift code:
#if os(tvOS)
// tvOS-specific implementation
#else
result(FlutterError(code: "UNSUPPORTED", message: "Not supported on this platform", details: nil))
#endifFor plugins that wrap a native C library, set ffiPlugin: true in pubspec.yaml:
flutter:
plugin:
platforms:
tvos:
ffiPlugin: trueFFI plugins are distributed as CocoaPods and loaded via DynamicLibrary.process() — they are not added to the plugin registrant.
cd example
flutter-tvos devices
flutter-tvos run -d <simulator_id>dart pub publish --dry-run
dart pub publishSee Flutter Docs: Publishing packages for details.