動画再生の為に止まったミュージックプレイヤーを動画終了後に戻す
私はいつもイヤホンで音楽を聞きながらスマートフォンを操作するのですが、最近は動画によってそれが止まることが増えました、例えば Facebook、Twitter、ニュースアプリ...etc
数秒の動画や動画広告の為に何度もミュージックプレイヤーを再生し直すのは鬱陶しくなんとかならないかと思っていましたが、ちゃんと動画終わった後にミュージックプレイヤーが鳴り始めるアプリがあって、「なんだできんじゃん!!!じゃあJustawayも対応するか」とコードを書き始めた次第です。
ざっとこういったコードで対応しています。
Android
final boolean musicWasPlaying = ((AudioManager) getSystemService(Context.AUDIO_SERVICE)).isMusicActive(); // ... if (musicWasPlaying) { Intent i = new Intent("com.android.music.musicservicecommand"); i.putExtra("command", "play"); sendBroadcast(i); }
iOS
do { try AVAudioSession.sharedInstance().setActive(false, withOptions: AVAudioSessionSetActiveOptions.NotifyOthersOnDeactivation) } catch { print("AVAudioSession setActive failure.") }
半年ぶりにJustaway for Androidを更新しました
あけましておめでとうございます。
遂に動画の再生が可能になりました、実に半年ぶりの更新です。
Justaway - Google Play の Android アプリ
「動くやろ〜」と思ってrelease apkの動作確認しないでアップデートしたら起動しなくなるなど不具合が起きるなどトラブルもありました。先人のおかげですぐリカバリーできました、本当にすみませんでした。
Android - GsonとProguard - Qiita
ProGuardは使うべきか
オープンソースなので難読化する意味は無いのですが、minifyによるパフォーマンスの恩恵が少しでもあるなら使おうというスタンスです。
半年間何をしていたのか
for iOS の開発と仕事とプライベートで時間がなかったことと、iOS開発中はiPhoneを持ち歩いていたため、そっちに動画再生機能をつけて楽しんでいました、本当にすみませんでした。
Nexus 5X ✄ 4G-S
Nexus 5XにNexus 5に刺さってしたSIMを移植するに為にSIMカッターをamazonで買おうとしていましたが「ハサミ出来ますよ」と言われやってみたらさくっと出来ました。
ハサミは便利
iPhoneユーザーはバックキーじゃなくてジェスチャーを使うんだよ!!!
iPhoneの画面下にバックキーを追加する強化液晶ガラス保護シートが話題になったりホームボタンのダブルタップで押し下がる画面を見て私も「だからバックキーいるじゃん!!!」と思っていた。
しかしずっとAndroidを使っているうちにiPhoneの操作でジェスチャーをよく使うというのをすっかり忘れていただけだったのだ。
iPhone 6sをしばらく使っていると殆どシチュエーション、例えばプッシュで追加された画面は右スワイプ、画像プレビューなどは上下スワイプでバック相当の動きが出来ていて、画面の左上をタップすることなんて殆ど無い。
Androidはバックキーがあるのでとにかく前の状態に戻りたい時は考えずにバックキーを押すしこれが便利でスマホには必須だと思っていたけどジェスチャーというもの、ジェスチャーというものを、彼の事を忘れていた。
そういった具合にiPhoneアプリはジェスチャーをバリバリ使っていくのがスタンダードで画面下に戻るボタンを置くのは悪手だなと思いJustawayを改良しています。
Justaway for iOS βテスト申し込み
iOS標準Frameworkで作れるオーバーレイタイプの動画プレイヤーを付けました
Android の Vine Player が好きであのさり気ない感じの動画プレイヤーを Justaway for iOS に組み込みました
Vine Playerの公開とVineの動画をAndroidで再生するお話 - おぼえにくいおぼえがき
サムネイルをタップするとオーバーレイで動画再生ビューが開いてタップすると閉じるというシンプルな仕様です
ソース(新)
2015/9/22 MPMoviePlayerController が非推奨になっていたので更新しました。
参考
//-- SomeViewController.swift import AVFoundation let playerView = AVPlayerView() func configureView() { // タップされたら動画終了 playerView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "hideVideo")) // 背景を半透明に playerView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5) } func configureEvent() { // 動画の最後に来たら最初から再生(リピート) NSNotificationCenter.defaultCenter().addObserver(self, selector: "endVideo", name: AVPlayerItemDidPlayToEndTimeNotification, object: nil) } func showVideo(videoURL: NSURL) { guard let view = UIApplication.sharedApplication().keyWindow else { return } // 画面いっぱい playerView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height) // このURLの動画プレイヤーを playerView.player = AVPlayer(URL: videoURL) playerView.player?.actionAtItemEnd = AVPlayerActionAtItemEnd.None // アスペクト比を維持しつつ playerView.setVideoFillMode(AVLayerVideoGravityResizeAspect) view.addSubview(playerView) // 再生していく人生 playerView.player?.play() } // 動画の時代終わり func hideVideo() { playerView.player?.pause() playerView.removeFromSuperview() } // リピート func endVideo() { playerView.player?.currentItem?.seekToTime(kCMTimeZero) } //-- AVPlayerView.swift import UIKit import AVFoundation class AVPlayerView: UIView { var player: AVPlayer? { get { let layer: AVPlayerLayer = self.layer as! AVPlayerLayer return layer.player } set(newValue) { let layer: AVPlayerLayer = self.layer as! AVPlayerLayer layer.player = newValue } } override class func layerClass() -> AnyClass { return AVPlayerLayer.self } func setVideoFillMode(mode: String) { let layer: AVPlayerLayer = self.layer as! AVPlayerLayer layer.videoGravity = mode } }
ソース
import MediaPlayer var moviePlayer: MPMoviePlayerController? func showVideo(videoURL: NSURL) { guard let view = UIApplication.sharedApplication().keyWindow else { return } let moviePlayer = MPMoviePlayerController(contentURL: videoURL) // view playerスタイル(再生コントロールがない) moviePlayer.controlStyle = MPMovieControlStyle.None // ショートムービーはリピートした方がいい moviePlayer.repeatMode = MPMovieRepeatMode.One // 画面いっぱい moviePlayer.view.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height) // 背景透過 moviePlayer.backgroundView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5) // 再帰的にclearColor指定しないと真っ黒 moviePlayer.view.backgroundColor = UIColor.clearColor() for subView in moviePlayer.view.subviews { subView.backgroundColor = UIColor.clearColor() } // タップして閉じるをやっていく let screenView = UIView(frame: view.bounds) screenView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "hideVideo")) moviePlayer.view.addSubview(screenView) // 最前面にaddSubview view.addSubview(moviePlayer.view) // 自動再生 moviePlayer.play() // インスタンスを保持しておかないと再生できない(viewだけじゃなダメ) self.moviePlayer = moviePlayer } func hideVideo() { // 停止してから消さないと音が止まらない self.moviePlayer?.stop() self.moviePlayer?.view.removeFromSuperview() }
SwiftでTwitter Streaming APIをparseするのに便利なNSData分割読み込みライブラリ
Twitter Streaming APIはCRLF区切りでJSONを送ってくるのですが、これを都度Stringに変換しcomponentsSeparatedByStringで配列にし、最後の手前まではNSDataに戻してJSONに、最後の要素はバッファに詰めて次回処理で先頭にくっつける...というのがいかにもパフォーマンス上よろしくなさそうなので、NSDataからデータを変換せずにある区切り毎にデータを読めるライブラリを書きました。
以前のコードと比較すると7倍弱高速化されました、パフォーマンスを体感することはないでしょうが消費電力が下がるという見方もできます。
また、コードの可読性も高まりました。
import Foundation import MutableDataScanner import SwiftyJSON class TwitterAPIStreamingRequest: NSObject, NSURLSessionDataDelegate { let scanner = MutableDataScanner(delimiter: "\r\n") // ... func connection(connection: NSURLConnection, didReceiveData data: NSData) { self.scanner.appendData(data) while let data = self.scanner.nextLine() { if data.length > 0 { let json = JSON(data: data) } } } }
github.com
※Swift 2以降のみ対応です