FBUnityInterface.mm 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083
  1. // Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
  2. //
  3. // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
  4. // copy, modify, and distribute this software in source code or binary form for use
  5. // in connection with the web services and APIs provided by Facebook.
  6. //
  7. // As with any software that integrates with the Facebook platform, your use of
  8. // this software is subject to the Facebook Developer Principles and Policies
  9. // [http://developers.facebook.com/policy/]. This copyright notice shall be
  10. // included in all copies or substantial portions of the software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  14. // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  15. // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  16. // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  17. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  18. #import <SafariServices/SafariServices.h>
  19. #import <AuthenticationServices/AuthenticationServices.h>
  20. #import <FBSDKCoreKit/FBSDKCoreKit-Swift.h>
  21. #import <FBSDKLoginKit/FBSDKLoginKit-Swift.h>
  22. #import <Foundation/NSJSONSerialization.h>
  23. #include "FBUnityInterface.h"
  24. #include "FBUnitySDKDelegate.h"
  25. #include "FBUnityUtility.h"
  26. #include "FBSDK+Internal.h"
  27. static BOOL _fastAppSwitchEnabled = NO;
  28. @interface FBUnityInterface()
  29. @property (nonatomic, copy) NSString *openURLString;
  30. // Declared explicitly so @selector(...) resolves under the Swift Xcode project type, where these
  31. // are no longer inherited from the AppDelegateListener protocol.
  32. - (void)didFinishLaunching:(NSNotification *)notification;
  33. - (void)didBecomeActive:(NSNotification *)notification;
  34. #if UNITY_XCODE_PROJECT_TYPE_SWIFT
  35. // Swift-only: no AppDelegateListener counterpart to inherit this from.
  36. - (void)onSceneOpenURLContexts:(NSNotification *)notification;
  37. #endif
  38. @end
  39. @implementation FBUnityInterface
  40. #pragma mark Object Initialization
  41. + (FBUnityInterface *)sharedInstance
  42. {
  43. static dispatch_once_t pred;
  44. static FBUnityInterface *shared = nil;
  45. dispatch_once(&pred, ^{
  46. shared = [[FBUnityInterface alloc] init];
  47. shared.shareDialogMode = ShareDialogMode::AUTOMATIC;
  48. });
  49. return shared;
  50. }
  51. + (void)load
  52. {
  53. #if UNITY_XCODE_PROJECT_TYPE_SWIFT
  54. [[FBUnityInterface sharedInstance] registerForLifecycleNotifications];
  55. #else
  56. UnityRegisterAppDelegateListener([FBUnityInterface sharedInstance]);
  57. #endif
  58. }
  59. #pragma mark - App (Delegate) Lifecycle
  60. // Under the Objective-C Xcode project type, didBecomeActive: and onOpenURL: are called by Unity's
  61. // AppController because we implement <AppDelegateListener> and registered via
  62. // UnityRegisterAppDelegateListener(...) above. The Swift project type has no AppDelegateListener,
  63. // so the same methods are driven from NotificationCenter instead.
  64. #if UNITY_XCODE_PROJECT_TYPE_SWIFT
  65. - (void)registerForLifecycleNotifications
  66. {
  67. NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  68. [center addObserver:self
  69. selector:@selector(didFinishLaunching:)
  70. name:UIApplicationDidFinishLaunchingNotification
  71. object:nil];
  72. [center addObserver:self
  73. selector:@selector(didBecomeActive:)
  74. name:UIApplicationDidBecomeActiveNotification
  75. object:nil];
  76. // Literal names: the UnityNotifications Swift header exists only under the Swift project type.
  77. [center addObserver:self
  78. selector:@selector(onSceneOpenURLContexts:)
  79. name:@"UnitySceneOpenURLContexts"
  80. object:nil];
  81. }
  82. // A scene can be handed several URLs at once, so each context is offered to the SDK in turn.
  83. - (void)onSceneOpenURLContexts:(NSNotification *)notification
  84. {
  85. id contexts = notification.userInfo[@"UnityNotificationsOpenURLContextsKey"];
  86. if (![contexts isKindOfClass:[NSSet class]]) {
  87. return;
  88. }
  89. for (UIOpenURLContext *context in (NSSet *)contexts) {
  90. if (![context isKindOfClass:[UIOpenURLContext class]]) {
  91. continue;
  92. }
  93. // sourceApplication and annotation live on context.options here, not the notification userInfo.
  94. BOOL isHandledByFBSDK = [[FBSDKApplicationDelegate sharedInstance] application:[UIApplication sharedApplication]
  95. openURL:context.URL
  96. sourceApplication:context.options.sourceApplication
  97. annotation:context.options.annotation];
  98. if (!isHandledByFBSDK) {
  99. [FBUnityInterface sharedInstance].openURLString = [context.URL absoluteString];
  100. }
  101. }
  102. }
  103. #endif
  104. - (void)didFinishLaunching:(NSNotification *)notification
  105. {
  106. [[FBSDKApplicationDelegate sharedInstance] application:[UIApplication sharedApplication]
  107. didFinishLaunchingWithOptions:notification.userInfo];
  108. }
  109. - (void)didBecomeActive:(NSNotification *)notification
  110. {
  111. }
  112. - (void)onOpenURL:(NSNotification *)notification
  113. {
  114. NSURL *url = notification.userInfo[@"url"];
  115. BOOL isHandledByFBSDK = [[FBSDKApplicationDelegate sharedInstance] application:[UIApplication sharedApplication]
  116. openURL:url
  117. sourceApplication:notification.userInfo[@"sourceApplication"]
  118. annotation:notification.userInfo[@"annotation"]];
  119. if (!isHandledByFBSDK) {
  120. [FBUnityInterface sharedInstance].openURLString = [url absoluteString];
  121. }
  122. }
  123. #pragma mark - Implementation
  124. - (void)configureAppId:(const char *)appId
  125. frictionlessRequests:(bool)frictionlessRequests
  126. urlSuffix:(const char *)urlSuffix
  127. {
  128. self.useFrictionlessRequests = frictionlessRequests;
  129. if(appId) {
  130. [FBSDKSettings.sharedSettings setAppID:[FBUnityUtility stringFromCString:appId]];
  131. }
  132. if(urlSuffix && strlen(urlSuffix) > 0) {
  133. [FBSDKSettings.sharedSettings setAppURLSchemeSuffix:[FBUnityUtility stringFromCString:urlSuffix]];
  134. }
  135. NSDictionary *userData = [self getAccessTokenUserData] ?: @{};
  136. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnInitComplete userData:userData requestId:0];
  137. }
  138. - (void)logInWithPublishPermissions:(int) requestId
  139. scope:(const char *)scope
  140. {
  141. [self startLogin:requestId scope:scope isPublishPermLogin:YES];
  142. }
  143. - (void)logInWithReadPermissions:(int) requestId
  144. scope:(const char *)scope
  145. {
  146. [self startLogin:requestId scope:scope isPublishPermLogin:NO];
  147. }
  148. - (void)startLogin:(int) requestId
  149. scope:(const char *)scope
  150. isPublishPermLogin:(BOOL)isPublishPermLogin
  151. {
  152. NSString *scopeStr = [FBUnityUtility stringFromCString:scope];
  153. NSArray *permissions = nil;
  154. if(scope && strlen(scope) > 0) {
  155. permissions = [scopeStr componentsSeparatedByString:@","];
  156. }
  157. void (^loginHandler)(FBSDKLoginManagerLoginResult *,NSError *) = ^(FBSDKLoginManagerLoginResult *result, NSError *error) {
  158. if (error) {
  159. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnLoginComplete error:error requestId:requestId];
  160. return;
  161. } else if (result.isCancelled) {
  162. [FBUnityUtility sendCancelToUnity:FBUnityMessageName_OnLoginComplete requestId:requestId];
  163. return;
  164. }
  165. if ([self tryCompleteLoginWithRequestId:requestId]) {
  166. return;
  167. } else {
  168. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnLoginComplete errorMessage:@"Unknown login error" requestId:requestId];
  169. }
  170. };
  171. FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
  172. [login logInWithPermissions:permissions
  173. fromViewController:nil
  174. handler:loginHandler];
  175. }
  176. - (void)loginWithTrackingPreference:(int)requestId
  177. scope:(const char *)scope
  178. tracking:(const char *)tracking
  179. nonce:(const char *)nonce
  180. {
  181. NSString *scopeStr = [FBUnityUtility stringFromCString:scope];
  182. NSArray *permissions = nil;
  183. if(scope && strlen(scope) > 0) {
  184. permissions = [scopeStr componentsSeparatedByString:@","];
  185. }
  186. NSString *trackingStr = [FBUnityUtility stringFromCString:tracking];
  187. NSString *nonceStr = nil;
  188. if (nonce) {
  189. nonceStr = [FBUnityUtility stringFromCString:nonce];
  190. }
  191. FBSDKLoginConfiguration *config;
  192. if (nonce) {
  193. config = [[FBSDKLoginConfiguration alloc] initWithPermissions:permissions tracking:([trackingStr isEqualToString:@"enabled"] ? FBSDKLoginTrackingEnabled : FBSDKLoginTrackingLimited) nonce:nonceStr appSwitch:_fastAppSwitchEnabled ? FBSDKAppSwitchEnabled : FBSDKAppSwitchDisabled];
  194. } else {
  195. config = [[FBSDKLoginConfiguration alloc] initWithPermissions:permissions tracking:([trackingStr isEqualToString:@"enabled"] ? FBSDKLoginTrackingEnabled : FBSDKLoginTrackingLimited) appSwitch:_fastAppSwitchEnabled ? FBSDKAppSwitchEnabled : FBSDKAppSwitchDisabled];
  196. }
  197. void (^loginHandler)(FBSDKLoginManagerLoginResult *,NSError *) = ^(FBSDKLoginManagerLoginResult *result, NSError *error) {
  198. if (error) {
  199. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnLoginComplete error:error requestId:requestId];
  200. return;
  201. } else if (result.isCancelled) {
  202. [FBUnityUtility sendCancelToUnity:FBUnityMessageName_OnLoginComplete requestId:requestId];
  203. return;
  204. }
  205. if ([self tryCompleteLoginWithRequestId:requestId]) {
  206. return;
  207. } else {
  208. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnLoginComplete errorMessage:@"Unknown login error" requestId:requestId];
  209. }
  210. };
  211. FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
  212. [login logInFromViewController:nil configuration:config completion:loginHandler];
  213. }
  214. - (void)logOut
  215. {
  216. FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
  217. [login logOut];
  218. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnLogoutComplete userData:@{} requestId:0];
  219. }
  220. - (void)appRequestWithRequestId:(int)requestId
  221. message:(const char *)message
  222. actionType:(const char *)actionType
  223. objectId:(const char *)objectId
  224. to:(const char **)to
  225. toLength:(int)toLength
  226. filters:(const char *)filters
  227. data:(const char *)data
  228. title:(const char *)title
  229. {
  230. FBSDKGameRequestContent *content = [[FBSDKGameRequestContent alloc] init];
  231. content.message = [FBUnityUtility stringFromCString:message];
  232. content.actionType = [FBUnityUtility gameRequestActionTypeFromString:[FBUnityUtility stringFromCString:actionType]];
  233. content.objectID = [FBUnityUtility stringFromCString:objectId];
  234. if(to && toLength) {
  235. NSMutableArray *toArray = [NSMutableArray array];
  236. for(int i = 0; i < toLength; i++) {
  237. [toArray addObject:[FBUnityUtility stringFromCString:to[i]]];
  238. }
  239. content.recipients = toArray;
  240. }
  241. content.filters = [FBUnityUtility gameRequestFilterFromString:[FBUnityUtility stringFromCString:filters]];
  242. content.data = [FBUnityUtility stringFromCString:data];
  243. content.title = [FBUnityUtility stringFromCString:title];
  244. FBUnitySDKDelegate *delegate = [FBUnitySDKDelegate instanceWithRequestID:requestId];
  245. NSError *error;
  246. FBSDKGameRequestDialog *dialog = [[FBSDKGameRequestDialog alloc] initWithContent:content delegate:delegate];
  247. dialog.isFrictionlessRequestsEnabled = self.useFrictionlessRequests;
  248. if (![dialog validateWithError:&error]) {
  249. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnAppRequestsComplete error:error requestId:requestId];
  250. }
  251. if (![dialog show]) {
  252. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnAppRequestsComplete errorMessage:@"Failed to show request dialog" requestId:requestId];
  253. }
  254. }
  255. - (void)shareLinkWithRequestId:(int)requestId
  256. contentURL:(const char *)contentURL
  257. contentTitle:(const char *)contentTitle
  258. contentDescription:(const char *)contentDescription
  259. photoURL:(const char *)photoURL
  260. {
  261. FBSDKShareLinkContent *linkContent = [[FBSDKShareLinkContent alloc] init];
  262. NSString *contentUrlStr = [FBUnityUtility stringFromCString:contentURL];
  263. if (contentUrlStr) {
  264. linkContent.contentURL = [NSURL URLWithString:contentUrlStr];
  265. }
  266. [self shareContentWithRequestId:requestId
  267. shareContent:linkContent
  268. dialogMode:[self getDialogMode]];
  269. }
  270. - (void)shareFeedWithRequestId:(int)requestId
  271. toId:(const char *)toID
  272. link:(const char *)link
  273. linkName:(const char *)linkName
  274. linkCaption:(const char *)linkCaption
  275. linkDescription:(const char *)linkDescription
  276. picture:(const char *)picture
  277. mediaSource:(const char *)mediaSource
  278. {
  279. FBSDKShareLinkContent *linkContent = [[FBSDKShareLinkContent alloc] init];
  280. NSString *contentUrlStr = [FBUnityUtility stringFromCString:link];
  281. if (contentUrlStr) {
  282. linkContent.contentURL = [NSURL URLWithString:contentUrlStr];
  283. }
  284. NSMutableDictionary *feedParameters = [[NSMutableDictionary alloc] init];
  285. NSString *toStr = [FBUnityUtility stringFromCString:toID];
  286. if (toStr) {
  287. [feedParameters setObject:toStr forKey:@"to"];
  288. }
  289. NSString *captionStr = [FBUnityUtility stringFromCString:linkCaption];
  290. if (captionStr) {
  291. [feedParameters setObject:captionStr forKey:@"caption"];
  292. }
  293. NSString *sourceStr = [FBUnityUtility stringFromCString:mediaSource];
  294. if (sourceStr) {
  295. [feedParameters setObject:sourceStr forKey:@"source"];
  296. }
  297. [linkContent addParameters:feedParameters bridgeOptions:FBSDKShareBridgeOptionsDefault];
  298. [self shareContentWithRequestId:requestId
  299. shareContent:linkContent
  300. dialogMode:FBSDKShareDialogModeFeedWeb];
  301. }
  302. - (void)shareContentWithRequestId:(int)requestId
  303. shareContent:(FBSDKShareLinkContent *)linkContent
  304. dialogMode:(FBSDKShareDialogMode)dialogMode
  305. {
  306. FBUnitySDKDelegate *delegate = [FBUnitySDKDelegate instanceWithRequestID:requestId];
  307. FBSDKShareDialog *dialog = [[FBSDKShareDialog alloc] initWithViewController:nil
  308. content:linkContent
  309. delegate:delegate];
  310. dialog.mode = dialogMode;
  311. NSError *error;
  312. if (![dialog validateWithError:&error]) {
  313. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnShareLinkComplete error:error requestId:requestId];
  314. }
  315. if (![dialog show]) {
  316. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnShareLinkComplete errorMessage:@"Failed to show share dialog" requestId:requestId];
  317. }
  318. }
  319. - (FBSDKShareDialogMode)getDialogMode
  320. {
  321. switch (self.shareDialogMode) {
  322. case ShareDialogMode::AUTOMATIC:
  323. return FBSDKShareDialogModeAutomatic;
  324. case ShareDialogMode::NATIVE:
  325. return FBSDKShareDialogModeNative;
  326. case ShareDialogMode::WEB:
  327. return FBSDKShareDialogModeWeb;
  328. case ShareDialogMode::FEED:
  329. return FBSDKShareDialogModeFeedWeb;
  330. default:
  331. NSLog(@"Unexpected dialog mode: %@", [NSNumber numberWithInt:self.shareDialogMode]);
  332. return FBSDKShareDialogModeAutomatic;
  333. }
  334. }
  335. - (BOOL)tryCompleteLoginWithRequestId:(int) requestId
  336. {
  337. NSMutableDictionary *userData = [[NSMutableDictionary alloc] init];
  338. NSDictionary *accessTokenUserData = [self getAccessTokenUserData];
  339. NSDictionary *authenticationTokenUserData = [self getAuthenticationTokenUserData];
  340. if (accessTokenUserData) {
  341. [userData addEntriesFromDictionary:accessTokenUserData];
  342. }
  343. if (authenticationTokenUserData) {
  344. [userData addEntriesFromDictionary:authenticationTokenUserData];
  345. }
  346. if (userData) {
  347. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnLoginComplete
  348. userData:[userData copy]
  349. requestId:requestId];
  350. return YES;
  351. } else {
  352. return NO;
  353. }
  354. }
  355. - (NSDictionary *)getAccessTokenUserData
  356. {
  357. FBSDKAccessToken *token = [FBSDKAccessToken currentAccessToken];
  358. if (token) {
  359. // Old v3 sdk tokens don't always contain a UserID. If the user ID is null
  360. // treat the token as bad and clear it. These values are all required
  361. // on c# side for initlizing a token.
  362. NSDictionary *userData = [FBUnityUtility getUserDataFromAccessToken:token];
  363. if (userData) {
  364. return userData;
  365. } else {
  366. // The token is missing a required value. Clear the token
  367. [[[FBSDKLoginManager alloc] init] logOut];
  368. }
  369. }
  370. return nil;
  371. }
  372. - (NSDictionary *)getAuthenticationTokenUserData
  373. {
  374. FBSDKAuthenticationToken *token = [FBSDKAuthenticationToken currentAuthenticationToken];
  375. if (token.tokenString && token.nonce) {
  376. return @{
  377. @"auth_token_string": token.tokenString,
  378. @"auth_nonce": token.nonce
  379. };
  380. }
  381. return nil;
  382. }
  383. - (void)refreshLimitedLogin:(int)requestId
  384. fallbackPolicy:(int)fallbackPolicy
  385. {
  386. FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
  387. [login refreshLimitedLoginFromViewController:nil
  388. fallbackPolicy:(FBSDKRefreshFallbackPolicy)fallbackPolicy
  389. completion:^(FBSDKProfile *profile, NSError *error) {
  390. if (error) {
  391. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnRefreshLimitedLoginComplete error:error requestId:requestId];
  392. return;
  393. }
  394. // The refreshed Profile is cached as FBSDKProfile.currentProfile and read on
  395. // the C# side via FB.Mobile.CurrentProfile(). Send back the refreshed
  396. // authentication token so LoginResult can update AuthenticationToken.Current.
  397. NSMutableDictionary *userData = [[NSMutableDictionary alloc] init];
  398. NSDictionary *authenticationTokenUserData = [self getAuthenticationTokenUserData];
  399. if (authenticationTokenUserData) {
  400. [userData addEntriesFromDictionary:authenticationTokenUserData];
  401. }
  402. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnRefreshLimitedLoginComplete
  403. userData:[userData copy]
  404. requestId:requestId];
  405. }];
  406. }
  407. @end
  408. #pragma mark - Actual Unity C# interface (extern C)
  409. extern "C" {
  410. void IOSFBSendViewHierarchy(const char *_tree )
  411. {
  412. Class FBUnityUtility = NSClassFromString(@"FBSDKCodelessIndexer");
  413. [FBUnityUtility performSelector:NSSelectorFromString(@"uploadIndexing:")
  414. withObject:[NSString stringWithUTF8String:_tree]];
  415. }
  416. void IOSFBInit(const char *_appId, bool _frictionlessRequests, const char *_urlSuffix, const char *_userAgentSuffix)
  417. {
  418. // Set the user agent before calling init to ensure that calls made during
  419. // init use the user agent suffix.
  420. [FBSDKSettings.sharedSettings setUserAgentSuffix:[FBUnityUtility stringFromCString:_userAgentSuffix]];
  421. [[FBUnityInterface sharedInstance] configureAppId:_appId
  422. frictionlessRequests:_frictionlessRequests
  423. urlSuffix:_urlSuffix];
  424. [[FBSDKAppEvents shared] setIsUnityInitialized:true];
  425. [[FBSDKAppEvents shared] sendEventBindingsToUnity];
  426. }
  427. void IOSFBEnableProfileUpdatesOnAccessTokenChange(bool enable)
  428. {
  429. [FBSDKProfile enableUpdatesOnAccessTokenChange:enable];
  430. }
  431. void IOSFBLoginWithTrackingPreference(int requestId, const char *scope, const char *tracking, const char *nonce)
  432. {
  433. [[FBUnityInterface sharedInstance] loginWithTrackingPreference:requestId scope:scope
  434. tracking:tracking
  435. nonce:nonce];
  436. }
  437. void IOSFBLogInWithReadPermissions(int requestId,
  438. const char *scope)
  439. {
  440. [[FBUnityInterface sharedInstance] logInWithReadPermissions:requestId scope:scope];
  441. }
  442. void IOSFBLogInWithPublishPermissions(int requestId,
  443. const char *scope)
  444. {
  445. [[FBUnityInterface sharedInstance] logInWithPublishPermissions:requestId scope:scope];
  446. }
  447. void IOSFBLogOut()
  448. {
  449. [[FBUnityInterface sharedInstance] logOut];
  450. }
  451. char* IOSFBCurrentAuthenticationToken()
  452. {
  453. FBSDKAuthenticationToken *token = [FBSDKAuthenticationToken currentAuthenticationToken];
  454. NSString *str = @"";
  455. if (token.tokenString && token.nonce) {
  456. try {
  457. NSData *jsonData = [NSJSONSerialization dataWithJSONObject:@{
  458. @"auth_token_string": token.tokenString,
  459. @"auth_nonce": token.nonce
  460. } options:NSJSONWritingPrettyPrinted error:nil];
  461. if (jsonData) {
  462. str = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
  463. }
  464. } catch (NSException *exception) {
  465. NSLog(@"Fail to parse AuthenticationToken");
  466. }
  467. }
  468. const char* string = [str UTF8String];
  469. char* res = (char*)malloc(strlen(string) + 1);
  470. strcpy(res, string);
  471. return res;
  472. }
  473. char* IOSFBCurrentProfile()
  474. {
  475. FBSDKProfile *profile = [FBSDKProfile currentProfile];
  476. NSString *str = @"";
  477. NSMutableDictionary<NSString *, id> *data = [NSMutableDictionary new];
  478. if (profile.userID) {
  479. data[@"userID"] = profile.userID;
  480. }
  481. if (profile.firstName) {
  482. data[@"firstName"] = profile.firstName;
  483. }
  484. if (profile.middleName) {
  485. data[@"middleName"] = profile.middleName;
  486. }
  487. if (profile.lastName) {
  488. data[@"lastName"] = profile.lastName;
  489. }
  490. if (profile.name) {
  491. data[@"name"] = profile.name;
  492. }
  493. if (profile.email) {
  494. data[@"email"] = profile.email;
  495. }
  496. if (profile.imageURL) {
  497. data[@"imageURL"] = profile.imageURL.absoluteString;
  498. }
  499. if (profile.linkURL) {
  500. data[@"linkURL"] = profile.linkURL.absoluteString;
  501. }
  502. if (profile.friendIDs) {
  503. data[@"friendIDs"] = [profile.friendIDs componentsJoinedByString:@","];
  504. }
  505. if (profile.birthday) {
  506. data[@"birthday"] = [NSString stringWithFormat:@"%@", @((time_t)[profile.birthday timeIntervalSince1970])];
  507. }
  508. if (profile.ageRange) {
  509. if (profile.ageRange.min) {
  510. data[@"ageMin"] = profile.ageRange.min.stringValue;
  511. }
  512. if (profile.ageRange.max) {
  513. data[@"ageMax"] = profile.ageRange.max.stringValue;
  514. }
  515. }
  516. if (profile.hometown) {
  517. data[@"hometown_id"] = profile.hometown.id;
  518. data[@"hometown_name"] = profile.hometown.name;
  519. }
  520. if (profile.location) {
  521. data[@"location_id"] = profile.location.id;
  522. data[@"location_name"] = profile.location.name;
  523. }
  524. if (profile.gender) {
  525. data[@"gender"] = profile.gender;
  526. }
  527. try {
  528. NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:nil];
  529. if (jsonData) {
  530. str = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
  531. }
  532. } catch (NSException *exception) {
  533. NSLog(@"Fail to parse Profile");
  534. }
  535. const char* string = [str UTF8String];
  536. char* res = (char*)malloc(strlen(string) + 1);
  537. strcpy(res, string);
  538. return res;
  539. }
  540. void IOSFBSetPushNotificationsDeviceTokenString(const char *token)
  541. {
  542. [[FBSDKAppEvents shared] setPushNotificationsDeviceTokenString:[FBUnityUtility stringFromCString:token]];
  543. }
  544. void IOSFBSetShareDialogMode(int mode)
  545. {
  546. [FBUnityInterface sharedInstance].shareDialogMode = static_cast<ShareDialogMode>(mode);
  547. }
  548. void IOSFBAppRequest(int requestId,
  549. const char *message,
  550. const char *actionType,
  551. const char *objectId,
  552. const char **to,
  553. int toLength,
  554. const char *filters,
  555. const char **excludeIds, //not supported on mobile
  556. int excludeIdsLength, //not supported on mobile
  557. bool hasMaxRecipients, //not supported on mobile
  558. int maxRecipients, //not supported on mobile
  559. const char *data,
  560. const char *title)
  561. {
  562. [[FBUnityInterface sharedInstance] appRequestWithRequestId: requestId
  563. message: message
  564. actionType: actionType
  565. objectId: objectId
  566. to: to
  567. toLength: toLength
  568. filters: filters
  569. data: data
  570. title: title];
  571. }
  572. // Swift-only: the cold-start URL arrives via Application.absoluteURL from C#, not a notification.
  573. #if UNITY_XCODE_PROJECT_TYPE_SWIFT
  574. void IOSFBHandleLaunchURL(const char *urlString)
  575. {
  576. if ([FBUnityInterface sharedInstance].openURLString != nil) {
  577. return;
  578. }
  579. NSString *absoluteString = [FBUnityUtility stringFromCString:urlString];
  580. if (absoluteString.length == 0) {
  581. return;
  582. }
  583. NSURL *url = [NSURL URLWithString:absoluteString];
  584. if (url == nil) {
  585. return;
  586. }
  587. // Offered to the SDK first, like the warm path, so a Login redirect is not seen as an app link.
  588. BOOL isHandledByFBSDK = [[FBSDKApplicationDelegate sharedInstance] application:[UIApplication sharedApplication]
  589. openURL:url
  590. sourceApplication:nil
  591. annotation:nil];
  592. if (!isHandledByFBSDK) {
  593. [FBUnityInterface sharedInstance].openURLString = absoluteString;
  594. }
  595. }
  596. #else
  597. // No-op: onOpenURL: already delivered it, and openURLString is empty when FBSDK claimed the URL.
  598. void IOSFBHandleLaunchURL(__unused const char *urlString)
  599. {
  600. }
  601. #endif
  602. void IOSFBGetAppLink(int requestId)
  603. {
  604. NSURL *url = [NSURL URLWithString:[FBUnityInterface sharedInstance].openURLString];
  605. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnGetAppLinkComplete
  606. userData:[FBUnityUtility appLinkDataFromUrl:url]
  607. requestId:requestId];
  608. [FBUnityInterface sharedInstance].openURLString = nil;
  609. }
  610. void IOSFBShareLink(int requestId,
  611. const char *contentURL,
  612. const char *contentTitle,
  613. const char *contentDescription,
  614. const char *photoURL)
  615. {
  616. [[FBUnityInterface sharedInstance] shareLinkWithRequestId:requestId
  617. contentURL:contentURL
  618. contentTitle:contentTitle
  619. contentDescription:contentDescription
  620. photoURL:photoURL];
  621. }
  622. void IOSFBFeedShare(int requestId,
  623. const char *toId,
  624. const char *link,
  625. const char *linkName,
  626. const char *linkCaption,
  627. const char *linkDescription,
  628. const char *picture,
  629. const char *mediaSource)
  630. {
  631. [[FBUnityInterface sharedInstance] shareFeedWithRequestId:requestId
  632. toId:toId
  633. link:link
  634. linkName:linkName
  635. linkCaption:linkCaption
  636. linkDescription:linkDescription
  637. picture:picture
  638. mediaSource:mediaSource];
  639. }
  640. void IOSFBAppEventsActivateApp()
  641. {
  642. [FBSDKAppEvents.shared activateApp];
  643. }
  644. void IOSFBAppEventsLogEvent(const char *eventName,
  645. double valueToSum,
  646. int numParams,
  647. const char **paramKeys,
  648. const char **paramVals)
  649. {
  650. NSDictionary *params = [FBUnityUtility dictionaryFromKeys:paramKeys values:paramVals length:numParams];
  651. [[FBSDKAppEvents shared] logEvent:[FBUnityUtility stringFromCString:eventName] valueToSum:valueToSum parameters:params];
  652. }
  653. void IOSFBAppEventsLogPurchase(double amount,
  654. const char *currency,
  655. int numParams,
  656. const char **paramKeys,
  657. const char **paramVals)
  658. {
  659. NSDictionary *params = [FBUnityUtility dictionaryFromKeys:paramKeys values:paramVals length:numParams];
  660. [[FBSDKAppEvents shared] logPurchase:amount currency:[FBUnityUtility stringFromCString:currency] parameters:params];
  661. }
  662. void IOSFBAppEventsSetLimitEventUsage(BOOL limitEventUsage)
  663. {
  664. [FBSDKSettings.sharedSettings setIsEventDataUsageLimited:limitEventUsage];
  665. }
  666. void IOSFBAutoLogAppEventsEnabled(BOOL autoLogAppEventsEnabledID)
  667. {
  668. [FBSDKSettings.sharedSettings setAutoLogAppEventsEnabled:autoLogAppEventsEnabledID];
  669. }
  670. void IOSFBAdvertiserIDCollectionEnabled(BOOL advertiserIDCollectionEnabledID)
  671. {
  672. [FBSDKSettings.sharedSettings setAdvertiserIDCollectionEnabled:advertiserIDCollectionEnabledID];
  673. }
  674. BOOL IOSFBAdvertiserTrackingEnabled(BOOL advertiserTrackingEnabled)
  675. {
  676. [FBSDKSettings.sharedSettings setAdvertiserTrackingEnabled:advertiserTrackingEnabled];
  677. return [FBSDKSettings.sharedSettings isAdvertiserTrackingEnabled];
  678. }
  679. BOOL IOSFBDomainErrorEnabled(BOOL domainErrorEnabled)
  680. {
  681. [FBSDKSettings.sharedSettings setIsDomainErrorEnabled:domainErrorEnabled];
  682. return [FBSDKSettings.sharedSettings isDomainErrorEnabled];
  683. }
  684. BOOL IOSFBFastAppSwitchEnabled(BOOL fastAppSwitchEnabled)
  685. {
  686. _fastAppSwitchEnabled = fastAppSwitchEnabled;
  687. return _fastAppSwitchEnabled;
  688. }
  689. char* IOSFBSdkVersion()
  690. {
  691. const char* string = [[FBSDKSettings.sharedSettings sdkVersion] UTF8String];
  692. char* res = (char*)malloc(strlen(string) + 1);
  693. strcpy(res, string);
  694. return res;
  695. }
  696. void IOSFBSetUserID(const char *userID)
  697. {
  698. [[FBSDKAppEvents shared] setUserID:[FBUnityUtility stringFromCString:userID]];
  699. }
  700. void IOSFBOpenGamingServicesFriendFinder(int requestId)
  701. {
  702. [FBSDKFriendFinderDialog
  703. launchFriendFinderDialogWithCompletionHandler:^(BOOL success, NSError * _Nullable error) {
  704. if (!success || error) {
  705. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnFriendFinderComplete error:error requestId:requestId];
  706. } else {
  707. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnFriendFinderComplete
  708. userData:NULL
  709. requestId:requestId];
  710. }
  711. }];
  712. }
  713. void IOSFBCreateGamingContext(int requestID, const char *playerID) {
  714. NSError *error;
  715. NSString *playerIDString = [FBUnityUtility stringFromCString:playerID];
  716. FBUnitySDKDelegate *delegate = [FBUnitySDKDelegate instanceWithRequestID:requestID];
  717. FBSDKCreateContextContent *content = [[FBSDKCreateContextContent alloc] initDialogContentWithPlayerID:playerIDString];
  718. FBSDKContextDialogPresenter *presenter = [[FBSDKContextDialogPresenter alloc] init];
  719. [presenter makeAndShowCreateContextDialogWithContent:content delegate:delegate error:&error];
  720. if (error) {
  721. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnGetTournamentsComplete error:error requestId:requestID];
  722. }
  723. }
  724. void IOSFBSwitchGamingContext(
  725. int requestID,
  726. const char *contextID) {
  727. NSError *error;
  728. NSString *contextIDString = [FBUnityUtility stringFromCString:contextID];
  729. FBUnitySDKDelegate *delegate = [FBUnitySDKDelegate instanceWithRequestID:requestID];
  730. FBSDKSwitchContextContent *content = [[FBSDKSwitchContextContent alloc] initDialogContentWithContextID:contextIDString];
  731. FBSDKContextDialogPresenter *presenter = [[FBSDKContextDialogPresenter alloc] init];
  732. [presenter makeAndShowSwitchContextDialogWithContent:content delegate:delegate error:&error];
  733. if (error) {
  734. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnGetTournamentsComplete error:error requestId:requestID];
  735. }
  736. }
  737. void IOSFBChooseGamingContext(
  738. int requestID,
  739. const char *filter,
  740. int minSize,
  741. int maxSize)
  742. {
  743. FBUnitySDKDelegate *delegate = [FBUnitySDKDelegate instanceWithRequestID:requestID];
  744. FBSDKChooseContextContent *chooseContent = [FBSDKChooseContextContent alloc];
  745. NSString *filterNSString = [NSString stringWithUTF8String:filter];
  746. if ([filterNSString length] == 0) {
  747. chooseContent.filter = FBSDKChooseContextFilterNone;
  748. } else if ([filterNSString isEqualToString:@"NEW_PLAYERS_ONLY"]) {
  749. chooseContent.filter = FBSDKChooseContextFilterNewPlayersOnly;
  750. } else if ([filterNSString isEqualToString:@"INCLUDE_EXISTING_CHALLENGES"]) {
  751. chooseContent.filter = FBSDKChooseContextFilterExistingChallenges;
  752. } else if ([filterNSString isEqualToString:@"NEW_CONTEXT_ONLY"]) {
  753. chooseContent.filter = FBSDKChooseContextFilterNewContextOnly;
  754. }
  755. if (minSize > 0) {
  756. chooseContent.minParticipants = minSize;
  757. }
  758. if (maxSize > 0) {
  759. chooseContent.maxParticipants = maxSize;
  760. }
  761. FBSDKContextDialogPresenter *presenter = [[FBSDKContextDialogPresenter alloc] init];
  762. [presenter makeAndShowChooseContextDialogWithContent:chooseContent delegate:delegate];
  763. }
  764. void IOSFBGetCurrentGamingContext(int requestID)
  765. {
  766. FBSDKGamingContext *currentContext = [FBSDKGamingContext currentContext];
  767. if (currentContext) {
  768. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnGetCurrentGamingContextComplete
  769. userData:@{@"contextId":[currentContext identifier]}
  770. requestId:requestID];
  771. } else {
  772. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnGetCurrentGamingContextComplete
  773. userData:NULL
  774. requestId:requestID];
  775. }
  776. }
  777. void IOSFBSetDataProcessingOptions(
  778. const char** options,
  779. int numOptions,
  780. int country,
  781. int state) {
  782. NSMutableArray<NSString*>* array = [[NSMutableArray alloc] init];
  783. for (int i = 0; i < numOptions; i++) {
  784. NSString* option = [FBUnityUtility stringFromCString:options[i]];
  785. if (option) {
  786. [array addObject:option];
  787. }
  788. }
  789. [FBSDKSettings.sharedSettings setDataProcessingOptions:array country:country state:state];
  790. }
  791. void IOSFBGetTournaments(int requestID)
  792. {
  793. FBSDKTournamentFetcher *fetcher = [[FBSDKTournamentFetcher alloc] init];
  794. [fetcher fetchTournamentsWithCompletionHandler:^(NSArray<FBSDKTournament *> * tournaments, NSError * error) {
  795. if (error) {
  796. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnGetTournamentsComplete error:error requestId:requestID];
  797. }
  798. NSMutableDictionary *userData = [NSMutableDictionary new];
  799. for (FBSDKTournament *tournament in tournaments) {
  800. userData[tournament.identifier] = [tournament toDictionary];
  801. }
  802. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnGetTournamentsComplete
  803. userData:userData
  804. requestId:requestID];
  805. }];
  806. }
  807. void IOSFBUpdateTournament(const char *tournamentID, int score, int requestID)
  808. {
  809. FBSDKTournamentUpdater *updater = [[FBSDKTournamentUpdater alloc] init];
  810. [updater updateWithTournamentID:[NSString stringWithUTF8String:tournamentID]
  811. score:score
  812. completionHandler:^(BOOL success, NSError * _Nullable error) {
  813. if (!success || error) {
  814. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnUpdateTournamentComplete error:error requestId:requestID];
  815. } else {
  816. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnUpdateTournamentComplete
  817. userData:NULL
  818. requestId:requestID];
  819. }
  820. }];
  821. }
  822. void IOSFBUpdateAndShareTournament(const char *tournamentID, int score, int requestID)
  823. {
  824. NSError *error;
  825. FBUnitySDKDelegate *delegate = [FBUnitySDKDelegate instanceWithRequestID:requestID];
  826. FBSDKShareTournamentDialog *dialog = [[FBSDKShareTournamentDialog alloc] initWithDelegate: delegate];
  827. [dialog showWithScore:score tournamentID:[NSString stringWithUTF8String:tournamentID] error:&error];
  828. if (error) {
  829. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnGetTournamentsComplete error:error requestId:requestID];
  830. }
  831. }
  832. void IOSFBCreateAndShareTournament(
  833. int initialScore,
  834. const char *title,
  835. int sortOrder,
  836. int scoreFormat,
  837. long endTime,
  838. const char *payload,
  839. int requestID)
  840. {
  841. NSError *error;
  842. FBUnitySDKDelegate *delegate = [FBUnitySDKDelegate instanceWithRequestID:requestID];
  843. FBSDKShareTournamentDialog *dialog = [[FBSDKShareTournamentDialog alloc] initWithDelegate: delegate];
  844. NSString *payloadString;
  845. if (payload) {
  846. payloadString = [NSString stringWithUTF8String:payload];
  847. }
  848. [dialog showWithInitialScore:initialScore
  849. title:[NSString stringWithUTF8String:title]
  850. endTime:[NSDate dateWithTimeIntervalSince1970: endTime]
  851. scoreType:scoreFormat
  852. sortOrder:sortOrder
  853. payload:payloadString
  854. error: &error];
  855. if (error) {
  856. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnGetTournamentsComplete error:error requestId:requestID];
  857. }
  858. }
  859. void IOSFBUploadImageToMediaLibrary(
  860. int requestId,
  861. const char *caption,
  862. const char *imageUri,
  863. bool shouldLaunchMediaDialog)
  864. {
  865. NSString *captionString = [FBUnityUtility stringFromCString:caption];
  866. NSString *imageUriString = [FBUnityUtility stringFromCString:imageUri];
  867. UIImage *image = [UIImage imageWithContentsOfFile:imageUriString];
  868. FBSDKGamingImageUploaderConfiguration *config =
  869. [[FBSDKGamingImageUploaderConfiguration alloc]
  870. initWithImage:image
  871. caption:captionString
  872. shouldLaunchMediaDialog:shouldLaunchMediaDialog ? YES: NO];
  873. [FBSDKGamingImageUploader
  874. uploadImageWithConfiguration:config
  875. andResultCompletion:^(BOOL success, id result, NSError * _Nullable error) {
  876. if (!success || error) {
  877. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnUploadImageToMediaLibraryComplete
  878. error:error
  879. requestId:requestId];
  880. } else {
  881. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnUploadImageToMediaLibraryComplete
  882. userData:@{@"id":result[@"id"]}
  883. requestId:requestId];
  884. }
  885. }];
  886. }
  887. void IOSFBUploadVideoToMediaLibrary(int requestId,
  888. const char *caption,
  889. const char *videoUri)
  890. {
  891. NSString *captionString = [FBUnityUtility stringFromCString:caption];
  892. NSString *videoUriString = [FBUnityUtility stringFromCString:videoUri];
  893. NSURL *videoURL = [NSURL fileURLWithPath:videoUriString];
  894. FBSDKGamingVideoUploaderConfiguration *config =
  895. [[FBSDKGamingVideoUploaderConfiguration alloc]
  896. initWithVideoURL:videoURL
  897. caption:captionString];
  898. [FBSDKGamingVideoUploader
  899. uploadVideoWithConfiguration:config
  900. andResultCompletion:^(BOOL success, id result, NSError * _Nullable error) {
  901. if (!success || error) {
  902. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnUploadVideoToMediaLibraryComplete
  903. error:error
  904. requestId:requestId];
  905. } else {
  906. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnUploadVideoToMediaLibraryComplete
  907. userData:@{@"id":result[@"id"]}
  908. requestId:requestId];
  909. }
  910. }];
  911. }
  912. char* IOSFBGetUserID()
  913. {
  914. NSString *userID = [[FBSDKAppEvents shared] userID];
  915. if (!userID) {
  916. return NULL;
  917. }
  918. const char* string = [userID UTF8String];
  919. char* res = (char*)malloc(strlen(string) + 1);
  920. strcpy(res, string);
  921. return res;
  922. }
  923. void IOSFBFetchDeferredAppLink(int requestId)
  924. {
  925. [FBSDKAppLinkUtility fetchDeferredAppLink:^(NSURL *url, NSError *error) {
  926. if (error) {
  927. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnFetchDeferredAppLinkComplete error:error requestId:requestId];
  928. return;
  929. }
  930. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnFetchDeferredAppLinkComplete
  931. userData:[FBUnityUtility appLinkDataFromUrl:url]
  932. requestId:requestId];
  933. }];
  934. }
  935. void IOSFBRefreshCurrentAccessToken(int requestId)
  936. {
  937. FBSDKGraphRequestCompletion completion = ^(id<FBSDKGraphRequestConnecting> connection, id result, NSError *error) {
  938. if (error) {
  939. [FBUnityUtility sendErrorToUnity:FBUnityMessageName_OnRefreshCurrentAccessTokenComplete error:error requestId:requestId];
  940. return;
  941. }
  942. [FBUnityUtility sendMessageToUnity:FBUnityMessageName_OnRefreshCurrentAccessTokenComplete
  943. userData:[FBUnityUtility getUserDataFromAccessToken:[FBSDKAccessToken currentAccessToken]]
  944. requestId:requestId];
  945. };
  946. [FBSDKAccessToken refreshCurrentAccessTokenWithCompletion: completion];
  947. }
  948. void IOSFBRefreshLimitedLogin(int requestId, int fallbackPolicy)
  949. {
  950. [[FBUnityInterface sharedInstance] refreshLimitedLogin:requestId fallbackPolicy:fallbackPolicy];
  951. }
  952. }