Suche senden
Hochladen
Cast SDK for Flutter
•
3 gefällt mir
•
1,548 views
K
KojiYamada22
Folgen
Cast SDK for Flutter Meetup Slide
Weniger lesen
Mehr lesen
Ingenieurwesen
Melden
Teilen
Melden
Teilen
1 von 31
Jetzt herunterladen
Downloaden Sie, um offline zu lesen
Empfohlen
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
NTT DATA Technology & Innovation
Istioサービスメッシュ入門
Istioサービスメッシュ入門
Yoichi Kawasaki
Docker Compose 徹底解説
Docker Compose 徹底解説
Masahito Zembutsu
ジョブ管理でcronは限界があったので”Rundeck”を使ってハッピーになりました
ジョブ管理でcronは限界があったので”Rundeck”を使ってハッピーになりました
Yukiya Hayashi
Serf / Consul 入門 ~仕事を楽しくしよう~
Serf / Consul 入門 ~仕事を楽しくしよう~
Masahito Zembutsu
DockerコンテナでGitを使う
DockerコンテナでGitを使う
Kazuhiro Suga
FIDO2導入してみたを考えてみた
FIDO2導入してみたを考えてみた
FIDO Alliance
Android向けUnity製ゲーム最適化のためのCI/CDと連携した自動プロファイリングシステム
Android向けUnity製ゲーム最適化のためのCI/CDと連携した自動プロファイリングシステム
KLab Inc. / Tech
Empfohlen
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
Grafana LokiではじめるKubernetesロギングハンズオン(NTT Tech Conference #4 ハンズオン資料)
NTT DATA Technology & Innovation
Istioサービスメッシュ入門
Istioサービスメッシュ入門
Yoichi Kawasaki
Docker Compose 徹底解説
Docker Compose 徹底解説
Masahito Zembutsu
ジョブ管理でcronは限界があったので”Rundeck”を使ってハッピーになりました
ジョブ管理でcronは限界があったので”Rundeck”を使ってハッピーになりました
Yukiya Hayashi
Serf / Consul 入門 ~仕事を楽しくしよう~
Serf / Consul 入門 ~仕事を楽しくしよう~
Masahito Zembutsu
DockerコンテナでGitを使う
DockerコンテナでGitを使う
Kazuhiro Suga
FIDO2導入してみたを考えてみた
FIDO2導入してみたを考えてみた
FIDO Alliance
Android向けUnity製ゲーム最適化のためのCI/CDと連携した自動プロファイリングシステム
Android向けUnity製ゲーム最適化のためのCI/CDと連携した自動プロファイリングシステム
KLab Inc. / Tech
セキュアエレメントとIotデバイスセキュリティ2
セキュアエレメントとIotデバイスセキュリティ2
Kentaro Mitsuyasu
Anthos を使ったエンタープライズ向けクラスタの設計とアップグレード戦略のススメ(CloudNative Days Tokyo 2021 発表資料)
Anthos を使ったエンタープライズ向けクラスタの設計とアップグレード戦略のススメ(CloudNative Days Tokyo 2021 発表資料)
NTT DATA Technology & Innovation
Yahoo!ニュースにおけるBFFパフォーマンスチューニング事例
Yahoo!ニュースにおけるBFFパフォーマンスチューニング事例
Yahoo!デベロッパーネットワーク
Usb接続するアプリを開発した時に試行錯誤した事
Usb接続するアプリを開発した時に試行錯誤した事
Masataka Kono
Try new transport protocol SRT (ver. 2)
Try new transport protocol SRT (ver. 2)
Tetsuyuki Kobayashi
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
sairoutine
Keycloak入門-OpenID ConnectによるAPIセキュリティ
Keycloak入門-OpenID ConnectによるAPIセキュリティ
Yuichi Nakamura
マイクロサービスバックエンドAPIのためのRESTとgRPC
マイクロサービスバックエンドAPIのためのRESTとgRPC
disc99_
○ヶ月でできた!?さくらのクラウド開発秘話(【ヒカ☆ラボ】さくらインターネットとMilkcocoa!年末イベント:ここだけのウラ話)
○ヶ月でできた!?さくらのクラウド開発秘話(【ヒカ☆ラボ】さくらインターネットとMilkcocoa!年末イベント:ここだけのウラ話)
さくらインターネット株式会社
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
Daisuke Morishita
アプリの鍵が消える時_Droid kaigi2018
アプリの鍵が消える時_Droid kaigi2018
ak_shio_555
Node RED で実現する製造業の DX
Node RED で実現する製造業の DX
雅治 新澤
KeycloakでAPI認可に入門する
KeycloakでAPI認可に入門する
Hitachi, Ltd. OSS Solution Center.
大規模環境のOpenStackアップグレードの考え方と実施のコツ
大規模環境のOpenStackアップグレードの考え方と実施のコツ
Tomoya Hashimoto
Microsoft Partner Network ガイドライン
Microsoft Partner Network ガイドライン
Hiroyasu Sato
TLS, HTTP/2演習
TLS, HTTP/2演習
shigeki_ohtsu
WebRTCのオーディオ処理の謎、誰か教えて!
WebRTCのオーディオ処理の謎、誰か教えて!
mganeko
AlmaLinux と Rocky Linux の誕生経緯&比較
AlmaLinux と Rocky Linux の誕生経緯&比較
beyond Co., Ltd.
実践!OpenTelemetry と OSS を使った Observability 基盤の構築(CloudNative Days Tokyo 2022 発...
実践!OpenTelemetry と OSS を使った Observability 基盤の構築(CloudNative Days Tokyo 2022 発...
NTT DATA Technology & Innovation
MQTTとAMQPと.NET
MQTTとAMQPと.NET
terurou
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
Jumpei Ogawa
Pf部2012年1月勉強会.androidsola
Pf部2012年1月勉強会.androidsola
android sola
Weitere ähnliche Inhalte
Was ist angesagt?
セキュアエレメントとIotデバイスセキュリティ2
セキュアエレメントとIotデバイスセキュリティ2
Kentaro Mitsuyasu
Anthos を使ったエンタープライズ向けクラスタの設計とアップグレード戦略のススメ(CloudNative Days Tokyo 2021 発表資料)
Anthos を使ったエンタープライズ向けクラスタの設計とアップグレード戦略のススメ(CloudNative Days Tokyo 2021 発表資料)
NTT DATA Technology & Innovation
Yahoo!ニュースにおけるBFFパフォーマンスチューニング事例
Yahoo!ニュースにおけるBFFパフォーマンスチューニング事例
Yahoo!デベロッパーネットワーク
Usb接続するアプリを開発した時に試行錯誤した事
Usb接続するアプリを開発した時に試行錯誤した事
Masataka Kono
Try new transport protocol SRT (ver. 2)
Try new transport protocol SRT (ver. 2)
Tetsuyuki Kobayashi
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
sairoutine
Keycloak入門-OpenID ConnectによるAPIセキュリティ
Keycloak入門-OpenID ConnectによるAPIセキュリティ
Yuichi Nakamura
マイクロサービスバックエンドAPIのためのRESTとgRPC
マイクロサービスバックエンドAPIのためのRESTとgRPC
disc99_
○ヶ月でできた!?さくらのクラウド開発秘話(【ヒカ☆ラボ】さくらインターネットとMilkcocoa!年末イベント:ここだけのウラ話)
○ヶ月でできた!?さくらのクラウド開発秘話(【ヒカ☆ラボ】さくらインターネットとMilkcocoa!年末イベント:ここだけのウラ話)
さくらインターネット株式会社
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
Daisuke Morishita
アプリの鍵が消える時_Droid kaigi2018
アプリの鍵が消える時_Droid kaigi2018
ak_shio_555
Node RED で実現する製造業の DX
Node RED で実現する製造業の DX
雅治 新澤
KeycloakでAPI認可に入門する
KeycloakでAPI認可に入門する
Hitachi, Ltd. OSS Solution Center.
大規模環境のOpenStackアップグレードの考え方と実施のコツ
大規模環境のOpenStackアップグレードの考え方と実施のコツ
Tomoya Hashimoto
Microsoft Partner Network ガイドライン
Microsoft Partner Network ガイドライン
Hiroyasu Sato
TLS, HTTP/2演習
TLS, HTTP/2演習
shigeki_ohtsu
WebRTCのオーディオ処理の謎、誰か教えて!
WebRTCのオーディオ処理の謎、誰か教えて!
mganeko
AlmaLinux と Rocky Linux の誕生経緯&比較
AlmaLinux と Rocky Linux の誕生経緯&比較
beyond Co., Ltd.
実践!OpenTelemetry と OSS を使った Observability 基盤の構築(CloudNative Days Tokyo 2022 発...
実践!OpenTelemetry と OSS を使った Observability 基盤の構築(CloudNative Days Tokyo 2022 発...
NTT DATA Technology & Innovation
MQTTとAMQPと.NET
MQTTとAMQPと.NET
terurou
Was ist angesagt?
(20)
セキュアエレメントとIotデバイスセキュリティ2
セキュアエレメントとIotデバイスセキュリティ2
Anthos を使ったエンタープライズ向けクラスタの設計とアップグレード戦略のススメ(CloudNative Days Tokyo 2021 発表資料)
Anthos を使ったエンタープライズ向けクラスタの設計とアップグレード戦略のススメ(CloudNative Days Tokyo 2021 発表資料)
Yahoo!ニュースにおけるBFFパフォーマンスチューニング事例
Yahoo!ニュースにおけるBFFパフォーマンスチューニング事例
Usb接続するアプリを開発した時に試行錯誤した事
Usb接続するアプリを開発した時に試行錯誤した事
Try new transport protocol SRT (ver. 2)
Try new transport protocol SRT (ver. 2)
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
Keycloak入門-OpenID ConnectによるAPIセキュリティ
Keycloak入門-OpenID ConnectによるAPIセキュリティ
マイクロサービスバックエンドAPIのためのRESTとgRPC
マイクロサービスバックエンドAPIのためのRESTとgRPC
○ヶ月でできた!?さくらのクラウド開発秘話(【ヒカ☆ラボ】さくらインターネットとMilkcocoa!年末イベント:ここだけのウラ話)
○ヶ月でできた!?さくらのクラウド開発秘話(【ヒカ☆ラボ】さくらインターネットとMilkcocoa!年末イベント:ここだけのウラ話)
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
エンジニアのためのOSSライセンス管理~OSS管理ツールの池の水全部抜く~
アプリの鍵が消える時_Droid kaigi2018
アプリの鍵が消える時_Droid kaigi2018
Node RED で実現する製造業の DX
Node RED で実現する製造業の DX
KeycloakでAPI認可に入門する
KeycloakでAPI認可に入門する
大規模環境のOpenStackアップグレードの考え方と実施のコツ
大規模環境のOpenStackアップグレードの考え方と実施のコツ
Microsoft Partner Network ガイドライン
Microsoft Partner Network ガイドライン
TLS, HTTP/2演習
TLS, HTTP/2演習
WebRTCのオーディオ処理の謎、誰か教えて!
WebRTCのオーディオ処理の謎、誰か教えて!
AlmaLinux と Rocky Linux の誕生経緯&比較
AlmaLinux と Rocky Linux の誕生経緯&比較
実践!OpenTelemetry と OSS を使った Observability 基盤の構築(CloudNative Days Tokyo 2022 発...
実践!OpenTelemetry と OSS を使った Observability 基盤の構築(CloudNative Days Tokyo 2022 発...
MQTTとAMQPと.NET
MQTTとAMQPと.NET
Ähnlich wie Cast SDK for Flutter
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
Jumpei Ogawa
Pf部2012年1月勉強会.androidsola
Pf部2012年1月勉強会.androidsola
android sola
Titanium Mobile
Titanium Mobile
Naoya Ito
Windows azure mobile services による mobile + cloud アプリケーション超高速開発
Windows azure mobile services による mobile + cloud アプリケーション超高速開発
Shotaro Suzuki
Azure IoT Edge で Custom Vision
Azure IoT Edge で Custom Vision
Yoshitaka Seo
Redmineosaka 20 talk_crosspoints
Redmineosaka 20 talk_crosspoints
Shinji Tamura
WebRTCを始めよう! HTML5fun 第一回勉強会
WebRTCを始めよう! HTML5fun 第一回勉強会
Yusuke Naka
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用
de:code 2017
Android bluetooth
Android bluetooth
Masahiro Hidaka
"Up" with vagrant and docker
"Up" with vagrant and docker
Hiroshi Miura
UnityとnodeとMMDと
UnityとnodeとMMDと
sters
FlutterをRenderObjectまで理解する
FlutterをRenderObjectまで理解する
KeisukeKiriyama
VRのマルチプラットフォーム開発について
VRのマルチプラットフォーム開発について
yashinut
"Up" with vagrant and docker
"Up" with vagrant and docker
Hiroshi Miura
MRTK-Unreal(UX Tools) を利用した HoloLens 2 アプリ開発 | UNREAL FEST EXTREME 2020 WINTER
MRTK-Unreal(UX Tools) を利用した HoloLens 2 アプリ開発 | UNREAL FEST EXTREME 2020 WINTER
エピック・ゲームズ・ジャパン Epic Games Japan
.NET Gadgeteer のハンズオン資料 (2014年3月版)
.NET Gadgeteer のハンズオン資料 (2014年3月版)
Yoshitaka Seo
Unreal Engine でアプリ開発~ MRTK UXTools for Unreal V0.9.0 ~
Unreal Engine でアプリ開発~ MRTK UXTools for Unreal V0.9.0 ~
Takahiro Miyaura
Let's begin WebRTC
Let's begin WebRTC
yoshikawa_t
Grafana Dashboards as Code
Grafana Dashboards as Code
Takuhiro Yoshida
20120118 titanium
20120118 titanium
Hiroshi Oyamada
Ähnlich wie Cast SDK for Flutter
(20)
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
QML を用いた YouTube クライアントの作成 - 関東 Qt 勉強会
Pf部2012年1月勉強会.androidsola
Pf部2012年1月勉強会.androidsola
Titanium Mobile
Titanium Mobile
Windows azure mobile services による mobile + cloud アプリケーション超高速開発
Windows azure mobile services による mobile + cloud アプリケーション超高速開発
Azure IoT Edge で Custom Vision
Azure IoT Edge で Custom Vision
Redmineosaka 20 talk_crosspoints
Redmineosaka 20 talk_crosspoints
WebRTCを始めよう! HTML5fun 第一回勉強会
WebRTCを始めよう! HTML5fun 第一回勉強会
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用
[AI08] 深層学習フレームワーク Chainer × Microsoft で広がる応用
Android bluetooth
Android bluetooth
"Up" with vagrant and docker
"Up" with vagrant and docker
UnityとnodeとMMDと
UnityとnodeとMMDと
FlutterをRenderObjectまで理解する
FlutterをRenderObjectまで理解する
VRのマルチプラットフォーム開発について
VRのマルチプラットフォーム開発について
"Up" with vagrant and docker
"Up" with vagrant and docker
MRTK-Unreal(UX Tools) を利用した HoloLens 2 アプリ開発 | UNREAL FEST EXTREME 2020 WINTER
MRTK-Unreal(UX Tools) を利用した HoloLens 2 アプリ開発 | UNREAL FEST EXTREME 2020 WINTER
.NET Gadgeteer のハンズオン資料 (2014年3月版)
.NET Gadgeteer のハンズオン資料 (2014年3月版)
Unreal Engine でアプリ開発~ MRTK UXTools for Unreal V0.9.0 ~
Unreal Engine でアプリ開発~ MRTK UXTools for Unreal V0.9.0 ~
Let's begin WebRTC
Let's begin WebRTC
Grafana Dashboards as Code
Grafana Dashboards as Code
20120118 titanium
20120118 titanium
Cast SDK for Flutter
1.
Cast SDK for
Flutter
2.
山田 幸司 koji.yamada@gree.net グリー株式会社 開発本部 /
インフラストラクチャ部 / ディベロップメント オペレーションズグループ / サービスディベロップメント チーム 所属 業務内容 VRアプリフロントエンド担当 最近のお仕事はFlutter / Unity / Unreal Engine 4など
3.
アジェンダ ● Chromecastについて ○ Chromecastとは? ○
Cast SDKについて ● Cast SDK for Flutterを作る ○ Flutterでプラグインを作る準備やインストール方法など ○ 構成から実装のおおまかな流れ ○ 実装方法などについて
4.
Chromecast ● Googleが開発・販売する小型のデバイス ● HDMI端子に接続/Wi-Fiを介してスマートフォンやタブレットなどで再生して いる動画、写真、ウェブサイトなどをディスプレイに表示出来るデバイス ●
ミラーリングとはやや違ってスマートフォンをコントローラとして扱い動画 の再生や停止などもできる ● 値段は5,000円程度(4K対応のUltraは10,000円程度) ● アプリで利用するにはCast SDKを組み込む必要がある ※↑アプリが対応しているかつ周辺にChromecast がある場合はこのアイコンが表示される
5.
Cast SDK ● Googleが提供するChromecast用のSDK ○
https://developers.google.com/cast/ ● Android/iOS/Chrome(ブラウザ)に対応 ○ Android → Java/Kotlin ○ iOS → Objective-C/Swift ○ Chrome → Javascript ● 公式のFlutter用Cast SDKはまだ存在しない ● Flutter版もいつか対応するかも ○ GitHubのissuesはあがっている ○ https://github.com/flutter/flutter/issues/18212
6.
Cast SDK for
Flutter ● 今日の話 ○ Flutter用のChromecast Pluginを作る話 ○ ChromecastのAndroid/iOS両方に対応するアプリをさく っと作れる ● 実装するもの ○ 送信側(Sender)と受信側(Receiver)を作る必要があ りますが、今回はSenderアプリのみについて ○ 動画コントロールパネルやキャストボタンなどのUI部分 はFlutterで実装 ○ 動画をChromecastにキャスト/再生と停止ができる
7.
準備 ● Plugin Packageプロジェクトの作成 ○
$ flutter create --template=plugin -i swift -a kotlin [プロジェクト名] 例) chrome_cast_plugin Android/build.gradle … dependencies { implementation 'com.google.android.gms:play-services-cast-framework:16.1.2' ... iOS/Podfile … target 'Runner' do pod 'google-cast-sdk', '~> 4.3' ... Sync Now pod install
8.
構成 app main.dart lib chrome_cast_ plugin.dart Flutter/Dart Android/Kotlin iOS/Swift CastOptionsProvider.kt ChromeCastPlugin.kt SwiftChromeCast Plugin.swift Cast SDK for
Android gms:play-services-cast Cast SDK for iOS google-cast-sdk ● main.dart ○ キャストボタンなどのUI表示 ● chrome_cast_plugin.dart ○ Kotlin/Swiftとのつなぎ プラグイン側
9.
Pluginで実装すること 1. Cast Contextの初期化 2.
Cast Dialogの表示 3. Cast Buttonの表示 4. リスナーの登録 5. 動画をキャストする 6. キャストした動画を制御する
10.
Cast Contextの初期化 ● Chromecast
の機能を使うために必要 ● Android ○ OptionsProviderインタフェースを実装したクラスの作成 ○ レシーバーIdのCastOptionsのインスタンスを作る ○ CastContext.getSharedInstance(Activity)で初期化 ● iOS ○ レシーバーIdのGCKCastOptionのインスタンスを作る ○ GCKCastContext.setSharedInstanceWith(GCKCastOption)で初期化 ● 初期化タイミング ○ pluginのregisterWith / register
11.
class ChromeCastPlugin(private val
pActivity: Activity, private val pChannel: MethodChannel): … companion object { @JvmStatic fun registerWith(registrar: Registrar) { CastContext.getSharedInstance(pActivity) … Android/Kotlin static const MethodChannel _channel = const MethodChannel('chrome_cast_plugin'); chrome_cast_plugin.dart public class SwiftChromeCastPlugin: NSObject, FlutterPlugin { … public static func register(with registrar: FlutterPluginRegistrar) { let tCriteria = GCKDiscoveryCriteria(applicationID: [レシーバーのId]) let tOption = GCKCastOptions(discoveryCriteria: tCriteria) GCKCastContext.setSharedInstanceWith(tOption) … iOS/Swift
12.
class CastOptionsProvider :
OptionsProvider { … override fun getCastOptions(context: Context): CastOptions? { val tAppId = context.resources.getIdentifier("chromecast_app_id", "string", context.packageName) … return CastOptions.Builder() .setReceiverApplicationId(context.getString(tAppId)) .build() } … } Android/Kotlin Cast Contextの初期化(Android CastOptionsProvider.kt) <?xml version="1.0" encoding="utf-8"?> <resources> <string name="chromecast_app_id">[レシーバーId]</string> </resources> app/res/values/string.xml
13.
Cast Dialogの表示 ● キャストしてないとき ○
キャスト可能なデバイス一覧を表示 ● キャストしてるとき ○ メディア情報、音量などを表示 ● Android(少々手間がかかる) ○ 現在キャスト中かどうかを判定して出し分けが必要 ○ 現在のキャストセッションがあれば MediaRouteControllerDialog ○ 無い場合はMediaRouteChooserDialogを呼ぶ ● iOS ○ presentCastDialogを呼ぶだけ
14.
private fun showDialog(pCall:
MethodCall, pResult: Result) { val tCastSession = CastContext.getSharedInstance()?.sessionManager?.currentCastSession if (tCastSession != null) { val tControllerDialog = MediaRouteControllerDialog(pActivity, R.style.CastControllerDialogTheme) tControllerDialog.show() } else { val tChooserDialog = MediaRouteChooserDialog(pActivity, R.style.CastMediaRouterTheme) tChooserDialog.routeSelector = CastContext.getSharedInstance()?.mergedSelector!! tChooserDialog.show() } } Android/Kotlin Future<void> showCastDialog() async { await _channel.invokeMethod('ShowCastDialog'); } chrome_cast_plugin.dart private func showDialog(_ pCall: FlutterMethodCall, _ pResult: @escaping FlutterResult) { let tContext:GCKCastContext = GCKCastContext.sharedInstance() tContext.presentCastDialog() } iOS/Swift
15.
動画をキャストする ● 動画をキャストするために必要な情報をFlutterからPlugin側に渡す ● 手順 ○
[1] キャストするための必要なメタデータ(Metadata)を作成するためのパ ラメータ ■ タイトル、キャストダイアログに出す画像など ○ [2] 作成したメタデータからメディア情報(MediaInfo)を作成するためのパ ラメータ ■ 動画のコンテンツタイプ(mp4など)、レシーバーに渡す独自のJsonデータなど ○ [3] 必要に応じて読み込み時のオプションを作成するためのパラメータ ■ 再生位置、自動再生するかどうかなど ○ [4] 動画をデバイスにキャスト
16.
Future<bool> startCast(Media media)
async { bool _result = await _channel.invokeMethod('StartCast', { 'Uri': media.url, 'Title': media.title, 'Subtitle': media.subTitle, 'Studio': media.studio, 'ContentType': media.contentType, 'Images': { 'Dialog': { 'Url': media.dialogThumbnail.url, 'Width': media.dialogThumbnail.width, 'Height': media.dialogThumbnail.height }, 'Notification': { 'Url': media.notificationThumbnail.url, } }, chrome_cast_plugin.dart 'IsAuto': media.isAuto, 'PlayPosition': media.position, 'IsLive': media.isLive, 'CustomData': media.customData }); return _result; } ... class Media { Media({ this.url, this.title, this.subTitle, this.studio, this.contentType:, this.customData: const {}, this.isAuto, this.position, this.isLive, this.dialogThumbnail, this.notificationThumbnail, }) : ...
17.
private fun startCast(pCall:
MethodCall, pResult: Result) { val tArguments = pCall.arguments as? Map<String, Any> … // [1] メタデータの設定 val tMovieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE) tMovieMetadata.putString(MediaMetadata.KEY_TITLE, tTitle) tMovieMetadata.addImage(WebImage(Uri.parse(tDialogUrl), tWidth, tHeight)) tMovieMetadata.addImage(WebImage(Uri.parse(tNotificationUrl))) … // [2] メディア情報の作成 val tMediaInfo = MediaInfo.Builder(tUri) .setStreamType(tStreamType) .setContentType(tContentType) .setMetadata(tMovieMetadata) .setCustomData(tJsonObject) .build() … Android/Kotlin // [3] 読み込み時のオプション val tMediaLoadOptions: MediaLoadOptions = MediaLoadOptions.Builder() .setAutoplay(tIsAuto) .setPlayPosition(tPlayPosition.toLong()) .build() … // [4] Chromecastにキャスト val tIsSuccess = (tCastSession?.remoteMediaClient?.load(tMediaInfo, tMediaLoadOptions) != null) pResult.success(tIsSuccess) }
18.
private func startCast(_
pCall: FlutterMethodCall, _ pResult: @escaping FlutterResult) { let tArguments = pCall.arguments as? Dictionary<String, Any> … // [1] メタデータの設定 let tMetadata:GCKMediaMetadata = GCKMediaMetadata(metadataType: GCKMediaMetadataType.movie) tMetadata.setString(tTitle, forKey: kGCKMetadataKeyTitle) tMetadata.addImage(GCKImage(url: URL(string: (tDialogUrl)), width: tWidth, height: tHeight)) … // [2] メディア情報の作成 let tBuilder = GCKMediaInformationBuilder.init(contentURL: tParseUrl) tBuilder.contentID = tUri tBuilder.streamType = tStreamType tBuilder.contentType = tContentType tBuilder.metadata = tMetadata tBuilder.customData = tJsonData … // [3] 読み込み時のオプション let tMediaLoadOption = GCKMediaLoadOptions(); tMediaLoadOption.autoplay = tIsAuto tMediaLoadOption.playPosition = tPlayPosition … // [4] Chromecastにキャスト var tIsSuccess = true; if (tCastSession?.remoteMediaClient? .loadMedia(tMediaInfo, with: tMediaLoadOption)) != nil { tIsSuccess = true; } else { tIsSuccess = false } pResult(tIsSuccess) } iOS/Swift
19.
実演(動画)
20.
● 仕様 ○ Android
/ iOSで動作するFlutterプラグイン及びアプリ ■ Flutter : 1.2.1 ■ Android : Kotlin 1.3.11 / gms-play-service : 16.1.2 ■ iOS : Swift 4.2.1 / google-cast-sdk : 4.3.5 ● 開発エディタ ○ VSCode ○ Android Studio ○ Xcode ● Google Cast Document ○ https://developers.google.com/cast/docs/developers ● Google Cast GitHub(Android/iOS) ○ https://github.com/googlecast/CastVideos-ios ○ https://github.com/googlecast/CastVideos-android ここから先のスライドは補足
21.
補足 iOS/Xcodeで開発する場合の注意 ● Xcode10以上、iOS
12以降をターゲットにしている場合 ● Access Wifi InformationをONにする
22.
Cast Buttonの表示 ● キャスト可能なデバイスがあるときはアイコンを表示、接続中は接続中のア イコン、キャスト可能なデバイスがない場合は非表示に切り替える ●
Cast StatusをAndroid/iOSのプラグイン側から取得 ● Cast Statusの状態をもとにFlutter側でアイコンの表示・非表示を切り替える キャストしてない キャスト中
23.
private fun getCastState(pCall:
MethodCall, pResult: Result) { val tCastContext = CastContext.getSharedInstance() val Status = tCastContext.castState pResult.success(tStatus) } Android/Kotlin enum CastStatus { NO_DEVICES_AVAILABLE, NOT_CONNECTED, CONNECTING, CONNECTED, } … Future<CastStatus> getCastStatus() async { CastStatus _castStatus; int _result = await _channel.invokeMethod('GetCastStatus'); _castStatus = _getCastStateByValue(_result); return _castStatus; } … CastStatus _getCastStateByValue(int result) { switch (result) { case 1: _castStatus = CastStatus.NO_DEVICES_AVAILABLE; … break; case 2: _castStatus = CastStatus.NOT_CONNECTED; … break; … chrome_cast_plugin.dart private func getCastStatus(_ pCall: FlutterMethodCall, _ pResult: @escaping FlutterResult) { let tCastContext = GCKCastContext.sharedInstance() let tStatus = tCastContext.castState.rawValue pResult(tStatus) } iOS/Swift
24.
リスナーの登録 ● SessionManager Listener ○
アプリ全体のキャストセッションを管理 ○ SessionManagerに登録する ■ アプリがセッションを開始したとき ■ アプリがセッションとの接続を停止したとき など… ● RemoteMediaClient Listener ○ アプリと現在キャストしているデバイス(Chromecast)のメディアのセッションを管理 ○ CastSessionに登録する ■ 動画などをキャストをしたとき ■ キャストした動画に変更があったとき など… ● Flutter側の実装は必要なし ○ ※リスナーの中身の実装は今回は省略
25.
class ChromeCastPlugin(private val
pActivity: Activity, private val pChannel: MethodChannel): … CastContext.getSharedInstance()?.sessionManager? .addSessionManagerListener(*fugafura, CastSession::class.java) ... CastContext.getSharedInstance()?.sessionManager?.currentCastSession? .remoteMediaClient?.registerCallback(*hogehoge) …. Android/Kotlin public class SwiftChromeCastPlugin: NSObject, FlutterPlugin, GCKSessionManagerListener, GCKRemoteMediaClientListener { … GCKCastContext.sharedInstance().sessionManager.add(*hogehoge) …. GCKCastContext.sharedInstance().sessionManager.currentSession?.remoteMediaClient?.add(*fugafuga) …. iOS/Swift
26.
キャストした動画を制御する ● キャストしている動画をFlutter側から制御(一時停 止やシークなど)する ● Flutter側 ○
動画コントロールパネル用のUIを作る ● Plugin側 ○ 現在のキャストセッションからリモートメディアクライアン ト(remoteMediaClient)を取得して再生(play)や一時停止 (pause)、シーク(seek)を呼ぶ シーク 停止 再生 ボリューム変更
27.
Android/Kotlin private fun setMediaStreamPosition(pCall:
MethodCall, pResult: Result) { … tCastSession.remoteMediaClient.seek(tSeekTime.toLong()) … } iOS/Swift private func setMediaStreamPosition(_ pCall: FlutterMethodCall, _ pResult: @escaping FlutterResult) { … let tOptions = GCKMediaSeekOptions() // remotMediaClient.seekに渡す引数のために、ミリ秒から秒へ変換 tOptions.interval = tTime! / 1000 tCastSession?.remoteMediaClient?.seek(with: tOptions) } chrome_cast_plugin.dart Future<bool> setMediaStreamPosition(var milliseconds) async { bool _result = await _channel.invokeMethod('SetMediaStreamPosition', milliseconds); return _result; } 例)シーク
28.
応用 キャストボタンの表示バグをなくす ● Cast
Statusの状態がNOT_CONNECTEDの状態からアプリがバックグラウンドに いくと、キャストデバイスはない状態(NO_DEVICES_AVALLABLE)になる ● アプリがフォアグラウンドに戻った際に、キャストボタンが表示・非表示をし て点滅する ○ Google Playムービーなどの一部アプリでも起きている ● アプリがフォアグラウンドに戻ってきた際、数ミリ秒まってからCast Stateの 状態を取得する
29.
chrome_cast_plugin.dart class ChromeCast extends
WidgetsBindingObserver { … WidgetsBinding.instance.addObserver(this); …. @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); switch (state) { case AppLifecycleState.paused: _isDelay = true; break; default: break; } } … abstract WidgetsBindingObserver アプリのライフサイクルを監視する didChangeAppLifecycleState関数を使うために継承 didChangeAppLifecycleState AppLifecycleState state ● resumed ● inactive ● paused ● suspending のいずれかの状態を返す pausedのときに遅延を起こす WidgetsBindingObserverに登録
30.
chrome_cast_plugin.dart ... typedef OnChangeCastState =
Function(CastStatus); … class ChromeCast extends WidgetsBindingObserver { static const MethodChannel _channel = const MethodChannel('chrome_cast_plugin'); OnChangeCastState onChangeCastState; bool _isDelay = false; bool _isWaiting = false; … ChromeCast._internal() { … if (call.method == "OnChangeCastState") { CastStatus _castStatus = _getCastStateByValue(call.arguments); if (_isDelay) { if (_isWaiting == false) { _delayGetCastStatus(); } } else { onChangeCastState(_castStatus); } } }); ... } … chrome_cast_plugin.dart OnChangeCastState キャストの状態が変化したときに呼ばれるようにデリ ゲートを用意 _delayGetCastStatus 数ミリ秒待機してからキャストの状態を取得する(自作)
31.
… _delayGetCastStatus() async { _isWaiting
= true; await Future.delayed(Duration(milliseconds: _waitSeconds)); getCastStatus().then((onStatus) { if (onStatus != CastStatus.NO_DEVICES_AVAILABLE) { onChangeCastState(onStatus); _isDelay = false; } _isWaiting = false; }); } … chrome_cast_plugin.dart 数秒待機してCastStatusを取得する
Jetzt herunterladen