今年もLINE Developer Day 2017に行ってきました!!
本記事はiOSアプリ内で動画を小さい画面で再生できるPIPについて熱く解説された「動画を見ながらトークできるPIP機能の開発について」のまとめになります!
動画を見ながらトークできるPIP機能の開発について
富家将己様
line iosの開発について
- 2011年リリース
- objc 80%, swift 30%
- japan, korea, taiwan, chinaで開発している
- 本体と親和性の高いのはgit submodule、他のものに関してはcocoapods/carthageを用いている
チャットルームのアプローチについて
- よりよくコミュニケーションをできるように考えるChatroom TFというチームが立ち上がった
- その中で、動画の利便性を高くしたいという要望ができ、それの解決法としてPIPを実装することに。
- PIPは動画をみている際にチャットをしたりすることができる
- 画面内を自由に移動させたりすることができる
- video message/ youtube videoに対応済み
- なぜ自前でPIPを実装したのか?
- ios9からPIPを使えるが、ipadでしか使うことができないため自前で実装した
- 自前のためアプリを超えて動画を再生はできないので注意
課題
- どのように実装するか、audiosessinの管理が課題だった
実装方法
- 機能ごとにPIP ViewControllerを作った
- UIViewにコントローラのロジックをいれないようにするために、ViewControllerを用いるようにした
- PIPを表示するためのcontainer ViewControllerをつくるようにした
- メリットとして馴染み深いライフサイクルが使えるようになる
- PIP表示ロジックを作り、簡単にどこでもPIPを表示できるように目指した
PIP ViewControllerを作る
- PIP提供用に新たなプロトコルを作成した
- 動画サイズは横や縦で異なるが、動画サイズはコンテンツに依存するため、サイズを設定するプロパティをPIP ViewControllerに用意し、子ViewControllerのサイズ変更をハンドリングできるようにした
LINEで表示する方法について
- PIPLayerViewControllerを既存のLINEに重ねれられれば画面遷移してもずっと表示することができる
- 今までrootViewControllerはtabViewControllerだったが、LineRootViewControllerというカスタムViewControllerを親ViewControllerに変更し、そこから、PIP LayerViewControllerと今までのTabViewControllerを表示できるようにした
- tabViewControllerを参照しているコードがあるかもしれないので非常にリスキーではあったがうまくいった
PIP Layerを表示する方法
- チャットルームからPIPLayerViewControllerに動画を渡さないといけないが、入れ子関係の距離がとても遠いため、LineRootViewControllerにPIPLayerを渡して表示できるように作成した
- 流れとしてLineRootViewControllerに動画をわたし、更にPipLayerViewControllerに渡すことで表示している
- 自作ViewControllerを親にすることで、柔軟に画面表示ができるようにした
AudioSessionの管理について
- 開発の2/3はここに時間がかかった
- audiosessionはOSに対して音声の利用状況を設定するためのものでアプリ内の音声を制御できる
- 今までのLINEは都度、AudioSessionに渡して音声を流していた
- VoIPは最優先にしており、VoIPを利用中は他の機能はAudioSessionは利用できないようにしている
- PIPも優先度は高いため、各機能から参照できるようにする必要があるが既存の仕組みでは無理
- そこで、AudioSession設定をステートとしてセットして、現在のステートをみて、挙動をするようにした。
- ステートには重要度が設定されており、一番重要度の高いステートから音声が再生される
- これらを音の出る機能全てに設定しないといけなかったため、非常に時間がかかるので、チーム内で分担して実施した
- ステートはenumで定義して一番下程優先度が高い
利点
- VoIPの依存性を排除できた
- 音を出す機能を追加しやすくなった
- 複数の音をだすのが把握しやすくなった
問題
ステートのリーク問題
- 配列で管理していたが、ステートの削除に失敗するとステートが永遠に残ってしまった
- 弱参照のNSMapTableの管理に変更することで、そのオブジェクトのライフタイムに乗っ取り、オブジェクトを開放する際に一緒にステートも消えるようになった
他のプロジェクトで勝手にaudio sessionを変更するものがあった
- auidio sessionを勝手に触らないルールを他プロジェクトでも適用するために、audio sessionの管理は一時的に放棄して別プロジェクトに移譲するオプションを追加した
audiosessionをdeactiveするときの問題
- 音をフェードアウトするとOSがアプリのUIを止めて、その都度アプリの挙動などが止まってしまったり、動画セッション中に音がとまってしまう問題が発生した
- deactiveを結果的に諦めた
- しかし新たな問題として、VoIP後、BGMが復活しない、一般のBGMを止めてしまうなどの問題が発生したので以下の対策を入れた
- 他にstateがなければdeactiveするオプションの導入をした
- 設定を変える前に一瞬deactiveするまえに音を止めずに再生することがわかったので、設定前にdeactiveを実施し、カテゴリが設定されたあとすぐにactivateを実施するオプションを導入した
まとめ
- PIP
- LineRootViewControllerを追加した
- targetViewControllerを用いてどこでもPIPを表示できるようにした
- AudioSession
- 中間管理の仕組みを入れた
- 弱参照で管理するステート
- deactivateの追加ルールを加えた
PIPをアプリで実装するために大胆な変更をして見事成功されたおもいっきりや技術力に非常に感服いたしました。
iPhoneでもPiPを提供してくれればいいんですけどね・・・iPadではできるのに非常に悔やまれます。
気軽にPiPできるライブラリとかもこれを機にあるといい感じがしますね!(探せばありそうではありますが)
View Comments
Thanks for sharing. I read many of your blog posts, cool, your blog is very good.
Your article helped me a lot, is there any more related content? Thanks!