- PVSM.RU - https://www.pvsm.ru -
Мобильный free-to-play уже практически не обходится без использования социальных сетей в играх. Социальные сети обеспечивают то, что называют виральностью [1] (от англ. viral – вирусный, т.е. способный распространяться как вирус, от одного человека к другому), что позволяет привлекать новых игроков с минимальными затратами. В данной статье мы поделимся опытом интеграции Facebook в игры Alawar на платформе iOS.
В типичной мобильной free-to-play-игре интеграция Facebook предоставляет следующие возможности:
Для того чтобы упростить интеграцию Facebook, мы создали демо-приложение, реализующее практически все необходимое с клиентской стороны.
Демо-приложение написано на C++ (как и большинство наших free-to-play-игр) со вставками на Objective-C и представляет собой простейшее приложение на движке Cocos2d-x [3] (скачать можно здесь [4]). По экрану перемещается прямоугольник и отражается от границ экрана при достижении этих границ.
Управление осуществляется при помощи 4 кнопок: f – авторизация, REQ – отправка запроса друзьям, POST – постинг в таймлайн и LOGOUT. После авторизации на место прямоугольника помещается аватарка пользователя, и добавляется приветственная надпись.
Для компиляции необходимо скачать и установить Facebook SDK [5], добавить фреймворк Facebook SDK в проект в XCode. Мы использовали Facebook SDK версии 3.9.
Для запуска демо-приложения вы должны создать собственное Facebook-приложение на вашем портале разработчика, прописать его идентификатор в plist нашего демо-приложения, а также проделать ряд других несложных операций. Подробнее про это можно прочитать здесь [6].
Первое, с чем сталкиваешься при интеграции Facebook на клиенте – это создание сессии с запросом прав доступа (permissions), разные варианты [7] которых предлагает Facebook. Здесь важно сдержать порыв и не запросить права доступа на все сразу. Хорошим тоном считается запрос прав доступа в момент, когда они действительно необходимы. При создании сессии запросим только базовые права.
+ (NSArray*) getBasicPermissions
{
NSArray* permissions = [[NSArray alloc] initWithObjects: @"user_birthday", nil];
return permissions;
}
В этом случае при авторизации будет показан диалог следующего содержания.
Также следует обратить внимание на то, что нативные для iOS диалоги будут показываться только при условии предварительной авторизации в Facebook на самом устройстве в настройках.
В противном случае iOS попытается использовать приложение Facebook (если оно было установлено из App Store) или откроет Facebook в браузере.
Когда нам потребуются права для опубликования чего-либо в таймлайн или при запросе друзьям, запросим права конкретно на это.
+ (void) requestPublishPermissions
{
if (hasPublishPermissions) return;
NSArray *permissions = [[NSArray alloc] initWithObjects:
@"publish_actions", @"publish_stream", nil];
[[FBSession activeSession] requestNewPublishPermissions:permissions
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error)
{
hasPublishPermissions = [[FBSession activeSession].permissions containsObject:@"publish_actions"] &&
[[FBSession activeSession].permissions containsObject:@"publish_stream"];
if (g_handler) { g_handler->OnGetPublishPermissions(hasPublishPermissions); }
}];
}
В этом случае будет показан следующий диалог.
Важно помнить, что игрок может отказать в правах на опубликование от своего имени, но разрешить авторизацию. Эти случаи необходимо аккуратно обрабатывать.
Реализация запросов к друзьям (app requests) достаточно подробно изложена в документации [8], однако есть ряд тонкостей. При базовой реализации запросов будет показано диалоговое окно, приведенное ниже.
Код этой реализации находится под спойлером.
+ (void) requestFriend
{
// more details here
// https://developers.facebook.com/docs/ios/send-requests-using-ios-sdk/
if (!friendsCache)
{
friendsCache = [[FBFrictionlessRecipientCache alloc] init];
}
[friendsCache prefetchAndCacheForSession:nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:@"Help me, friend!"
title:@"Help me!"
parameters:nil
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
NSLog(@"Error sending request");
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
NSLog(@"User canceled request");
}
else
{
NSDictionary *urlParams = [FacebookController parseURLParams:[resultURL query]];
if (![urlParams valueForKey:@"request"])
{
NSLog(@"User canceled request");
}
else
{
NSLog([NSString stringWithFormat: @"Request Sent: %@", [urlParams valueForKey:@"request"]]);
}
}
}
}
friendCache:friendsCache];
}
Поведением окна запросов можно управлять при помощи параметров, передаваемых после parameters: при вызове диалога. Например, следующий набор параметров позволяет отправить запрос одному известному заранее другу.
NSString *friendId=@"100006530868327";
NSMutableDictionary* params = [[NSMutableDictionary alloc] init];
params[@"to"] = friendId;
Facebook SDK в этом случае покажет видоизменённое окно App requests и даже предложит не показывать окно при следующих запросах этому другу.
Facebook позволяет размещать в таймлайн так называемые истории (stories). Для того чтобы сформировать историю необходимо на странице вашего приложения на портале Facebook-разработчика [9] выбрать в меню слева «Open Graph». Вы увидите 3 вкладки: Stories (Истории), Object Types (Типы объектов) и Action Types (Типы действий). Тип объекта обобщает некоторую группу объектов, которые могут встретиться пользователям вашей игры, например, бейджи. Теперь нужны действия, которые можно применить к объекту «Бейдж», например, действие «Найти». Тип действия и тип объекта могут быть объединены в историю «Find a Badge». Facebook имеет широкие возможности по настройке историй. Подробнее об этом можно узнать здесь [10].
Чтобы получить код для публикации созданной истории из приложения, необходимо кликнуть на надпись «Get Code» справа от названия истории. Выбираем требуемую платформу (iOS SDK в нашем случае) и вкладку «Code for Object». Система сгенерирует код подобный этому:
NSMutableDictionary<FBGraphObject> *object =
[FBGraphObject openGraphObjectForPostWithType:@"aw_test:badge"
title:@"Sample Badge"
image:@"https://fbstatic-a.akamaihd.net/images/devsite/attachment_blank.png"
url:@"http://samples.ogp.me/473380876115865"
description:@""];;
[FBRequestConnection startForPostWithGraphPath:@"me/objects/aw_test:badge"
graphObject:object
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
// handle the result
}];
Во вкладке «Code for Action» можно получить код для действия. Для формирования истории в таймлайн сначала необходимо выполнить создание объекта затем создание действия с этим объектом.
Как ни странно, этот код не работает. Если включить его в проект без модификаций, то будет крэш по необнаруженному селектору в одном из классов. Для того чтобы это исправить, необходимо добавить пару строк в параметры создаваемого объекта Open Graph.
object[@"create_object"] = @"true";
object[@"fbsdk:create_object"] = @"true";
Эта «магия» исправляет крэш, однако постинг в таймлайн по-прежнему не работает. Хорошим признаком того, что все заработало, является возвращенный Facebook идентификатор операции в коллбэке. Идентификатор представляет собой набор цифр (например, 586146891470767). В ответ на код, полученный с портала, приходит строка «true». Это можно исправить, еще немного модифицировав код. В частности, предлагаемый кодогенератором вызов startForPostWithGraphPath необходимо заменить на startForPostOpenGraphObject при создании объекта.
Полный код для постинга в таймлайн можно увидеть под спойлером.
+ (void) createOpenGraphObjectWithType:(NSString *) type
title:(NSString *) title
url:(NSString *) url
image:(NSString *) image
handler: (OpenGraphObjectCreationHandler) handler
{
NSMutableDictionary<FBOpenGraphObject> *object =
[FBGraphObject openGraphObjectForPostWithType:type
title:title
image:image
url:url
description:@""];
object[@"create_object"] = @"true";
object[@"fbsdk:create_object"] = @"true";
[FBRequestConnection startForPostOpenGraphObject:object
completionHandler:^(FBRequestConnection *connection, id result, NSError *error)
{
if (!error && result != nil)
{
NSLog([NSString stringWithFormat:@"Posting object '%@' (id=%@) is created!",
title, [result objectForKey:@"id"]]);
handler([result objectForKey:@"id"]);
}
else
{
NSLog([NSString stringWithFormat:@"Posting object creation error: %@", error]);
}
}];
}
+ (void) postStory
{
NSString* badge_title = @"Blue Badge";
NSString* badge_url = @"http://demo.tom3.html5.services.alawar.com/images/tester/blue_badge.htm";
NSString* badge_image = @"http://demo.tom3.html5.services.alawar.com/images/tester/blue_badge.png";
int rnd = arc4random() % 2;
if (rnd == 0)
{
badge_title = @"Red Badge";
badge_url = @"http://demo.tom3.html5.services.alawar.com/images/tester/red_badge.htm";
badge_image = @"http://demo.tom3.html5.services.alawar.com/images/tester/red_badge.png";
}
[FacebookController createOpenGraphObjectWithType:@"aw_test:badge"
title:badge_title
url:badge_url
image:badge_image
handler:^(NSString *objectId)
{
// action
NSMutableDictionary<FBGraphObject> *action = [FBGraphObject graphObject];
action[@"badge"] = objectId;
action[@"fb:explicitly_shared"] = @"1";
[FBRequestConnection startForPostWithGraphPath:@"me/aw_test:find"
graphObject:action
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error)
{
if (!error && result != nil)
{
NSLog([NSString stringWithFormat:@"Posted (id=%@)!", [result objectForKey:@"id"]]);
}
else
{
NSLog([NSString stringWithFormat:@"Posting error: %@", error]);
}
}];
}];
}
Внимательный читатель обратит внимание, что при выполнении кода для действия был добавлен дополнительный параметр.
action[@"fb:explicitly_shared"] = @"1";
Если этот параметр не выставлен, то созданная история попадет в Recent Activities пользователя, а не в таймлайн. Если все сделано правильно, то в таймлайн пользователя можно будет наблюдать нечто, похожее на рисунок ниже.
Последний момент, с которым необходимо разобраться: где и как хранятся описания объектов. Описание объекта хранится как специальным образом размеченный html-документ на каком-либо открытом сервере. Изображения также размещаются на открытых серверах, откуда их Facebook и загружает.
Если вы решились на интеграцию в игру Facebook помните, что это не минутное дело. Обязательно продумайте, как игра будет взаимодействовать с пользователем через Facebook. В противном случае вы получите вместо полезного инструмента для привлечения игроков очередное приложение досаждающие игрокам. Жалобы от игроков на спам приведут к тому, что Facebook забанит приложение, чего, разумеется, никому не хочется.
Как показывает практика, взять Facebook с наскока получается далеко не у всех. Мы надеемся, что приведенный нами опыт по интеграции этой социальной сети будет вам полезен.
Автор: rokuz
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ios/56105
Ссылки в тексте:
[1] виральностью: http://en.wikipedia.org/wiki/Viral_marketing
[2] free-to-play-игре: https://www.facebook.com/TheTreasuresOfMontezumaBlitzCommunity
[3] Cocos2d-x: http://www.cocos2d-x.org/
[4] здесь: https://github.com/alawar/FacebookSample
[5] Facebook SDK: https://developers.facebook.com/docs/ios/
[6] здесь: https://developers.facebook.com/docs/ios/getting-started/
[7] разные варианты: https://developers.facebook.com/docs/reference/login/#permissions
[8] документации: https://developers.facebook.com/docs/ios/send-requests-using-ios-sdk/
[9] портале Facebook-разработчика: https://developers.facebook.com/apps
[10] здесь: https://developers.facebook.com/docs/opengraph/creating-custom-stories/
[11] Источник: http://habrahabr.ru/post/214043/
Нажмите здесь для печати.