2013年8月24日土曜日

iPhoneでバックグラウンド動作させる場合のTIPS

久々に技術ネタを書きます。
今回は、iPhoneアプリでのバックグラウンド動作について。

1. 概要

元々(iOS3の頃)のiOSは、サードパーティ製のアプリ(一般アプリ)のバックグラウンド動作は出来ない仕様でした。しかし、iOS4でバックグラウンド動作が出来るように仕様変更されました。

ただし、バックグラウンド動作は、特定の種類のアプリにしか許可されていません。
バックグラウンド動作をしても良いアプリは、次のもののみです。

  • 音楽プレーヤーのように、バックグラウンドで音声を再生するアプリケーション
  • ナビゲーションのように、常に位置情報を知らせるアプリケーション
  • VoIP(Voice over Internet Protocol)対応アプリケーション
  • 最新号をダウンロードして処理する必要があるNewsstandアプリケーション
  • 外付けアクセサリから定期的に更新情報を受け取るアプリケーション

詳しくは、Appleが発行している「iOSアプリケーションプログラミングガイド」の「バックグラウンド実行とマルチタスク」というセクション(65ページあたり)に書かれています。上記以外の種類のバックグラウンド動作をするアプリだと、Appleの審査でリジェクトされると思います。

2. 基本的な実装方法

plistに「Required Background Mode」を追加して、オーディオアプリならitem0に「App plays audio」を設定します。あとは、デリゲートで起動完了時に、オーディオセッションのカテゴリをプレイバックに設定する必要があります。

以下の記事あたりが分かり易いと思います。
http://d.hatena.ne.jp/KZR/20100920/p1

一般的なアプリなら、この実装をするだけでOKです。ですが、OpenALを用いているプログラムの場合、その他にも色々な改造が必要です。本項の情報なら、割と沢山出回っていたのですが、その点について解説したTIPSが見当たらなかったので、若干苦労しました。以下、OpenALを用いているプログラムをバックグラウンド対応する為に必要なTIPSについて記します。

3. バッファリング間隔の変更

バックグラウンド動作時のバッファリング間隔を修正する必要があるかもしれません。iOSでは、バッファリング間隔の目安として、CD品質(44100Hz、ステレオ、16bit)の音声であれば500ms程度※としています。
※Appleが発行している「オーディオセッションプログラミングガイド」の「最適なオーディオハードウェア設定の指定」(40ページあたり)を参照

SUZUKI PLAN - Video Game System(VGS)の音声品質は、22050Hz、モノラル、16bitなので、125ms辺りが目安値になります。しかし、バッファリング間隔をそんなに長くしてしまうと、効果音の再生処理の遅延が酷くなってしまいます。そのため、VGSでは通常(フォアグラウンド動作時)は、バッファリング間隔を50msにしています。フォアグラウンド動作であれば50msでも問題無く動いてくれていましたが、スリープボタンを押すと、音飛びが発生してしまいます。どうやらiOSは、スリープ時に(電池消費を抑える為に)プロセスに対して割り当てるプライオリティを、意図的に低く設定しているようです。

そこで、バッファリング間隔を
・フォアグラウンド時は50ms
・バックグラウンド移行後は500ms
という具合に、状態に応じて切り替える制御を実装する必要があります。

4. メインルーチンの別スレッド化

私のアプリの場合、メインルーチンは、CADisplayLink(垂直同期)の仕組みを使って1秒間に60回呼び出される形になっています。しかし、バックグラウンド移行後は(アプリに対して垂直同期時に割り込み通知をする必要が無いため)それが呼び出されなくなってしまいます。そこで、バックグラウンド移行後は、メインルーチンの呼び出しを別スレッドで行うようにする必要があります。

5. デバイスロスト(割り込み)の対処

従来の私のiPhoneアプリは、ホーム画面に戻った場合、プロセスを停止するようにしていました。しかし、バックグラウンドでの動作(※サスペンドを含む)を想定する場合、OpenALのデバイスロストを検知した時の処理を実装しなければなりません。OpenALのデバイスロストが発生すると、割り込みにより、予め定義したコールバック処理が実行される仕組みになっています。そのコールバック処理で、適切な復旧処理を行う必要があります。

ちなみに、コールバックが未登録の場合、デバイスロストが発生しても、特にエラーが発生せずに処理を続行します。しかし、その状態(適切な復旧処理を行っていない状態)では、音が鳴らなくなってしまうので、注意する必要があります。

