エンジニア

iOSアプリにGoogle Play Game Servicesを導入する

投稿日:2013年9月20日 更新日:

こんにちは、エンジニアの成田です。

皆さんはGoogle Play Game Servicesをご存知でしょうか?今年のGoogle I/O 2013で発表された、ゲームプラットフォームのコア機能を提供するGoogle社の新サービスです。今回はiOSアプリにGoogle Play Game Servicesを導入する手順を紹介します。

1.Google Play Game Servicesとは

Google社が提供するクロスプラットフォームゲームサービスであり、実績やリーダーボード(いわゆるランキング)、クラウド上へのゲームデータのセーブ、リアルタイムマルチプレイ(Androidのみ)といった、最近のゲームによく搭載されている機能をタブレット・モバイル向けアプリケーションに統合することができます。

ここまでならApple社が提供するGame Centerと趣が似ていますが、本サービスはAndroidだけでなく、iOSや、JavaScriptとRESTを利用することでFlashやHTML5ベースのWebアプリでも使うことができるのです。
これを利用して各プラットフォーム間でセーブや成績などのデータの同期を取れば、Android、iOS、Webアプリをユーザが自由に行き来できる、クロスプラットフォーム対応ゲームが出来上がります。

本稿は導入手順を紹介することが主眼ですので、これ以上の詳細はGoogle Developersのドキュメント(英語)をご覧下さい。

2.導入手順

それでは、導入してみましょう…と言いたいところですが、始める前にいくつかの前提条件があります。

  • XCodeバージョンは4.5以上
  • アプリのターゲットiOSバージョンは6.0以上
  • Google Playデベロッパーに登録済みでデベロッパーコンソールにアクセスできる状態である

よろしいでしょうか?では始めましょう。
今回は下のようなボタンが2つだけの簡単なアプリにGoogle Play Game Servicesを導入し、ボタンを押した時にGoogle+へのサインインと実績の取得が行えるという最低限の機能を搭載してみます。
ss_start

それでは最初に、Google+へのサインインをできるようにしてみます。

手順1

最初にサービスを有効にするため、IDを取得する必要があります。Google Playデベロッパーコンソールに行き、ゲームのエントリーを作成します。
top

エントリーを作成したら、「2.リンク済みアプリ」の画面で「IOSアプリのリンク」を選択し、ガイダンスに従ってアプリの詳細情報を入力していきます。
link

全ての情報を入力し終わると、アプリケーションIDOAuth 2.0クライアントIDが表示されますのでこれらをメモしておきます。
id

さらに、今回は実績の獲得機能を実装しますので、アプリで利用したい実績を登録しておきましょう。テスト用途であれば登録する実績は一つで構いません。
「3.実績」の画面でエントリーを作成し、ここでも実績のIDをメモしておきます。
achieve

最後に「5.テスト」の画面でテストアカウントを登録します。ここで登録したアカウントだけが未公開アプリでGoogle Play Game Servicesのテストを行うことができます(開発者自身のアカウントは既に登録されています)。登録を忘れると未公開アプリでは検証ができないので注意してください。
testuser

手順2

XCode上でプロジェクト設定を開き、Build PhasesタブのLink Binary With Librariesセクションに以下のframeworkを追加します。

  • CoreData.framework
  • Security.framework
  • SystemConfiguration.framework
  • QuartzCore.framework
  • CoreText.framework

以下のURLからGoogle+ iOS SDKをダウンロードして展開します。
https://developers.google.com/+/downloads/

Google+ SDKからプロジェクトに以下を追加します。

  • OpenSource.frameworkフォルダ
  • GooglePlus.bundle
  • GooglePlus.frameworkフォルダ

プロジェクト設定のBuild SettingsタブのLinkingセクション、Other Linker Flagsに -ObjC を追加します。

プロジェクト設定、InfoタブのURL Typesセクションにエントリーを追加し、IdentiferとURL Schemesの両方にプロジェクトのバンドルIDを入力します。

手順3

