mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-06 21:57:47 +00:00
GEEKING
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// RBHybridModuleDialogs.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "RBHybridModule.h"
|
||||
|
||||
@interface RBHybridModuleAnalytics : RBHybridModule
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// RBHybridModuleDialogs.m
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridModuleAnalytics.h"
|
||||
#import "RBHybridCommand.h"
|
||||
#import "NSDictionary+Parsing.h"
|
||||
#import "Flurry.h"
|
||||
|
||||
#define MODULE_ID @"Analytics"
|
||||
|
||||
@implementation RBHybridModuleAnalytics
|
||||
|
||||
-(instancetype) init
|
||||
{
|
||||
self = [super initWithModuleID:MODULE_ID];
|
||||
if(self)
|
||||
{
|
||||
[self registerFunction:@"trackEvent" withSelector:@selector(trackEvent:)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Present a single button dialog
|
||||
*
|
||||
* @param {string} eventName - Event name
|
||||
* @param {Object} params - Dictionary with the event parameters. Only the first level will be saved. (i.e. no nested objects).
|
||||
*
|
||||
*/
|
||||
-(void)trackEvent:(RBHybridCommand*)command
|
||||
{
|
||||
NSString* event = [command.params stringForKey:@"eventName" withDefault:@"Roblox"];
|
||||
NSDictionary* params = [command.params dictionaryForKey:@"params" withDefault:@{}];
|
||||
|
||||
[Flurry logEvent:event withParameters:params];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// RBHybridModuleDialogs.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "RBHybridModule.h"
|
||||
|
||||
@interface RBHybridModuleDialogs : RBHybridModule
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// RBHybridModuleDialogs.m
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridModuleDialogs.h"
|
||||
#import "RBHybridCommand.h"
|
||||
#import "NSDictionary+Parsing.h"
|
||||
#import "UIAlertView+Blocks.h"
|
||||
|
||||
#define MODULE_ID @"Dialogs"
|
||||
|
||||
@implementation RBHybridModuleDialogs
|
||||
|
||||
-(instancetype) init
|
||||
{
|
||||
self = [super initWithModuleID:MODULE_ID];
|
||||
if(self)
|
||||
{
|
||||
[self registerFunction:@"alert" withSelector:@selector(alert:)];
|
||||
[self registerFunction:@"confirm" withSelector:@selector(confirm:)];
|
||||
[self registerFunction:@"prompt" withSelector:@selector(prompt:)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Present a single button dialog
|
||||
*
|
||||
* @param {string} text - Content text
|
||||
* @param {Function} callback - Callback
|
||||
* @param {string} title - Window title
|
||||
* @param {string} buttonName - Button name
|
||||
* @instance
|
||||
*/
|
||||
-(void)alert:(RBHybridCommand*)command
|
||||
{
|
||||
NSString* text = [command.params stringForKey:@"text"];
|
||||
NSString* title = [command.params stringForKey:@"title" withDefault:@"Roblox"];
|
||||
NSString* buttonName = [command.params stringForKey:@"buttonName" withDefault:NSLocalizedString(@"OkWord", nil)];
|
||||
|
||||
UIAlertView* alert = [[UIAlertView alloc]
|
||||
initWithTitle:title
|
||||
message:text
|
||||
delegate:nil
|
||||
cancelButtonTitle:buttonName
|
||||
otherButtonTitles:nil];
|
||||
|
||||
[alert showWithCompletion:^(UIAlertView *alertView, NSInteger buttonIndex)
|
||||
{
|
||||
[command executeCallback:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Present a dialog with multiple options
|
||||
*
|
||||
* @param {string} text - Content text
|
||||
* @param {Function} callback - Callback
|
||||
* @param {string} title - Window title
|
||||
* @param {string[]} buttonName - Button labels
|
||||
* @instance
|
||||
*/
|
||||
-(void)confirm:(RBHybridCommand*)command
|
||||
{
|
||||
NSString* text = [command.params stringForKey:@"text"];
|
||||
NSString* title = [command.params stringForKey:@"title" withDefault:@"Roblox"];
|
||||
NSArray* buttons = [command.params arrayForKey:@"buttonName"];
|
||||
|
||||
// Validate button
|
||||
NSString* firstButton;
|
||||
if(buttons.count > 0 && [buttons[0] isKindOfClass:[NSString class]])
|
||||
{
|
||||
firstButton = buttons[0];
|
||||
|
||||
buttons = [buttons subarrayWithRange:NSMakeRange(1, buttons.count - 1)];
|
||||
}
|
||||
else
|
||||
{
|
||||
firstButton = NSLocalizedString(@"OkWord", nil);
|
||||
}
|
||||
|
||||
UIAlertView* alert = [[UIAlertView alloc]
|
||||
initWithTitle:title
|
||||
message:text
|
||||
delegate:nil
|
||||
cancelButtonTitle:firstButton
|
||||
otherButtonTitles:nil];
|
||||
|
||||
for(NSString* buttonName in buttons)
|
||||
{
|
||||
[alert addButtonWithTitle:buttonName];
|
||||
}
|
||||
|
||||
[alert showWithCompletion:^(UIAlertView *alertView, NSInteger buttonIndex)
|
||||
{
|
||||
[command executeCallback:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
-(void)prompt:(RBHybridCommand*)command
|
||||
{
|
||||
// [command executeCallback:@[]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// RBHybridModuleSocial.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridModule.h"
|
||||
|
||||
@interface RBHybridModuleGame : RBHybridModule
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// RBHybridModuleGame.mm
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridModuleGame.h"
|
||||
#import "RBGameViewController.h"
|
||||
#import "NSDictionary+Parsing.h"
|
||||
|
||||
#define MODULE_ID @"Game"
|
||||
|
||||
@implementation RBHybridModuleGame
|
||||
{
|
||||
RBHybridCommand* _command;
|
||||
}
|
||||
|
||||
-(instancetype) init
|
||||
{
|
||||
self = [super initWithModuleID:MODULE_ID];
|
||||
if(self)
|
||||
{
|
||||
[self registerFunction:@"startWithPlaceID" withSelector:@selector(startGameWithPlaceID:)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a game session
|
||||
*
|
||||
* @param {string} placeID - ID of the place to start
|
||||
* @param {Function} callback
|
||||
* @instance
|
||||
*/
|
||||
-(void)startGameWithPlaceID:(RBHybridCommand*)command
|
||||
{
|
||||
_command = command;
|
||||
|
||||
NSString* placeID = [command.params stringForKey:@"placeID" withDefault:nil];
|
||||
if(placeID != nil)
|
||||
{
|
||||
RBGameViewController* gameController = [[RBGameViewController alloc] initWithLaunchParams:[RBXGameLaunchParams InitParamsForJoinPlace:placeID.integerValue]];
|
||||
gameController.completionHandler = ^
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^
|
||||
{
|
||||
if(_command)
|
||||
{
|
||||
[_command executeCallback:YES];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
[command.originWebView.controller presentViewController:gameController animated:NO completion:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
[command executeCallback:NO];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// RBHybridModuleSocial.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridModule.h"
|
||||
|
||||
@interface RBHybridModuleSocial : RBHybridModule
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,139 @@
|
||||
//
|
||||
// RBHybridModuleSocial.m
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridModuleSocial.h"
|
||||
#import "RBHybridCommand.h"
|
||||
#import "RBHybridWebView.h"
|
||||
#import "NSDictionary+Parsing.h"
|
||||
#import "UIViewController+Helpers.h"
|
||||
#import "RBHybridModuleSocial_FBActivity.h"
|
||||
#import "RBHybridModuleSocial_TwitterActivity.h"
|
||||
#import "RBHybridModuleSocial_GooglePlusActivity.h"
|
||||
#import <Social/Social.h>
|
||||
|
||||
#define MODULE_ID @"Social"
|
||||
|
||||
@implementation RBHybridModuleSocial
|
||||
|
||||
-(instancetype) init
|
||||
{
|
||||
self = [super initWithModuleID:MODULE_ID];
|
||||
if(self)
|
||||
{
|
||||
[self registerFunction:@"presentShareDialog" withSelector:@selector(presentShareDialog:)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Present a share dialog
|
||||
* @param {string} text - Text to share
|
||||
* @param {string} link - Link to embed
|
||||
* @param {string} [imageURL=null] - link
|
||||
* @param {Function} [callback] - Callback
|
||||
* @instance
|
||||
*/
|
||||
-(void)presentShareDialog:(RBHybridCommand*)command
|
||||
{
|
||||
NSMutableArray* items = [NSMutableArray array];
|
||||
|
||||
// Collect arguments
|
||||
NSString* text = [command.params stringForKey:@"text" withDefault:@""];
|
||||
[items addObject:text];
|
||||
|
||||
NSString* link = [command.params stringForKey:@"link"];
|
||||
NSURL* linkURL = nil;
|
||||
if(link != nil)
|
||||
{
|
||||
linkURL = [NSURL URLWithString:link];
|
||||
[items addObject:linkURL];
|
||||
}
|
||||
|
||||
NSString* imageURLStr = [command.params stringForKey:@"imageURL" withDefault:nil];
|
||||
NSURL* imageURL = nil;
|
||||
UIImage* image = nil;
|
||||
if(imageURL != nil)
|
||||
{
|
||||
imageURL = [NSURL URLWithString:imageURLStr];
|
||||
NSData* imgData = [NSData dataWithContentsOfURL:imageURL];
|
||||
image = [UIImage imageWithData:imgData];
|
||||
|
||||
[items addObject:image];
|
||||
}
|
||||
|
||||
// Do the action
|
||||
dispatch_async(dispatch_get_main_queue(), ^
|
||||
{
|
||||
RBHybridModuleSocial_FBActivity* facebookActivity = [[RBHybridModuleSocial_FBActivity alloc] init];
|
||||
facebookActivity.parentController = command.originWebView.controller;
|
||||
facebookActivity.text = text;
|
||||
facebookActivity.link = linkURL;
|
||||
facebookActivity.imageURL = imageURL;
|
||||
facebookActivity.image = image;
|
||||
|
||||
RBHybridModuleSocial_TwitterActivity* twitterActivity = [[RBHybridModuleSocial_TwitterActivity alloc] init];
|
||||
twitterActivity.parentController = command.originWebView.controller;
|
||||
twitterActivity.text = text;
|
||||
twitterActivity.link = linkURL;
|
||||
twitterActivity.imageURL = imageURL;
|
||||
twitterActivity.image = image;
|
||||
|
||||
// For Apple submission problems, I am disbaling GP until they fix the library.
|
||||
RBHybridModuleSocial_GooglePlusActivity* googlePlusActivity = [[RBHybridModuleSocial_GooglePlusActivity alloc] init];
|
||||
googlePlusActivity.text = text;
|
||||
googlePlusActivity.link = linkURL;
|
||||
googlePlusActivity.imageURL = imageURL;
|
||||
googlePlusActivity.image = image;
|
||||
|
||||
NSArray* activities = @[facebookActivity, twitterActivity, googlePlusActivity];
|
||||
|
||||
UIViewController* parentController = command.originWebView.controller;
|
||||
|
||||
UIActivityViewController* activityController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:activities];
|
||||
activityController.excludedActivityTypes = @[
|
||||
UIActivityTypePostToFacebook,
|
||||
UIActivityTypePostToTwitter,
|
||||
UIActivityTypePostToWeibo,
|
||||
UIActivityTypePostToFlickr,
|
||||
UIActivityTypePostToVimeo
|
||||
];
|
||||
|
||||
if( [activityController respondsToSelector:@selector(popoverPresentationController:)] )
|
||||
{
|
||||
activityController.popoverPresentationController.sourceView = parentController.view;
|
||||
activityController.popoverPresentationController.permittedArrowDirections = 0;
|
||||
activityController.popoverPresentationController.sourceRect = CGRectInset(parentController.view.bounds, 200, 200);
|
||||
}
|
||||
|
||||
// Setup callbacks
|
||||
// setCompletionWithItemsHandler is avaialble only in iOS8
|
||||
if( [activityController respondsToSelector:@selector(setCompletionWithItemsHandler:)] )
|
||||
{
|
||||
activityController.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError)
|
||||
{
|
||||
[self onActionCompletedForCommand:command withStatus:completed];
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
activityController.completionHandler = ^(NSString *activityType, BOOL completed)
|
||||
{
|
||||
[self onActionCompletedForCommand:command withStatus:completed];
|
||||
};
|
||||
}
|
||||
|
||||
[parentController presentViewController:activityController animated:YES completion:nil];
|
||||
});
|
||||
}
|
||||
|
||||
-(void)onActionCompletedForCommand:(RBHybridCommand*)command withStatus:(BOOL)completed
|
||||
{
|
||||
[command executeCallback:completed];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// RBHybridModuleSocial_FBActivity.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/19/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface RBHybridModuleSocial_FBActivity : UIActivity
|
||||
|
||||
@property(weak, nonatomic) UIViewController* parentController;
|
||||
@property(strong, nonatomic) NSString* text;
|
||||
@property(strong, nonatomic) NSURL* link;
|
||||
@property(strong, nonatomic) NSURL* imageURL;
|
||||
@property(strong, nonatomic) UIImage* image;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// RBHybridModuleSocial_FBActivity.m
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/19/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridModuleSocial_FBActivity.h"
|
||||
#import <FacebookSDK/FacebookSDK.h>
|
||||
#import <Social/Social.h>
|
||||
|
||||
@implementation RBHybridModuleSocial_FBActivity
|
||||
{
|
||||
FBLinkShareParams* _shareParams;
|
||||
BOOL _shareWithFBApp;
|
||||
}
|
||||
|
||||
+ (UIActivityCategory)activityCategory
|
||||
{
|
||||
return UIActivityCategoryShare;
|
||||
}
|
||||
|
||||
- (NSString *)activityType
|
||||
{
|
||||
return @"wtf.watrbx.activity.facebook";
|
||||
}
|
||||
|
||||
- (NSString *)activityTitle
|
||||
{
|
||||
return @"Facebook";
|
||||
}
|
||||
|
||||
- (UIImage *)activityImage
|
||||
{
|
||||
UIImage* image = [UIImage imageNamed:@"Social-FB-Icon"];
|
||||
return image;
|
||||
}
|
||||
|
||||
// For some reason on iOS7 without this function the icon is completely gray
|
||||
- (UIImage *)_activityImage
|
||||
{
|
||||
UIImage* image = [UIImage imageNamed:@"Social-FB-Icon"];
|
||||
return image;
|
||||
}
|
||||
|
||||
- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)prepareWithActivityItems:(NSArray *)activityItems
|
||||
{
|
||||
_shareParams = [[FBLinkShareParams alloc] init];
|
||||
_shareParams.name = _text;
|
||||
_shareParams.link = _link;
|
||||
_shareParams.picture = _imageURL;
|
||||
|
||||
_shareWithFBApp = ![FBDialogs canPresentOSIntegratedShareDialog] && [FBDialogs canPresentShareDialogWithParams:_shareParams];
|
||||
}
|
||||
|
||||
- (UIViewController *)activityViewController
|
||||
{
|
||||
if(!_shareWithFBApp)
|
||||
{
|
||||
SLComposeViewController *composeViewController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
|
||||
[composeViewController setInitialText:_text];
|
||||
|
||||
if(_link)
|
||||
{
|
||||
[composeViewController addURL:_link];
|
||||
}
|
||||
|
||||
if(_image)
|
||||
{
|
||||
[composeViewController addImage:_image];
|
||||
}
|
||||
|
||||
[composeViewController setCompletionHandler:^(SLComposeViewControllerResult result)
|
||||
{
|
||||
[self activityDidFinish:(result == SLComposeViewControllerResultDone)];
|
||||
}];
|
||||
|
||||
return composeViewController;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)performActivity
|
||||
{
|
||||
if(_shareWithFBApp)
|
||||
{
|
||||
// FBDialogs call to open Share dialog within the Facebook app
|
||||
[FBDialogs
|
||||
presentShareDialogWithParams:_shareParams
|
||||
clientState:nil
|
||||
handler:^(FBAppCall *call, NSDictionary *results, NSError *error)
|
||||
{
|
||||
BOOL success = !error && !(results[@"completionGesture"] && [results[@"completionGesture"] isEqualToString:@"cancel"]);
|
||||
[self activityDidFinish:success];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// RBHybridModuleSocial_GooglePlusActivity.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/19/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface RBHybridModuleSocial_GooglePlusActivity : UIActivity
|
||||
|
||||
@property(strong, nonatomic) NSString* text;
|
||||
@property(strong, nonatomic) NSURL* link;
|
||||
@property(strong, nonatomic) NSURL* imageURL;
|
||||
@property(strong, nonatomic) UIImage* image;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// RBHybridModuleSocial_GooglePlusActivity.m
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/19/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridModuleSocial_GooglePlusActivity.h"
|
||||
|
||||
#import <GooglePlus/GooglePlus.h>
|
||||
#import <GoogleOpenSource/GoogleOpenSource.h>
|
||||
|
||||
//
|
||||
// As defined in https://console.developers.google.com/project/roblox-mobile
|
||||
//
|
||||
static NSString * const kClientId = @"757902889875-mdpibqck9096ap3gt0minfg85d27kavm.apps.googleusercontent.com";
|
||||
|
||||
@interface RBHybridModuleSocial_GooglePlusActivity() <GPPSignInDelegate, GPPShareDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation RBHybridModuleSocial_GooglePlusActivity
|
||||
|
||||
+ (UIActivityCategory)activityCategory
|
||||
{
|
||||
return UIActivityCategoryShare;
|
||||
}
|
||||
|
||||
- (NSString *)activityType
|
||||
{
|
||||
return @"wtf.watrbx.activity.googleplus";
|
||||
}
|
||||
|
||||
- (NSString *)activityTitle
|
||||
{
|
||||
return @"Google+";
|
||||
}
|
||||
|
||||
- (UIImage *)activityImage
|
||||
{
|
||||
UIImage* image = [UIImage imageNamed:@"Social-Google-Icon"];
|
||||
return image;
|
||||
}
|
||||
|
||||
// For some reason on iOS7 without this function the icon is completely gray
|
||||
- (UIImage *)_activityImage
|
||||
{
|
||||
UIImage* image = [UIImage imageNamed:@"Social-Google-Icon"];
|
||||
return image;
|
||||
}
|
||||
|
||||
- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)prepareWithActivityItems:(NSArray *)activityItems
|
||||
{
|
||||
[GPPSignIn sharedInstance].clientID = kClientId;
|
||||
}
|
||||
|
||||
- (UIViewController *)activityViewController
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)performActivity
|
||||
{
|
||||
[self signIn];
|
||||
}
|
||||
|
||||
- (void)signIn
|
||||
{
|
||||
GPPSignIn *signIn = [GPPSignIn sharedInstance];
|
||||
signIn.shouldFetchGooglePlusUser = YES;
|
||||
//signIn.shouldFetchGoogleUserEmail = YES;
|
||||
|
||||
signIn.delegate = self;
|
||||
signIn.clientID = kClientId;
|
||||
|
||||
signIn.scopes = @[ kGTLAuthScopePlusLogin ]; // "https://www.googleapis.com/auth/plus.login" scope
|
||||
//signIn.scopes = @[ @"profile" ]; // "profile" scope
|
||||
|
||||
BOOL userLoggedIn = [signIn trySilentAuthentication];
|
||||
if(!userLoggedIn)
|
||||
{
|
||||
[signIn authenticate];
|
||||
}
|
||||
}
|
||||
|
||||
// The authorization has finished and is successful if |error| is |nil|.
|
||||
- (void)finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error
|
||||
{
|
||||
if(error == nil)
|
||||
{
|
||||
[self shareLink];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self activityDidFinish:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)shareLink
|
||||
{
|
||||
[GPPShare sharedInstance].delegate = self;
|
||||
|
||||
id<GPPNativeShareBuilder> shareBuilder = [[GPPShare sharedInstance] nativeShareDialog];
|
||||
|
||||
[shareBuilder setPrefillText:_text];
|
||||
[shareBuilder setURLToShare:_link];
|
||||
[shareBuilder attachImage:_image];
|
||||
[shareBuilder setContentDeepLinkID:[_link query]];
|
||||
|
||||
[shareBuilder open];
|
||||
}
|
||||
|
||||
- (void)finishedSharing:(BOOL)shared
|
||||
{
|
||||
[self activityDidFinish:shared];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// RBHybridModuleSocial_TwitterActivity.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/19/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface RBHybridModuleSocial_TwitterActivity : UIActivity
|
||||
|
||||
@property(weak, nonatomic) UIViewController* parentController;
|
||||
@property(strong, nonatomic) NSString* text;
|
||||
@property(strong, nonatomic) NSURL* link;
|
||||
@property(strong, nonatomic) NSURL* imageURL;
|
||||
@property(strong, nonatomic) UIImage* image;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// RBHybridModuleSocial_TwitterActivity.m
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/19/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridModuleSocial_TwitterActivity.h"
|
||||
#import <Social/Social.h>
|
||||
|
||||
@implementation RBHybridModuleSocial_TwitterActivity
|
||||
|
||||
+ (UIActivityCategory)activityCategory
|
||||
{
|
||||
return UIActivityCategoryShare;
|
||||
}
|
||||
|
||||
- (NSString *)activityType
|
||||
{
|
||||
return @"wtf.watrbx.activity.twitter";
|
||||
}
|
||||
|
||||
- (NSString *)activityTitle
|
||||
{
|
||||
return @"Twitter";
|
||||
}
|
||||
|
||||
- (UIImage *)activityImage
|
||||
{
|
||||
UIImage* image = [UIImage imageNamed:@"Social-Twitter-Icon"];
|
||||
return image;
|
||||
}
|
||||
|
||||
// For some reason on iOS7 without this function the icon is completely gray
|
||||
- (UIImage *)_activityImage
|
||||
{
|
||||
UIImage* image = [UIImage imageNamed:@"Social-Twitter-Icon"];
|
||||
return image;
|
||||
}
|
||||
|
||||
- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)prepareWithActivityItems:(NSArray *)activityItems
|
||||
{
|
||||
}
|
||||
|
||||
- (UIViewController *)activityViewController
|
||||
{
|
||||
NSString *message = _text;
|
||||
NSString *urlString = [_link absoluteString];
|
||||
|
||||
// Boldly invoke the target app, because the phone will display a nice message asking to configure the app
|
||||
SLComposeViewController *composeViewController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
|
||||
[composeViewController setInitialText:message];
|
||||
[composeViewController addURL:[NSURL URLWithString:urlString]];
|
||||
|
||||
[composeViewController setCompletionHandler:^(SLComposeViewControllerResult result)
|
||||
{
|
||||
[self activityDidFinish:(result == SLComposeViewControllerResultDone)];
|
||||
}];
|
||||
|
||||
return composeViewController;
|
||||
}
|
||||
|
||||
- (void)performActivity
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// RBHybridWebViewProtocol.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ashish Jain on 10/19/15.
|
||||
// Copyright © 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
@class RBHybridCommand;
|
||||
|
||||
@protocol RBHybridWebViewProtocol <NSObject>
|
||||
|
||||
@property(weak, nonatomic) UIViewController *controller;
|
||||
@property(nonatomic, readonly) NSString* webviewID;
|
||||
@property(nonatomic, readonly) NSInteger lastRequestID;
|
||||
|
||||
- (void)executeJavascriptCommand:(NSString *)jsonCommand requestID:(NSInteger)requestId;
|
||||
- (void)executeCallback:(NSString*)callbackID success:(BOOL)success withParams:(NSDictionary*)params;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// RBHybridBridge.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RBHybridWebViewProtocol.h"
|
||||
|
||||
@class RBHybridWebView;
|
||||
@class RBHybridModule;
|
||||
|
||||
|
||||
@interface RBHybridBridge : NSObject
|
||||
|
||||
+ (RBHybridBridge*) sharedInstance;
|
||||
|
||||
-(void)registerWebView:(UIView <RBHybridWebViewProtocol> *)webview;
|
||||
-(void)unRegisterWebView:(UIView <RBHybridWebViewProtocol> *)webview;
|
||||
|
||||
-(RBHybridWebView*)getWebViewForID:(NSString*)webviewID;
|
||||
-(RBHybridModule*)getModuleForID:(NSString*)moduleID;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,177 @@
|
||||
//
|
||||
// RBHybridURLProtocol.m
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridBridge.h"
|
||||
#import "RBHybridCommand.h"
|
||||
#import "RBHybridModuleDialogs.h"
|
||||
#import "RBHybridModuleSocial.h"
|
||||
#import "RBHybridModuleGame.h"
|
||||
#import "RBHybridModuleAnalytics.h"
|
||||
#import "RBHybridWebView.h"
|
||||
#import "RBXFunctions.h"
|
||||
#import "SessionReporter.h"
|
||||
#import "UserInfo.h"
|
||||
|
||||
#import "NSDictionary+Parsing.h"
|
||||
|
||||
@interface RBHybridURLProtocol : NSURLProtocol
|
||||
|
||||
@end
|
||||
|
||||
@implementation RBHybridURLProtocol
|
||||
|
||||
+ (BOOL)canInitWithRequest:(NSURLRequest*)request
|
||||
{
|
||||
NSURL* url = [request URL];
|
||||
|
||||
if( url.path != nil && [url.path rangeOfString:@"/rbx_native_exec"].location != NSNotFound )
|
||||
{
|
||||
NSString* webViewID = [request valueForHTTPHeaderField:@"webViewId"];
|
||||
RBHybridWebView* webView = [[RBHybridBridge sharedInstance] getWebViewForID:webViewID];
|
||||
if(!webView)
|
||||
{
|
||||
NSLog(@"ERROR: Unable to retrieve webview for ID %@", webViewID);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString* requestIDStr = [request valueForHTTPHeaderField:@"requestId"];
|
||||
NSInteger requestID = [requestIDStr integerValue];
|
||||
if(requestID > webView.lastRequestID)
|
||||
{
|
||||
NSString* jsonCommand = [request valueForHTTPHeaderField:@"command"];
|
||||
[webView executeJavascriptCommand:jsonCommand requestID:requestID];
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)request
|
||||
{
|
||||
return request;
|
||||
}
|
||||
|
||||
- (void)startLoading
|
||||
{
|
||||
// Send a null but successful response immediately
|
||||
NSHTTPURLResponse* response = [[NSHTTPURLResponse alloc]
|
||||
initWithURL:[[self request] URL]
|
||||
statusCode:200
|
||||
HTTPVersion:@"HTTP/1.1"
|
||||
headerFields:@{@"Content-Type":@"text/plain"}];
|
||||
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
|
||||
[[self client] URLProtocolDidFinishLoading:self];
|
||||
}
|
||||
|
||||
- (void)stopLoading
|
||||
{
|
||||
// Dummy implementation // Not necessary
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RBHybridBridge
|
||||
{
|
||||
NSMutableDictionary* _modules;
|
||||
NSMutableArray* _webviews;
|
||||
}
|
||||
|
||||
+ (RBHybridBridge*) sharedInstance
|
||||
{
|
||||
static RBHybridBridge* instance;
|
||||
|
||||
static dispatch_once_t queue;
|
||||
dispatch_once(&queue, ^
|
||||
{
|
||||
instance = [[RBHybridBridge alloc] init];
|
||||
});
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
-(instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if(self)
|
||||
{
|
||||
[NSURLProtocol registerClass:[RBHybridURLProtocol class]];
|
||||
|
||||
_modules = [NSMutableDictionary dictionary];
|
||||
_webviews = [NSMutableArray array];
|
||||
|
||||
[self initializeModules];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)initializeModules
|
||||
{
|
||||
[self registerModule:[[RBHybridModuleDialogs alloc] init]];
|
||||
[self registerModule:[[RBHybridModuleSocial alloc] init]];
|
||||
[self registerModule:[[RBHybridModuleGame alloc] init]];
|
||||
[self registerModule:[[RBHybridModuleAnalytics alloc] init]];
|
||||
}
|
||||
|
||||
-(void) registerModule:(RBHybridModule*)module
|
||||
{
|
||||
[_modules setObject:module forKey:module.moduleID];
|
||||
}
|
||||
|
||||
-(void) unRegisterModule:(RBHybridModule*)module
|
||||
{
|
||||
[_modules removeObjectForKey:module.moduleID];
|
||||
}
|
||||
|
||||
-(void)registerWebView:(UIView <RBHybridWebViewProtocol> *)webview
|
||||
{
|
||||
// 2015.1023 ajain - valueWithNonretainedObject adds an object "value reference"
|
||||
// without incrementing the retain count of the object, thereby allowing it to be
|
||||
// unregistered when the webview's retain count hits 0.
|
||||
if (![_webviews containsObject:[NSValue valueWithNonretainedObject:webview]]) {
|
||||
[_webviews addObject:[NSValue valueWithNonretainedObject:webview]];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)unRegisterWebView:(UIView *)webview
|
||||
{
|
||||
if ([_webviews containsObject:[NSValue valueWithNonretainedObject:webview]]) {
|
||||
[_webviews removeObject:[NSValue valueWithNonretainedObject:webview]];
|
||||
}
|
||||
}
|
||||
|
||||
-(UIView <RBHybridWebViewProtocol> *)getWebViewForID:(NSString*)webviewID
|
||||
{
|
||||
for(NSValue* webviewPtr in _webviews)
|
||||
{
|
||||
UIView <RBHybridWebViewProtocol> * webview = [webviewPtr nonretainedObjectValue];
|
||||
if (!webview)
|
||||
{
|
||||
NSLog(@"Webview no longer exists");
|
||||
}
|
||||
else if(webview.webviewID != nil && [webview.webviewID isEqualToString:webviewID])
|
||||
{
|
||||
return webview;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
-(RBHybridModule*)getModuleForID:(NSString*)moduleID
|
||||
{
|
||||
return [_modules objectForKey:moduleID];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[NSURLProtocol unregisterClass:[RBHybridURLProtocol class]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// RBHybridCommand.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "RBHybridWebView.h"
|
||||
#import "RBHybridWebViewProtocol.h"
|
||||
|
||||
@interface RBHybridCommand : NSObject
|
||||
|
||||
@property(nonatomic) NSInteger requestID;
|
||||
@property(strong, nonatomic) NSString* moduleID;
|
||||
@property(strong, nonatomic) NSString* functionName;
|
||||
@property(strong, nonatomic) NSDictionary* params;
|
||||
@property(strong, nonatomic) NSString* callbackID;
|
||||
|
||||
@property(weak, nonatomic) UIView <RBHybridWebViewProtocol> *originWebView;
|
||||
|
||||
-(void)executeCallback:(BOOL)success;
|
||||
-(void)executeCallback:(BOOL)success withParams:(NSDictionary*)params;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// RBHybridCommand.m
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridCommand.h"
|
||||
#import "RBHybridBridge.h"
|
||||
#import "RBHybridWebView.h"
|
||||
|
||||
@implementation RBHybridCommand
|
||||
|
||||
-(void)executeCallback:(BOOL)success
|
||||
{
|
||||
if(_callbackID)
|
||||
{
|
||||
[_originWebView executeCallback:_callbackID success:success withParams:nil];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)executeCallback:(BOOL)success withParams:(NSDictionary*)params
|
||||
{
|
||||
if(_callbackID)
|
||||
{
|
||||
[_originWebView executeCallback:_callbackID success:(BOOL)success withParams:params];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// RBHybridModule.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "RBHybridCommand.h"
|
||||
|
||||
@interface RBHybridModule : NSObject
|
||||
|
||||
// Module properties
|
||||
@property(strong, nonatomic) NSString* moduleID;
|
||||
|
||||
// Initialization function
|
||||
-(instancetype)initWithModuleID:(NSString*)moduleID;
|
||||
|
||||
// Register a function to be executed from JS
|
||||
-(void)registerFunction:(NSString*)functionName withSelector:(SEL)selector;
|
||||
|
||||
// Internal function to make the actual call.
|
||||
// Override this function in your module if you need special function handling.
|
||||
-(void)executeCommand:(RBHybridCommand*)command;
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// RBHybridModule.m
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/5/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridModule.h"
|
||||
#import "RBHybridBridge.h"
|
||||
#import "NSDictionary+Parsing.h"
|
||||
|
||||
@implementation RBHybridModule
|
||||
{
|
||||
NSMutableDictionary* _functions;
|
||||
}
|
||||
|
||||
-(instancetype)initWithModuleID:(NSString*)moduleID
|
||||
{
|
||||
self = [super init];
|
||||
if(self)
|
||||
{
|
||||
self.moduleID = moduleID;
|
||||
|
||||
_functions = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)registerFunction:(NSString*)functionName withSelector:(SEL)selector
|
||||
{
|
||||
[_functions setObject:[NSValue valueWithPointer:selector] forKey:functionName];
|
||||
}
|
||||
|
||||
-(void)executeCommand:(RBHybridCommand*)command
|
||||
{
|
||||
if([command.functionName isEqualToString:@"supports"])
|
||||
{
|
||||
NSString* functionName = [command.params stringForKey:@"functionName" withDefault:@"nil"];
|
||||
BOOL functionExists = functionName != nil && [_functions objectForKey:functionName] != nil;
|
||||
[command executeCallback:functionExists];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSValue* selectorValue = [_functions objectForKey:command.functionName];
|
||||
if(selectorValue == nil)
|
||||
{
|
||||
NSLog(@"ERROR - Function %@ not available in module of type %@", command.functionName, command.moduleID);
|
||||
return;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[self performSelector:(SEL)[selectorValue pointerValue] withObject:command];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// RBHybridWKWebView.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ashish Jain on 10/16/15.
|
||||
// Copyright © 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
#import "RBHybridWebViewProtocol.h"
|
||||
#import "WKWebView+RBXWKWebView.h"
|
||||
|
||||
@interface RBHybridWKWebView : WKWebView <RBHybridWebViewProtocol>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,165 @@
|
||||
//
|
||||
// RBHybridWKWebView.m
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ashish Jain on 10/16/15.
|
||||
// Copyright © 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RBHybridWKWebView.h"
|
||||
|
||||
#import "NSDictionary+Parsing.h"
|
||||
#import "RBHybridBridge.h"
|
||||
#import "RBHybridCommand.h"
|
||||
#import "RBHybridModule.h"
|
||||
#import "SessionReporter.h"
|
||||
#import "UserInfo.h"
|
||||
|
||||
#import "RobloxInfo.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#define JS_HYBRID_OBJ @"window.Roblox.Hybrid"
|
||||
|
||||
@implementation RBHybridWKWebView
|
||||
|
||||
// Implemented for RBHybridWebViewProtocol
|
||||
|
||||
@synthesize webviewID;
|
||||
@synthesize controller;
|
||||
@synthesize lastRequestID;
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
[RBHybridWKWebView initializeUserAgent];
|
||||
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
[self initializeWebView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[RBHybridWKWebView initializeUserAgent];
|
||||
|
||||
self = [super initWithCoder:coder];
|
||||
if (self)
|
||||
{
|
||||
[self initializeWebView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
[RBHybridWKWebView initializeUserAgent];
|
||||
|
||||
self = [super initWithFrame:frame];
|
||||
if (self)
|
||||
{
|
||||
[self initializeWebView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+(void)initializeUserAgent
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObject:[RobloxInfo getUserAgentString] forKey:@"UserAgent"]];
|
||||
}
|
||||
|
||||
-(void)initializeWebView
|
||||
{
|
||||
[[RBHybridBridge sharedInstance] registerWebView:self];
|
||||
self.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
|
||||
}
|
||||
|
||||
- (void) executeJavascriptCommand:(NSString *)jsCommand requestID:(NSInteger)requestId
|
||||
{
|
||||
/*
|
||||
2015.1116 ajain - This code is intentionally the same as the code in RBHybridWebView. I wrote this as a centralized method,
|
||||
but as a result of a code review it was determined that duplicating code would be better since in a few months we will stop
|
||||
supporting iOS 7 and UIWebView's which will allows for alI wrote this as a centralized method,
|
||||
but as a result of a code review it was determined that duplicating code would be better since in a few months we will stopl the RBHybridWebView code to be removed.
|
||||
*/
|
||||
NSError* parseError = nil;
|
||||
NSDictionary* params = [NSJSONSerialization JSONObjectWithData:[jsCommand dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&parseError];
|
||||
if(parseError == nil)
|
||||
{
|
||||
RBHybridCommand* command = [[RBHybridCommand alloc] init];
|
||||
command.requestID = requestId;
|
||||
command.moduleID = [params stringForKey:@"moduleID"];
|
||||
command.functionName = [params stringForKey:@"functionName"];
|
||||
command.params = [params dictionaryForKey:@"params"];
|
||||
command.callbackID = [params stringForKey:@"callbackID"];
|
||||
|
||||
[self executeCommand:command];
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2015.1116 ajain - Something is wrong with the javascript command. Report back.
|
||||
[[SessionReporter sharedInstance] postAnalyticPayloadFromContext:RBXAContextHybrid
|
||||
result:RBXAResultFailure
|
||||
rbxError:RBXAErrorJSONParseFailure
|
||||
startingTime:[NSDate date]
|
||||
attemptedUsername:[UserInfo CurrentPlayer].username
|
||||
URLRequest:nil
|
||||
HTTPResponseCode:201
|
||||
responseData:[jsCommand dataUsingEncoding:NSUTF8StringEncoding]
|
||||
additionalData:@{@"JSCommandParseErrorDescWK":parseError.description}];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)executeCommand:(RBHybridCommand*)command
|
||||
{
|
||||
command.originWebView = self;
|
||||
|
||||
if(command.requestID > self.lastRequestID)
|
||||
{
|
||||
lastRequestID = command.requestID;
|
||||
}
|
||||
|
||||
RBHybridModule* module = [[RBHybridBridge sharedInstance] getModuleForID:command.moduleID];
|
||||
if(module != nil)
|
||||
{
|
||||
[module executeCommand:command];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)executeCallback:(NSString*)callbackID success:(BOOL)success withParams:(NSDictionary*)params
|
||||
{
|
||||
NSError* error;
|
||||
NSString* paramsString = @"{}";
|
||||
if(params != nil)
|
||||
{
|
||||
NSData* paramsData = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:&error];
|
||||
paramsString = [[NSString alloc] initWithData:paramsData encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
NSString* callbackCommand =
|
||||
[NSString stringWithFormat:@"%@.Bridge.nativeCallback('%@', %@, %@);",
|
||||
JS_HYBRID_OBJ,
|
||||
callbackID,
|
||||
success ? @"true" : @"false",
|
||||
paramsString];
|
||||
|
||||
[self evaluateJavaScript:callbackCommand completionHandler:nil];
|
||||
}
|
||||
|
||||
- (NSString*) webviewID
|
||||
{
|
||||
/*
|
||||
The new implementation of javascript callbacks for WebKit makes this property unnecessary.
|
||||
This method is here simply to serve as a placeholder for purposes of paralleling the RBHybridWebView implementation.
|
||||
*/
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
NSLog(@"RBHybridWKWebView dealloc");
|
||||
[[RBHybridBridge sharedInstance] unRegisterWebView:self];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// RBHybridWebView.h
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/18/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RBHybridWebViewProtocol.h"
|
||||
#import "UIWebView+RBXUIWebView.h"
|
||||
|
||||
@interface RBHybridWebView : UIWebView <RBHybridWebViewProtocol>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// RBHybridWebView.m
|
||||
// RobloxMobile
|
||||
//
|
||||
// Created by Ariel Lichtin on 2/18/15.
|
||||
// Copyright (c) 2015 ROBLOX. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSDictionary+Parsing.h"
|
||||
#import "RBHybridWebView.h"
|
||||
#import "RBHybridBridge.h"
|
||||
#import "RBHybridCommand.h"
|
||||
#import "RBHybridModule.h"
|
||||
#import "SessionReporter.h"
|
||||
#import "UserInfo.h"
|
||||
|
||||
#import "RobloxInfo.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#define JS_HYBRID_OBJ @"window.Roblox.Hybrid"
|
||||
|
||||
@interface RBHybridWebView ()
|
||||
|
||||
@property(nonatomic, readwrite) NSInteger lastRequestID;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RBHybridWebView
|
||||
|
||||
// This is from RBHybridWebViewProtocol
|
||||
@synthesize controller;
|
||||
@synthesize webviewID;
|
||||
@synthesize lastRequestID;
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
[RBHybridWebView initializeUserAgent];
|
||||
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
[self initializeWebView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[RBHybridWebView initializeUserAgent];
|
||||
|
||||
self = [super initWithCoder:coder];
|
||||
if (self)
|
||||
{
|
||||
[self initializeWebView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
[RBHybridWebView initializeUserAgent];
|
||||
|
||||
self = [super initWithFrame:frame];
|
||||
if (self)
|
||||
{
|
||||
[self initializeWebView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+(void)initializeUserAgent
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObject:[RobloxInfo getUserAgentString] forKey:@"UserAgent"]];
|
||||
}
|
||||
|
||||
-(void)initializeWebView
|
||||
{
|
||||
[[RBHybridBridge sharedInstance] registerWebView:self];
|
||||
self.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
|
||||
}
|
||||
|
||||
- (void) executeJavascriptCommand:(NSString *)jsonCommand requestID:(NSInteger)requestId
|
||||
{
|
||||
/*
|
||||
2015.1116 ajain - This code is intentionally the same as the code in RBHybridWKWebView. I wrote this as a centralized method,
|
||||
but as a result of a code review it was determined that duplicating code would be better since in a few months we will stop
|
||||
supporting iOS 7 and UIWebView's which will allow for all this code to be removed.
|
||||
*/
|
||||
NSError* parseError = nil;
|
||||
NSDictionary* params = [NSJSONSerialization JSONObjectWithData:[jsonCommand dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&parseError];
|
||||
if(parseError == nil)
|
||||
{
|
||||
RBHybridCommand* command = [[RBHybridCommand alloc] init];
|
||||
command.requestID = requestId;
|
||||
command.moduleID = [params stringForKey:@"moduleID"];
|
||||
command.functionName = [params stringForKey:@"functionName"];
|
||||
command.params = [params dictionaryForKey:@"params"];
|
||||
command.callbackID = [params stringForKey:@"callbackID"];
|
||||
|
||||
[self executeCommand:command];
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2015.1116 ajain - Something is wrong with the javascript command. Report back.
|
||||
[[SessionReporter sharedInstance] postAnalyticPayloadFromContext:RBXAContextHybrid
|
||||
result:RBXAResultFailure
|
||||
rbxError:RBXAErrorJSONParseFailure
|
||||
startingTime:[NSDate date]
|
||||
attemptedUsername:[UserInfo CurrentPlayer].username
|
||||
URLRequest:nil
|
||||
HTTPResponseCode:202
|
||||
responseData:[jsonCommand dataUsingEncoding:NSUTF8StringEncoding]
|
||||
additionalData:@{@"JSCommandParseErrorDescUI":parseError.description}];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)executeCommand:(RBHybridCommand*)command
|
||||
{
|
||||
command.originWebView = self;
|
||||
|
||||
if(command.requestID > self.lastRequestID)
|
||||
{
|
||||
self.lastRequestID = command.requestID;
|
||||
}
|
||||
|
||||
RBHybridModule* module = [[RBHybridBridge sharedInstance] getModuleForID:command.moduleID];
|
||||
if(module != nil)
|
||||
{
|
||||
[module executeCommand:command];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)executeCallback:(NSString*)callbackID success:(BOOL)success withParams:(NSDictionary*)params
|
||||
{
|
||||
NSError* error;
|
||||
NSString* paramsString = @"{}";
|
||||
if(params != nil)
|
||||
{
|
||||
NSData* paramsData = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:&error];
|
||||
paramsString = [[NSString alloc] initWithData:paramsData encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
NSString* callbackCommand =
|
||||
[NSString stringWithFormat:@"%@.Bridge.nativeCallback('%@', %@, %@);",
|
||||
JS_HYBRID_OBJ,
|
||||
callbackID,
|
||||
success ? @"true" : @"false",
|
||||
paramsString];
|
||||
|
||||
[self stringByEvaluatingJavaScriptFromString:callbackCommand];
|
||||
}
|
||||
|
||||
- (NSString *) webviewID
|
||||
{
|
||||
NSString *getIDCommand = [NSString stringWithFormat:@"%@.Bridge.getWebViewID()", JS_HYBRID_OBJ];
|
||||
NSString *newID = [self stringByEvaluatingJavaScriptFromString:getIDCommand];
|
||||
return newID;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
NSLog(@"RBHybridWebView dealloc");
|
||||
[[RBHybridBridge sharedInstance] unRegisterWebView:self];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user