なお、割り込みは、競合するオーディオデバイスを使用するアプリを起動した時に発生します。分かり易い例としては、アプリが動作中に電話が掛ってきた時とか。


こんな感じです。

東方VGSをバックグラウンド再生に対応させるため、これだけのことをやりました。割と大変でした・・・大変だったけど、結構沢山の方から要望を頂いたので、速めに対応した方が良さそうだということで、予定外のバージョンアップで対応することにしました。(本当は、妖々夢の全曲が揃ってからアップするつもりでしたが、それでは遅すぎるだろうと思ったので)

今回の敗因は、「iPhoneではバックグラウンド動作はできない」と私が勝手に思い込んでいたことかな。いわゆる「だろう設計」ってヤツです。Appleの設計思想は、そんなにコロコロ変わらないだろうと勝手にイメージしていましたが、どうやら、そうでもなかったようです。

2013年8月23日金曜日

NOKOGI Rider 祝100+&1周年

何気なく、Google PlayでNOKOGI Riderをチェックしていて、重大なことに気づきました。
Google Playの様子(8/23撮影)

お分かりいただけたでしょうか。

ダウンロード数が「100+件」になりました!!!

感無量です。
あれっ?
嬉しい筈なのに涙が・・・
ご購入いただいた方は、本当にありがとうございます。

ついでに、製品版のNOKOGI Riderをリリース開始してからもうすぐで1年になります。
「サクラを一切使わず1年で100本売る」
という販売目標(KPI)を立ててやっていたので、ギリギリ達成することができました。
Invader Block 2の時は、職場の知り合い数名に購入していただいたりしたのですが、NOKOGI Riderについては本物の「実力only」で勝負したかったので、Lite版を勧めることはあっても、製品版の購入は催促しないようにしました。

「1年で100本」と聞くと、とてもささやかな数字に見えるかもしれません。
ですが、ほぼ無名の個人が作ったアプリを100本売ることは、相当大変なことです。
CAVEの怒首領蜂大復活ですら5,000~10,000本しか売れていないし、パズドラが大ヒットしているガンホーも、実は有料アプリを出しているのですが5,000~10,000本しか売れていません。

無料(広告モデルとか)であれば100本なら割と簡単にクリアできますが、無料と有料の間の壁は、余りにも大きすぎます。「iPhoneなら」と、思っていた時期が私にもありましたが、iPhoneだったとしても大変なことです。(一昔前なら良かったかもしれませんが)

ちなみに、販売数の国別の内訳としては、次の通りでした。
国別の内訳
日本:外国=4:6という感じですね。
概ね想定通りの割合です。

私は、元々「スマホで作るなら、グローバルで売れるゲームを作りたい」と考えていました。グローバル路線でいくことについては、もしかすると、賛否両論があるかもしれません。日本人なら日本人向けに特化したゲームを作った方が、良いのは確かです。ただ、ロケールフリーなゲームを作るということは、言語による柵を超えることを意味します。私は常々、ゲームはシンプルでなければならないと考えていたので、グローバル路線を意識したことは、私の作品にはプラスの作用をしたと思います。

さて、次の目標ですが、「このやり方で100本売れたのなら、1万本は売れるんじゃない?」と思っていたりするのですが、それはまだまだ先のことになりそうです。地道なブランディングを推進して、「SUZUKI PLANのゲームなら買っても良い」と思っていただけるようになれば、恐らく達成できると思いますが、道はまだまだ遠い。っていうか、無料のLite版ですら10,000本に届いていないですし...(Lite版の総DL数は、現時点で6,000本ぐらい)

2013年8月4日日曜日

iPhone/Android両対応の有料アプリの売り方に関する考察

私は、SUZUKI PLAN - Video Game System(VGS)を用いることで、iPhoneとAndroid両対応のアプリを効率的に開発することができます。ですが、そのポテンシャルの活かしたマーケティング方法について、あまり考察せず、「完成したら可能な限り早くリリース」というスタンスでやってきました。ただ、ちょっとばかり考えてみると、どうもそのやり方はあまり宜しくないかもしれない…ということで、記事に纏めてみることにしました。