ViewControllerクラスとAppDelegateクラスに必要な処理を追加していきます。

GPGSViewController.h

#import <UIKit/UIKit.h>
#import <GooglePlus/GooglePlus.h>

// OAuth 2.0クライアントID  
static NSString * const kClientID = @"409281104805.apps.googleusercontent.com";

// ViewControllerクラスでGPPSignInDelegateプロトコルを実装する  
@interface GPGSViewController : UIViewController <GPPSignInDelegate>

- (IBAction)onSignInButtonClick:(UIButton *)sender;
- (IBAction)onAchievementButtonClick:(UIButton *)sender;

@end

GPGSViewController.m

#import "GPGSViewController.h"

@interface GPGSViewController ()

@end

@implementation GPGSViewController

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

// viewDidLoadメソッドでGPPSignInシングルトンインスタンスに各種設定をセットする  
- (void)viewDidLoad
{
    [super viewDidLoad];

    GPPSignIn *signIn = [GPPSignIn sharedInstance];
    signIn.clientID = kClientID;
    signIn.scopes = [NSArray arrayWithObjects:
                     @"https://www.googleapis.com/auth/games",
                     @"https://www.googleapis.com/auth/appstate",
                     nil];
    signIn.language = [[NSLocale preferredLanguages] objectAtIndex:0];
    signIn.delegate = self;
    signIn.shouldFetchGoogleUserID = YES;
}

// GPPSignInDelegateプロトコルのfinishedWithAuth:error:メソッドは  
// Google+サインイン認証が終了した際に一度だけ呼ばれる  
- (void)finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error
{
    NSLog(@"認証終了");
    if (error == nil && auth) {
        NSLog(@"Googleにサインイン成功!認証オブジェクト=%@", auth);

        // サインイン後にやりたいことをここへ書く  

    } else {
        NSLog(@"Googleにサインイン失敗\n\tエラー=%@\n\t認証オブジェクト=%@",error,auth);
    }
}

- (IBAction)onSignInButtonClick:(UIButton *)sender {
    // 認証開始  
    [[GPPSignIn sharedInstance] authenticate];
}

- (IBAction)onAchievementButtonClick:(UIButton *)sender {
}

@end

GPGSAppDelegate.m

#import "GPGSAppDelegate.h"
#import <GooglePlus/GooglePlus.h>

@implementation GPGSAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    return YES;
}

// このメソッドはGoogle+認証プロセスの最後でURLを受け取る  
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
    // GPPURLHandlerのハンドラに引数をそのまま渡す  
    return [GPPURLHandler handleURL:url sourceApplication:sourceApplication annotation:annotation];
}

@end

では、ここまでで一旦プログラムを実行してみましょう。
アプリが起動し、2つあるうちの上のボタン、サインインボタンを押すとGoogle+のサインインフォームが表示されます。Googleアカウントのメールアドレスとパスワードを入力すればアプリのアクセス許可を求める画面が表示されると思います。
ss_auth

許可するとアプリ画面に戻ってきます。XCodeの出力コンソールに「サインイン成功!」という文字が見えればGoogle+へのサインイン成功です。
log

※ここではテストのため、iOS標準のボタンを用いてGoogle+のサインインボタンを作成しましたが、実際にアプリを配布する際にはGoogle+ブランディングガイドラインに従ってサインインボタンを作成する必要があります。
Google+ iOS SDKにはガイドラインに準拠したサインインボタンを提供するGPPSignInButtonクラスが含まれています。
手順4

ここまででGoogle+へサインインできるようになりましたので、次に実績を獲得できるようにしてみましょう。
以下のURLからiOS版のGames SDKをダウンロードして展開してください。
https://developers.google.com/games/services/downloads

Games SDKからプロジェクトに以下を追加します。

  • PlayGameServices.bundle
  • PlayGameServices.frameworkフォルダ

