Flutter Tizen平台交互插件tizen_api的使用

发布于 1周前 作者 yibo5220 来自 Flutter

Flutter Tizen平台交互插件tizen_api的使用

Tizen

TV Remote for all mobile devices

如何使用

搜索设备

Future<void> searchDevices() async {
  final String? ip = await NetworkInfo().getWifiIP();
  if (ip == null) {
    return;
  }

  TizenHelperMethods.scanNetwork(ip).listen((tv) {
    print('Found TV $tv');
  });
}

设置选中的电视

TizenHelperMethods.selectedTv = tvVar;

控制电视

TizenHelperMethods.selectedTv!.addToSocket(KeyCodes.KEY_VOLDOWN);
TizenHelperMethods.selectedTv!.addToSocket(KeyCodes.KEY_VOLUP);
TizenHelperMethods.selectedTv!.addToSocket(KeyCodes.KEY_POWER);

测试示例应用

示例是一个智能电视遥控器应用,非常有趣且值得一试。

你可以尝试用你的电视测试一下。

感谢

感谢 @shaharhn 为这个包开发了基础功能。


完整示例Demo

以下是完整的示例代码:

import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:network_info_plus/network_info_plus.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tizen/logger.dart';
import 'package:tizen_api/tizen_api.dart';
import 'package:wakelock_plus/wakelock_plus.dart';

late final SharedPreferences preferences;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  preferences = await SharedPreferences.getInstance();

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  [@override](/user/override)
  Widget build(BuildContext context) => MaterialApp(
        title: 'Smart TV Controller',
        theme: ThemeData(primarySwatch: Colors.purple),
        darkTheme: ThemeData(
          brightness: Brightness.dark,
          primarySwatch: Colors.purple,
          dividerColor: Colors.purple,
        ),
        home: const MyHomePage(),
      );
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  [@override](/user/override)
  MyHomePageState createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  Tv? _connectedTv;
  List<Tv> tvs = [];
  Offset? _dragDelta;
  String? _token;
  bool isLoading = true;

  bool get connectedToTv =>
      _connectedTv != null && _connectedTv == TizenHelperMethods.selectedTv;

  String? get token => _token ??= preferences.getString('token');

  set token(String? token) {
    _token = token;
    if (token == null) {
      preferences.remove('token');
    } else {
      preferences.setString('token', token);
    }
  }

  [@override](/user/override)
  void initState() {
    super.initState();
    WakelockPlus.enable();
    searchDevices();
  }

  Future<void> searchDevices() async {
    final String? ip = await NetworkInfo().getWifiIP();
    if (ip == null) {
      return;
    }

    TizenHelperMethods.scanNetwork(ip).listen((tv) {
      setState(() {
        tvs.add(tv);
      });
    }).onDone(() {
      setState(() {
        isLoading = false;
      });
    });
  }

  void _pressKey(KeyCodes key) {
    if (TizenHelperMethods.selectedTv == null) {
      return;
    }
    Logger.log('Sending key: $key');
    HapticFeedback.mediumImpact();
    TizenHelperMethods.selectedTv!.addToSocket(key);
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: DropdownButton<String>(
          hint: const Text('Select TV'),
          value: TizenHelperMethods.selectedTv?.name,
          onChanged: (String? tv) {
            final Tv selectedTvTemp =
                tvs.firstWhere((element) => element.name == tv);
            setState(() {
              TizenHelperMethods.selectedTv = selectedTvTemp;
            });
            setupStream();
          },
          items: tvs
              .map<DropdownMenuItem<String>>(
                (Tv tv) => DropdownMenuItem<String>(
                  value: tv.name,
                  child: Text(tv.name, style: const TextStyle(fontSize: 30)),
                ),
              )
              .toList(),
        ),
        actions: connectedToTv
            ? [
                IconButton(
                  icon: const Icon(Icons.power_settings_new),
                  onPressed: () => _pressKey(KeyCodes.keyPower),
                ),
              ]
            : null,
      ),
      body: connectedToTv
          ? buildConnectedTvUi
          : Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  if (tvs.isNotEmpty)
                    Text(
                      _connectedTv != TizenHelperMethods.selectedTv
                          ? 'Waiting for TV to connect'
                          : 'Select a TV',
                    ),
                  const SizedBox(height: 20),
                  if (isLoading)
                    const CircularProgressIndicator()
                  else if (tvs.isEmpty) ...[
                    const Text('Could not find any TV, you retry'),
                    IconButton(
                      icon: const Icon(Icons.refresh),
                      onPressed: searchDevices,
                    ),
                  ],
                ],
              ),
            ),
    );
  }

  Widget get buildConnectedTvUi => Column(
        children: [
          buildTopRow,
          const Divider(),
          buildGestureControl,
          const Divider(),
          buildBottomRow,
        ],
      );

  Widget get buildTopRow => Row(
        children: [
          Expanded(
            child: DropdownButton<String>(
              hint: const Text('Select Application'),
              onChanged: (String? application) {
                if (TizenHelperMethods.selectedTv == null) return;
                HapticFeedback.lightImpact();
                TizenHelperMethods.selectedTv!
                    .forwardToApplication(application!);
              },
              items: Tv.applications.keys
                  .map<DropdownMenuItem<String>>(
                    (String value) => DropdownMenuItem<String>(
                      value: value,
                      child: Text(
                        value,
                        style: const TextStyle(fontSize: 30),
                      ),
                    ),
                  )
                  .toList(),
            ),
          ),
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 10),
            child: InkWell(
              child: const Text('HDMI', textAlign: TextAlign.center),
              onTap: () => _pressKey(KeyCodes.keyHdmi),
            ),
          ),
        ],
      );

  Widget get buildGestureControl => Expanded(
        child: Row(
          children: [
            buildVolumeControl,
            const VerticalDivider(),
            buildNavigationControl,
          ],
        ),
      );

  Widget get buildVolumeControl => Expanded(
        child: GestureDetector(
          onVerticalDragStart: (_) => _dragDelta = Offset.zero,
          onVerticalDragUpdate: (d) => handleVolumeGesture(d),
          onVerticalDragEnd: (_) => _dragDelta = null,
          onVerticalDragCancel: () => _dragDelta = null,
          onTap: () => _pressKey(KeyCodes.keyMute),
        ),
      );

  void handleVolumeGesture(DragUpdateDetails d) {
    _dragDelta = _dragDelta! + d.delta;
    const threshold = 30.0;
    if (_dragDelta!.distance > threshold) {
      final dir = (_dragDelta!.direction / pi * 2 + 0.5).floor();
      switch (dir) {
        case -1:
          _pressKey(KeyCodes.keyVolUp);
          _dragDelta = _dragDelta!.translate(0, threshold);
        case 1:
          _pressKey(KeyCodes.keyVolDown);
          _dragDelta = _dragDelta!.translate(0, -threshold);
      }
    }
  }

  Widget get buildNavigationControl => Expanded(
        flex: 3,
        child: GestureDetector(
          onPanStart: (_) => _dragDelta = Offset.zero,
          onPanUpdate: (d) => handleNavigationGesture(d),
          onPanEnd: (_) => _dragDelta = null,
          onPanCancel: () => _dragDelta = null,
          onTap: () => _pressKey(KeyCodes.keyEnter),
        ),
      );

  void handleNavigationGesture(DragUpdateDetails d) {
    _dragDelta = _dragDelta! + d.delta;
    const threshold = 60.0;
    if (_dragDelta!.distance > threshold) {
      final dir = (_dragDelta!.direction / pi * 2 + 0.5).floor();
      switch (dir) {
        case 2:
        case -2:
          _pressKey(KeyCodes.keyLeft);
          _dragDelta = _dragDelta!.translate(threshold, -_dragDelta!.dy);
        case -1:
          _pressKey(KeyCodes.keyUp);
          _dragDelta = _dragDelta!.translate(-_dragDelta!.dx, threshold);
        case 0:
          _pressKey(KeyCodes.keyRight);
          _dragDelta = _dragDelta!.translate(-threshold, -_dragDelta!.dy);
        case 1:
          _pressKey(KeyCodes.keyDown);
          _dragDelta = _dragDelta!.translate(-_dragDelta!.dx, -threshold);
      }
    }
  }

  Widget get buildBottomRow => SizedBox(
        height: 120,
        child: Row(
          children: [
            Expanded(
              child: InkWell(
                child: const Center(child: Icon(Icons.arrow_back)),
                onTap: () => _pressKey(KeyCodes.keyReturn),
              ),
            ),
            Expanded(
              child: InkWell(
                child: const Center(child: Icon(Icons.home_outlined)),
                onTap: () => _pressKey(KeyCodes.keyHome),
              ),
            ),
            Expanded(
              child: InkWell(
                child: const Center(child: Icon(Icons.pause)),
                onTap: () => _pressKey(KeyCodes.keyEnter),
              ),
            ),
          ],
        ),
      );

  void setupStream() {
    TizenHelperMethods.setupStream(token).listen((String? onData) {
      if (TizenHelperMethods.selectedTv != _connectedTv) {
        setState(() {
          _connectedTv = TizenHelperMethods.selectedTv;
        });
        token = onData;
      }
    });
  }
}