(1)マーケット特性
GooglePlayとAppStoreの特性の違いを、下表に纏めてみました。
比較項目
GooglePlay
AppStore
申請から公開迄に掛かる期間 1~2時間ほど 1~2週間ほど
新着インプレッション機会 一定の人気が有る場合に限る 必ず有る
ランキング変動スパン 長め 短め
価格変更 ○有料→無料
×無料→有料
○有料→無料
○無料→有料

(2)申請から公開迄に掛かる期間
GooglePlayの場合、申請したアプリについて、人手による審査は無いため、申請すればすぐに公開されますが、AppStoreの場合、Appleによる審査に1~2週間程度の期間を要します。そのため、AndroidとiPhone両方のアプリが同時に完成でき、可能な限り早く申請を行った場合、公開される順序は必ずGooglePlay→AppStoreの順序になります。

(3)新着インプレッション機会
GooglePlayとAppStoreの場合、新着アプリのインプレッション機会に大きな違いがあります。GooglePlayの場合、公開から1ヶ月以内の人気のあるアプリに限り、「新着ランキング」に載ることができますが、AppStoreの場合、全てのアプリに「新着アプリ」への掲載機会があります。
つまり、以下のようなことが言えます。
・GooglePlay:プロモーション(広告、SEO等々)をしなければ、殆どダウンロードされない。
・AppStore:何もしなくても数日間はダウンロードして貰える。

(4)ランキング変動スパン
人気ランキング(※新着に限らない)は、GooglePlayの場合、変動が少ないのに対して、AppStoreは非常にコロコロ変動します。この違いにより、GooglePlayでは、一度人気を取ったアプリは長期間ランキング掲載されるのに対して、AppStoreでは、人気が長続きすることは無いという特徴があります。換言すれば、GooglePlayでは、ランキング上位へ食い込むことが極めて困難であるのに対して、AppStoreでは、誰でもランキング上位へ食い込むチャンスがあると言えます。

(5)価格変更
AppStoreとGooglePlayの最大の違いは、無料アプリの有料化ができるか否かです。
AppStoreならできますが、GooglePlayではそれができません。
なお、有料アプリの無料化ならどちらでもできますが、それは基本的に禁じ手です。有料時に買っていただいた方に申し訳ないので、「お客様第一主義」という観点では、絶対にやってはいけないことだと思います。(個人的には、値下げ販売も同様だと思っています…割と横行してますが)

(6)考察
上述の事情を考察した結果、最も理想的な販売戦術は、次のような形だと思います。
①最初に、iPhone版を無料(広告すら無しの完全無料)でリリースする
②一定期間経過後、有料化する
③Android版を最初から有料でリリースする
④広告出稿等のプロモーションを必要に応じて行う
上記①は、アプリの内容について評価をして頂くためのものです。一般ユーザの声が聞けるので、プロモコードを発行するよりも遥かに有益だと思います。そして、評価されればランキング上位に食い込み、更なる評価機会を得ることができます。
その後(一定の評価が得られてから)、有料化(②)を行います。「有料→無料は禁じて」だと先述しましたが、「無料→有料」ならOKだと思います。ただし、「有料の別バージョンをリリースして、無料版を非公開にする」という方式はNGです。実際、そういうやり方をしているアプリを見た事があるのですが、☆1でボロクソに叩かれまくっていました。少し考えれば、そんなことは誰でも分かるのに、何故そんなことをしたのか不思議です。無料で提供することで得られなかった収益は、「プロモーション費用」だと割り切って考えるべきだと思います。
そして、iPhone版での一定の成功を待ってから、Android版をリリース(③)します。そうすれば、口コミ(ブログ等)でアプリの情報が広まった状態になっていると期待できるので、ランキング上位へ食い込むことが難しいAndroidでも、そのチャンスが訪れるかもしれません。
また、iPhone版で得た収益から、広告費用を捻出できるかもしれません。Android版の方が、売るのが難しい分、売れれば大きい(World wideでの数がiPhoneよりも遥かに多い)ので、iPhone版はテストマーケティング、Android版で本気のマーケティングを仕掛けるやり方の方が、売り上げが大きくなるのではないかと想定しています。なので、必要に応じてAndroid版の広告出稿など(④)を行います。

次(SUPER REAL RACING(仮))からは、この作戦で行ってみるか。
作り手サイドの思考としては、作ったらなるべく早くリリースしたいのですが...
ただ、そこは、グッと堪えた方が、得策かもしれません。