Xcodeで1つのプロジェクトから無料版と有料版のiOSアプリをビルドする

iOSアプリの無料版と有料版を提供するとき等に、Xcodeの1つのプロジェクトから無料版と有料版の2つのアプリをビルドしたいケースがあります。

Xcodeで2つのプロジェクトに分けてしまうと、バグ修正や新機能追加のたびに両プロジェクトをコーディングする必要があって大変なので、広告や有無や制限値の差異程度であれば1つのプロジェクトから2つのアプリをビルドすると楽です。

ここでは1つのプロジェクトの同一ソースから2つのアプリをビルドする方法を説明します。

Xcode上での作業

ここでは、有料版が既にあって、新たに無料版を追加する場合を例にして説明します。

  1. 有料版のTargetを複製して無料版を作る

    1. Projectツリーを開く
    2. Targets > 有料版アプリを右クリックする
    3. Duplicateをクリックして複製する
    4. 無料版のTarget名が「Target名 copy」となっているので無料版の名前に修正する
    5. 無料版のTarget > General > Identity > Bundle Identifierを無料版のものに修正する
  2. 無料版のプロダクト名を設定する

    1. 無料版のTarget > Build Settings > Packaging > Product Name
    2. Product Nameが「Target名 copy」となっているので無料版の名前に修正する

    f:id:slowquery:20140506201727p:plain

  3. 無料版のビルド時のマクロを設定する

    1. 無料版のTarget > Build Settings -> Apple LLVM 5.X - Preprocessing
    2. Preprocessor MacrosのDebugRelease両方に無料版のビルドフラグを追加する

       FREE_VERSION=1
      

    f:id:slowquery:20140506201738p:plain

  4. コードに#ifdef無料版と有料版の処理を分岐させる

     #ifdef FREE_VERSION
         無料版の処理
     #elif
         有料版の処理
     #endif
    

    ※注意 無料版/有料版のコードを分岐させるには以下のようなパターンがあります。

    1. シングルトンオブジェクトを作って、一度#ifdef内で有料/無料フラグを設定して、それ以降はif文で分岐する
    2. #ifdefで関数内で処理を分岐する
    3. #ifdefで無料版の関数と有料版の関数をわける

    無料版にしか存在しない広告系の関数などは3の方法で消すのがよいです。一方で、関数中のしきい値が異なる程度なら1や2の方法で分岐するのがよいかもしれません。

    #ifdefマクロは強力で便利ですが、Xcodeのシンタックスハイライトを崩すケースや無料/有料両方のコード修正が必要になるケースやリファクタリング機能がうまく使えなくなるケースなど様々なデメリットもあるため、メンテナンスコストを考えて使うと良いと思います。

HerokuでWebSocketを有効にする

HerokuでPublicBeta運用中のWebSocketを使う方法です。

Herokuは2013年の10月にWebSocket通信が行える機能がPublic Betaとしてリリースされました。しかしながら、Public Betaの期間中は初期設定のままでは使えません。

f:id:slowquery:20140506131653p:plain

したがって、以下のようにheroku labsコマンドを使って有効化して使います。

  • アプリを指定しない場合

      heroku labs:enable websockets
    
  • アプリを指定する場合

      heroku labs:enable websockets --app アプリ名
    

これまでHeroku上のアプリでWebSocketを使いたくてもSocket.IOのXHR long pollingなどで代用するのが一般的でしたが、この方法によってWebSocketが使えるようになります。

正式リリース後にはこの作業は不要になると思われます。

Herokuで1つのアプリを複数の環境にデプロイする

Herokuで運用中のアプリのローカルリポジトリからHerokuに複数環境を生成する方法です。

具体的には次のような事を行う場合に便利です。

  • Herokuに本番環境とステージング環境と開発環境を作成
  • Herokuでモバイルアプリの有料アプリのサーバと無料アプリのサーバを別に作る

新たなheroku環境作成

heroku create アプリ名 --remote 新環境名 (例:free, production, staging, test,...) 

例:

heroku create newapp --remote production

新たなheroku環境へデプロイ

git push 新環境名 master

例:

git push production master

Add-onを追加

1つのローカルリポジトリで複数のheroku環境を扱う様になったので、アドオン追加時にはアプリ名の指定が必要になります。

例:NewRelicのAdd-onを追加する場合

heroku addons:add newrelic --app アプリ名

以上

Herokuのアプリをターミナルで削除する

Herokuで運用しているアプリをCLIのターミナル経由で削除する方法です。

ターミナルで削除するとgit remoteの設定を削除する必要がないため、WebのGUI管理画面で削除するよりも楽です。

確認無しで削除する

heroku apps:destroy --app アプリ名 --confirm アプリ名

アプリの作成や削除をスクリプトなどで自動化したい場合はこちらを使います。

確認ありで削除する

heroku apps:destroy --app アプリ名

確認を求められるのでアプリ名を入力します。

MagicalRecord に mogenerator を組み合わせてよいか

CoreDataを使う際に、MagicalRecordに加えてmogeneratorを使う事を推奨しているブログ記事が散見されますが、mogeneratorには以下のようにリジェクトのリスクがあるようです。

筆者はmogeneratorを使っていた事もありましたが、現在は別の理由もあってMagicalRecord単体で使っています。リジェクトのリスクはmogeneratorに限った話しではないですが、注意した方がいいかもしれません。

以上