XCode上でアプリケーションの .plist ファイルを開き、上部メニューバーのEditorメニューからAdd itemを選択します。
Keyには"GPGApplicationID"、Typeには"String"、ValueにはアプリケーションIDを入力し、追加します。

次に、 .pch ファイルでPlayGameServicesのヘッダファイルをインポートします。

#import <PlayGameServices/PlayGameServices.h>

最後にViewControllerファイルを再度編集して、実績獲得のコードを書き足します。

#import "GPGSViewController.h"

@interface GPGSViewController ()

@end

@implementation GPGSViewController

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

// viewDidLoadメソッドでGPPSignInシングルトンインスタンスに各種設定をセットする  
- (void)viewDidLoad
{
    [super viewDidLoad];

    GPPSignIn *signIn = [GPPSignIn sharedInstance];
    signIn.clientID = kClientID;
    signIn.scopes = [NSArray arrayWithObjects:
                     @"https://www.googleapis.com/auth/games",
                     @"https://www.googleapis.com/auth/appstate",
                     nil];
    signIn.language = [[NSLocale preferredLanguages] objectAtIndex:0];
    signIn.delegate = self;
    signIn.shouldFetchGoogleUserID = YES;
}

// GPPSignInDelegateプロトコルのfinishedWithAuth:error:メソッドは  
// Google+サインイン認証が終了した際に一度だけ呼ばれる  
- (void)finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error
{
    NSLog(@"認証終了");
    if (error == nil && auth) {
        NSLog(@"Googleにサインイン成功!認証オブジェクト=%@", auth);

        // GPGManagerに準備が整ったことを知らせる  
        [self startGoogleGamesSignIn];

    } else {
        NSLog(@"Googleにサインイン失敗\n\tエラー=%@\n\t認証オブジェクト=%@",error,auth);
    }
}

- (IBAction)onSignInButtonClick:(UIButton *)sender {
    // 認証開始  
    [[GPPSignIn sharedInstance] authenticate];
}

- (IBAction)onAchievementButtonClick:(UIButton *)sender {
    // 実績ID  
    const NSString *achievementId = @"CgkIpZe42PQLEAIQAg";
    // GPGAchievementオブジェクトの取得  
    GPGAchievement *unlockMe = [GPGAchievement achievementWithId:achievementId];
    // unlockAchievementWithCompletionHandlerメソッドを呼べば実績獲得  
    [unlockMe unlockAchievementWithCompletionHandler:^(BOOL newlyUnlocked, NSError *error) {
        if (error) {
            // 何らかのエラー  
        } else if (!newlyUnlocked) {
            // 実績獲得済み  
        } else {
            NSLog(@"実績獲得!");
        }
    }];
}

-(void)startGoogleGamesSignIn
{
    // GPPSignInは既に認証トークンを保持しているのでそれをGPGManagerへ渡す  
    [[GPGManager sharedInstance] signIn:[GPPSignIn sharedInstance]
                     reauthorizeHandler:^(BOOL requiresKeychainWipe, NSError *error) {
                         // ここが呼ばれるのは認証に失敗して再認証が必要になった場合(トークンの期限切れ等)  
                         // 通常はそのまま再認証すればよい  
                         if (requiresKeychainWipe) {
                             [[GPPSignIn sharedInstance] signOut];
                         }
                         [[GPPSignIn sharedInstance] authenticate];
                     }];
}

@end

ではプログラムを実行してみましょう。まずGoogle+にサインインする必要があります。サインインすると次のようなウェルカムポップアップが表示されます。
ss_signin

続いて下の実績獲得ボタンをタップして次のようなポップアップが表示されれば、無事実績獲得です。
ss_achieve

いかがでしたでしょうか。冒頭で触れたとおり、この他にも実現できる機能はまだまだたくさんあります。
アプリへ簡単にゲームのコア機能を追加できるGoogle Play Game Services、今後もサービス拡充が楽しみですね。

採用情報

ワンダープラネットでは、一緒に働く仲間を幅広い職種で募集しております。

-エンジニア
-,

© WonderPlanet Inc.