読者です 読者をやめる 読者になる 読者になる

フニゲの開発日記

Electronとか...

iOSアプリの作成

原稿


2013/12/07校正

XCodeの環境設定

 iOSアプリの開発は、XCodeのインストールからです。Windows用のXCodeは無いので、WindowsではiOSのアプリは開発できません。
 iPhoneiPadにプログラムを転送して実行するには有料の開発者登録が必要ですが、XCodeiPhoneシミュレータは優秀なので、だいたい完成してから開発者登録しても遅くないと思います。まあやっぱりシミュレータなのでちょっと遅いですし、ゲームの面白さは実際に指で試してみないとわかりませんから、アプリを審査に提出する時は必ず実機を使ったテストが必要でしょう。
 XCodeMacのAppStoreから普通に入手できます。インストールも特に難しいところはありません。
 XCodeのインストールができたら、Androidの時と同じようにSampleプロジェクトを動かしてみましょう。プロジェクトをビルドするには、Xcodeのメニューから「File -> Open」で~/­cocos2d-x/­projects/­Sample/­proj.iosにあるSample.xcodeprojを開きます。
 XCodeの左上、下の図の青くなってる部分をクリックして、ビルドのターゲット(Sample)とシミュレータの種類(どれでもいい)を選んで、「Product -> Run」すれば、たぶんあっさり動くはずです。

f:id:funige:20131207141117p:plain

iOSネイティブのメソッドを呼び出す

 前章ではフレームワークをハックしてAndroidネイティブのメソッドをjavaScriptから叩く方法を解説しました。iOSではObjective-Cのプログラムに、C++を混ぜて書くことができるので、アプリの構造はjavaScriptC++の2階建てと考えることができます。3階建てのAndroidに比べればだいぶ簡単なのですが、やはりjavaScriptからネイティブのメソッドにアクセスするには工夫が必要です。
 Androidの時はlocalStorageにコマンドをセットしてjavaScript側から送信しました。iOSでも同じコマンドを使ってC++の関数を起動できるようにしましょう。フレームワークを検索すると……ふーん。どうも改造するべき場所は~/­cocos2d-x/­extensions/­LocalStorage/­Local­Storage.cppのようですね。
 localStorage­SetItemのところを以下のように改造して、ここを通ったとき自分で書いた関数(intercept)が呼ばれるようにします。

// LocalStorage.cpp
... 
extern void intercept(const char *key, const char *value); // 追加

/** sets an item in the LS */
void localStorageSetItem( const char *key, const char *value)
{
	intercept(key, value); // 追加
	assert( _initialized );
	
	int ok = sqlite3_bind_text(_stmt_update, 1, key, -1, SQLITE_TRANSIENT);
	ok |= sqlite3_bind_text(_stmt_update, 2, value, -1, SQLITE_TRANSIENT);
    ...

 interceptはグローバル関数なのでどこに置いてもいいのですが、Sample/­proj.iosのRootView­Controller.mmの先頭で定義するのがいいでしょう。

// RootViewController.mm
#import "RootViewController.h"

void showAd() {}
void hideAd() {}

void intercept(const char *key, const char *value) {
    printf("intercept: %s %s¥n", key, value);

    if (strcmp(key, "command") == 0) {
       if (strstr(value, "showAd")) showAd();
        if (strstr(value, "hideAd")) hideAd();
    }
}

@implementation RootViewController
...

こんな感じでしょうか。javaScript側からコマンドを送信して、メッセージがちゃんと流れてくるか確認してください。
 

広告の表示

 Androidと同様に、アイモバイルの広告を表示してみます。なんでも簡単なXCodeですが、ここはAndroidより面倒かもしれません。SDKに付属のドキュメントを見ながら気長に設定しましょう。

 iOS用のSDKをアイモバイルのサイトからダウンロードしたら、解凍したフォルダをプロジェクトにコピーします。

$ cp -r ~/Downloads/imobile_for_SP_app_iOS_SDK_1.5.5 ~/cocos2d-x/projects/Sample

 XCodeに移って、コピーしたフォルダに含まれるフレームワークを追加します。左側のツリービューのいちばん左上にある「Sample」をクリックして、プロジェクトの設定画面を表示して下さい。Generalタブの一番下にある「Linked Frameworks and Libraries」という所がフレームワークを追加する場所です。最後の行の「+」ボタンをクリックして「Add Other...」を押して、フォルダ(imobile_­for_­SP_­app_­iOSSDK_­1.5.5)のlibの下にあるフレームワークを全てインポートします。以下の3つです。

  • ASIHTTPRequest.framework
  • imobileAds.framework
  • JSONKit.framework

 あと、以下のフレームワーク(とライブラリ)も必要なので、これも「+」ボタンから追加して下さい。

  • AdSupport.framework
  • SystemConfiguration.framework
  • MobileCoreServices.framework
  • libz.dylib
  • CFNetwork.framework

 AdSupport.frameworkはiOS6から加わったフレームワークなので、iOS5にはありません。下の図のようにRequiredをOptionalに変更しておくと、iOS5でも実行できるアプリになるそうです。

f:id:funige:20131207141212p:plain

 合計8つのファイルがリストに追加されたのを確認して下さい。
 次に、RootViewController.mmに広告を表示するコードを追加します。ViewDidLoadで初期化すればいいような気がするのですが、なぜか動かないのでViewWillAppearに書いています。

// RootViewController.mm
#import "RootViewController.h"

#import "imobileAds/IMAdView.h"
static IMobileAdView *adView = nil;
..

// viewDidLoadの下にviewWillAppearメソッドを追加する
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if (!adView) {
       CGRect frame = CGRectMake(0, 0, 320, 50);
        adView = [[IMobileAdView alloc]
                initWithFrame:frame
                publisherId:[パブリッシャーID]
                mediaId:[メディアID]
                spotId:[スポットID]
                testMode:YES];

       [self.view addSubview:adView];
    }
}
...

 これでコンパイルすれば動くはずですが……何も表示されませんねえ。ログをよく見ると「[__NSCFString objectFromJSONString]: unrecognized selector sent to instance」とかエラーメッセージが出ています。
 こういう場合は、エラーメッセージをそのままブラウザのアドレスバーにペーストして検索するとヒントが見つかることが多いです。よく検索にひっかかるサイトはStack Overflow (stackoverflow.com) です。英語のサイトですが、まあ大抵のエラーは誰かが先に経験していることがわかります。
 ふむふむ。今回のエラーでは、どうもリンクの設定に-ObjCというフラグが無いのが原因のようです。ああ、SDK付属のドキュメントにちゃんと書いてありました。ごめんなさいアイモバイルさん。
 プロジェクトの設定画面でBuild Settingsタブを選択すると、Linkingの所に「Other Linker Flag」という欄があります。ここに「-ObjC」を追加して下さい。

f:id:funige:20131207141235p:plain

 これでうまくいきました。
 showAd()とhideAd()の実装は、以下のようになるでしょう。javaScript側から呼び出す方法は、Androidの場合とまったく同じです。

void showAd() {
    adView.hidden = NO;
}

void hideAd() {
    adView.hidden = YES;
}
広告を非表示にする