やりたかったこと:
RaspberryPi - Raspberry piとApacheとWebカメラで外部から見られる監視カメラを作った話。
http://qiita.com/CST_negi/items/a329cc98fb1aa33f33d3
を、iPhoneアプリから監視できるようにしたかったということです。
用意したもの:
・iPhone5s (iOS8.1)
・Xcode6 (Swiftを使って開発しています)
・raspberry pi2とApacheやmjpg-streamerなどの環境が構築されたもの
(これは詳しくは前回の記事をみてください)
では書いていきます。
ちなみになんで初心者向けなのかというと僕が初心者だからです。
作ったきっかけの話とプロトタイプ
とりあえずなんでiPhoneアプリから監視できるようにしたかったかというと、
・iPhoneからwebページにアクセスしてもなんの面白みがない(ブラウザ開いていちいちURL直打ちしたくない)
・使いづらかったことやストリーム受信による通信量が多くなりそう
だったのが個人的に嫌だったからですね。逆にポジティブな理由としては
・いずれおうちハックをiPhoneから全部制御できたらいいなと考えてるのでその機能の一貫として
ということです。(こっちがメインの理由)
というわけで、まずプロトタイプの完成品を見せます
こんな感じになりました。
TabbedPageLayoutのiPhoneアプリを作っていまして、このページは「カメラアプリや部屋の温度など部屋を操作するのではなくて、状態を監視するページ」として構築予定です。
ではiPhoneアプリ開発の話から始めていきましょう
開発始めと部品の配置
まずはXcode6を開いて、Projectを作っていきましょう。
僕は後々のことを考えてTabbedApplicationにしましたが、Single View Applicationでも構いません。
とりあえずプロジェクトを作って、Main.storyboardをクリック後、Simulated MetricsでSizeを4-inchにしたものがこちらです。
①:
右下のLibrary paneの右から二番目のボタンをクリック。するとたくさん部品(UIコンポーネント?)が出てくるのでその中からWebViewを探します。
②:
WebViewをドラッグして、StoryBoardのプレビューエリアにドロップします。すると配置されます。
③:
適当な大きさにサイズを調整します。
WebViewにカメラ画像を渡すための前準備
ここからコードを書いてゆきます。
このViewに関連付けされているViewController(Swiftファイル)を開いてください。
(Single Page ApplicationならデフォルトではViewController.swiftになってると思いますが、変更した場合は各自任意のものを使ってください。)
何が関連付けられているかは上の画像のようにInspector Paneの左から3番目のものをクリックするとわかります。
また、XcodeのEditor自体のレイアウトもこの際ちょっと変えておきます。
こんな感じのレイアウトにしておきましょう。
このレイアウトにするには、Editorの右上を以下の画像のような感じでスイッチしておけば大丈夫です。
だいぶ話がそれてしまったので戻ります。
StoryBoardのプレビューにあるWebViewをCtrlキーを押しながらドラッグして、右のViewController.swiftにドロップしてください。
すると、
こんな感じの画面がでてくるはずで、ViewController.swift上での変数名を決めることができます。
今回はMonitorWebViewとしました。
ここまでやると
@IBOutlet weak var MonitorWebView: UIWebView!
がコード上で生成されていると思います。
では前置きがめちゃくちゃ長くなりましたが、これに監視カメラの画像を埋め込む方法を説明します。
WebViewに監視カメラの画像を表示させる
といっても別に難しいことはしていません
override func viewDidLoad() {
super.viewDidLoad()
loadCamView()
}
func loadCamView(){
var url: String = "http://[前記事で設定したDDNSのアドレス]:8081/?action=snapshot"
let requestURL = NSURL(string: url)
let req = NSURLRequest(URL: requestURL!)
MonitorWebView.loadRequest(req)
}
これだけで「アプリ起動時に監視カメラの内容をWebViewに表示するということができちゃいます。楽!
loadCamView関数について少し説明すると、
①まずURLをString値で持っておく
②NSURLに変換する(NSURLとはローカル画像や外部ネットワークを介してのデータにアクセスする際に利用するクラスです。)
③req変数に先ほどのNSURLに変換されたURLを渡してRequestした結果をもたせる。
④最後にMonitorWebViewにその結果を表示させる。
という感じです。
(参考:http://qiita.com/drobune/items/17295b2de6663b56785a)
今回URLを渡して要求するのは画像ファイルそのものなので、WebViewには画像しかでてきません。
おまけ
今回はストリームをそのまま垂れ流すのではなく、action=snapshotつまり静止画を表示させているため通信量を抑える工夫をしています。
ただしこのままだと、アプリ起動時に画像を取得して表示させるだけの機能になってしまって使い勝手が悪いので別途ボタンを用意して
@IBAction func CamViewUpdateButton_Pressed(sender: UIButton) {
loadCamView()
}
こんな感じにボタンを押したら画像を再取得するようにすればいいかなと思います。(僕のアプリではこの方法を採用しています。)
また監視カメラの画像がでかすぎてアプリに収まらないよ!って人もいると思います。
その場合はまずStoryBoard上のWebViewをクリックして一番右のInspector Paneの右から3番目のボタンを押してください。(下の画像参照)
すると一番上にScaling ☑️Scales Page To Fitという超ありがたいボタンがあるのでそれをチェックしてください。
これをチェックすると、WebViewの大きさに合わせて画像が表示されるようになります。
(アスペクト比が崩れるかはちょっと検証してないです。すみません。)
(参照:http://qiita.com/s0hno/items/b4f33438df4297950d47)
未解決の問題
・URL指定の都合上サーバと同一Wifi内にいるとカメラ画像は表示できなくなっちゃいます。
・記事に書いてあることだけをやると、セキュリティかけてないのでURLがばれてしまうと大変危険なので各自セキュリティは工夫してください。
この2点ですが、何かおすすめの解決法とかこうすればいいんじゃない?みたいな提案などお待ちしてます。
後ほど追記させていただきます。