更多关于Flutter Tizen平台交互插件tizen_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter Tizen平台交互插件tizen_api的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中开发针对Tizen平台的应用时,tizen_api插件提供了一种与Tizen原生功能进行交互的方式。下面是一个使用tizen_api插件的简单示例,展示了如何在Flutter应用中调用Tizen的系统通知功能。

首先,确保你已经在pubspec.yaml文件中添加了tizen_api依赖:

dependencies:
  flutter:
    sdk: flutter
  tizen_api: ^x.y.z  # 请替换为最新版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Flutter项目中,你可以使用以下代码来调用Tizen的系统通知API:

import 'package:flutter/material.dart';
import 'package:tizen_api/tizen_api.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Tizen API Demo'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: _showNotification,
            child: Text('Show Notification'),
          ),
        ),
      ),
    );
  }

  void _showNotification() async {
    // 检查平台是否为Tizen
    if (TizenPlatform.isTizen) {
      try {
        // 初始化Tizen API
        final tizenApi = TizenApi();

        // 创建一个简单的通知
        final notification = tizenApi.notification.createSimple(
          title: 'Hello, Tizen!',
          content: 'This is a notification from Flutter!',
          appId: 'com.example.flutter_tizen_app',  // 替换为你的应用ID
        );

        // 发布通知
        await tizenApi.notification.post(notification);
      } catch (e) {
        print('Failed to post notification: $e');
      }
    } else {
      print('This platform is not Tizen.');
    }
  }
}

在这个示例中,我们首先检查当前平台是否为Tizen。如果是,我们初始化TizenApi实例,并创建一个简单的通知。然后,我们使用post方法将通知发布到系统通知栏。

注意

  1. 在实际开发中,你需要确保你的应用ID与Tizen Store中注册的应用ID一致,否则通知可能无法正确显示。
  2. tizen_api插件提供的API可能因版本而异,因此请参考官方文档以获取最新的API信息和用法示例。
  3. 在部署到Tizen设备之前,请确保你的开发环境已经正确配置,包括Tizen SDK和Flutter Tizen工具链。

这个示例展示了如何在Flutter应用中调用Tizen的原生通知功能。根据你的需求,你可以探索tizen_api插件提供的更多功能,如文件系统访问、硬件控制等。

回到顶部