iOSアプリ開発におけるイースターエッグのすすめ
はじめに
この記事はiOS Advent Calendar 2015 - Qiita 19日目の記事です。
昨日はhachinobuさんのMVVMっぽい構成のデモアプリを公開してみるでした。
本日はイースターエッグについて。
イースターエッグとは簡単にいうと隠し機能のことです。余裕のある開発者が仕込んだ粋なお遊びですね。
発見したときはついつい友達に教えたくなります。イースターエッグが仕込まれているアプリおよび実装例について紹介しますね。
イースターエッグの例
まず、イースターエッグが仕込まれているアプリをいくつか紹介しますね。
Google検索
「Google」という名前のGoogle検索アプリです。ロゴ部分をタップすると…!
ちなみにロゴが新しくなる前は、なぞるとロゴがバラバラになりました。
www.youtube.com
スーモ
「スーモ」アプリには複数のイースターエッグが仕込まれています。
トップの「借りる」または「買う」を16回タップすると…!
また、「設定」→「このアプリについて」の空白部分でコナミコマンドを打つと…!
Google Chrome
「Google Chrome」のタブを開くと右上の四角の枠にタブ数が数字で表示されますが、タブを100個開くと… :)
Google Chromeのネットワークエラー画面で恐竜をタップするとゲームができるのも有名ですね。
The Offline Dinosaur in Google Chrome is Actually a Game
イースターエッグを仕込むメリット
ちょっとしたアプリの宣伝になります。発見したイースターエッグを教えたいという気持ちからクチコミに繋げられますね。また、開発者としての余裕を見せつけることができます。ぜひ余力があればイースターエッグを仕込んでみましょう。こういう遊び心は忘れたくないものです。
イースターエッグを仕込む
イースターエッグを仕込むには様々な方法がありますが、「ある特定の条件を満たしたときにアクションを起こす」というのが王道かと思います。iOSには下記のように、ユーザによるアクションがたくさんあります
- 長押し
- タップ
- ピンチイン・アウト
- パン
- スワイプ
- 回転
- マルチタッチ
- なぞる
- 3D Touch
- 振る
- 傾ける
今回はこれらの中からイースターエッグとして使えそうなイベントをいくつか紹介しますね。ほぼコピペで使えるかと思いますのでぜひご参考ください。
(UIViewにイベントを付加した場合の例になります。)
長押し
ロゴやViewを長く押した場合に色が変わるなどそういった動作にどうぞ。minimumPressDurationが長押しと判定されるまでの時間になります。
let longPressGesture = UILongPressGestureRecognizer.init(target: self, action: "didLongPressGesture:") longPressGesture.minimumPressDuration = 2.0 self.addGestureRecognizer(longPressGesture) userInteractionEnabled = true
func didLongPressGesture(sender : UILongPressGestureRecognizer) { print("long pressed!") }
マルチタッチ
multipleTouchEnabledをtrueにするだけ。5本指でタッチしたとき、2本指でスライドしたときなど、複数の指の動作を判定したい場合に使えます。
multipleTouchEnabled = true
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { print("\(event?.allTouches()?.count)") }
振る
あまりiPhoneやiPadを振ることはありませんが(文字取り消しのときくらい?)、逆に普段使わない動作をイースターエッグ発動のイベントとして使うのはありですね。
override func canBecomeFirstResponder() -> Bool { return true }
override func motionBegan(motion: UIEventSubtype, withEvent event: UIEvent?) { if event?.type == .Motion && event?.subtype == .MotionShake { print("START:Shake!!") } }
override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent?) { if event?.type == .Motion && event?.subtype == .MotionShake { print("END:Shake!!") } }
3D Touch
iPhone 6s から登場した3D Touch。どれくらい強く押されたかを取得できます。アイコンを強く押したら動き出すなどいろいろな使い方ができそう。
注意点としてはiPhone 6s 以降の端末でないと利用できません。また、iPhone 6sでも3D Touchの機能をオフにしている場合があるので、下記のようにiOSのバージョンおよび3D Touchが有効かどうかをチェックする必要があります。
maximumPossibleForceを基準として今どれくらい強く押されているか判定できます。
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { switch UIDevice.currentDevice().systemVersion.compare("9.0", options: .NumericSearch) { case .OrderedDescending, .OrderedSame : if traitCollection.forceTouchCapability == .Available { print("3D Touch OK") for touch in touches { print("\(touch.force)") print("\(touch.maximumPossibleForce)") } } else { return } case .OrderedAscending : return } }
コマンド入力
「スーモ」のイースターエッグで紹介したコナミコマンドなどに使えます。上下左右のスワイプを感知して、特定の動作をしたときにイースターエッグを発動させましょう。下記の例ではコナミコマンド(上下左右の動きのみ)を実装しています。
var gestures = [UISwipeGestureRecognizerDirection]() var konamiCommands = [UISwipeGestureRecognizerDirection]()
// Add Gestures let leftSwipe = UISwipeGestureRecognizer.init(target: self, action: "checkCommand:") leftSwipe.direction = .Left self.addGestureRecognizer(leftSwipe) let rightSwipe = UISwipeGestureRecognizer.init(target: self, action: "checkCommand:") rightSwipe.direction = .Right self.addGestureRecognizer(rightSwipe) let upSwipe = UISwipeGestureRecognizer.init(target: self, action: "checkCommand:") upSwipe.direction = .Up self.addGestureRecognizer(upSwipe) let downSwipe = UISwipeGestureRecognizer.init(target: self, action: "checkCommand:") downSwipe.direction = .Down self.addGestureRecognizer(downSwipe) // Konami Command konamiCommands.append(upSwipe.direction) konamiCommands.append(upSwipe.direction) konamiCommands.append(downSwipe.direction) konamiCommands.append(downSwipe.direction) konamiCommands.append(leftSwipe.direction) konamiCommands.append(rightSwipe.direction) konamiCommands.append(leftSwipe.direction) konamiCommands.append(rightSwipe.direction)
func checkCommand(gesture : UISwipeGestureRecognizer) { if gestures.count == konamiCommands.count { gestures = Array() } gestures.append(gesture.direction) var i = 0 while i < gestures.count { if gestures[i] != konamiCommands[i] { gestures = Array() break } i += 1 } if i == konamiCommands.count { print("input Konami Command!!") } }
イースターエッグ実装時の注意点
イースターエッグを実装しているときはけっこうワクワクしますよね。
自分しか知らない機能を仕込んでいるときは悪い顔になっている気がします。
色々と楽しいイースターエッグですが、仕込む際に注意すべきことがあります。
2.アプリに負荷がかからない(クラッシュさせない)
イースターエッグを発動させたときの動作は十分パフォーマンスチェックをしましょう。
負荷がかかりすぎてアプリが重たくなったり、場合によってはクラッシュするようなことがあると台無しです。
おわりに
イースターエッグを仕込めるくらい余裕をもって開発したいですね。