{"_id":"59bc03d41d2d8d001a3445b3","category":{"_id":"59bc03d31d2d8d001a34457f","version":"59bc03d31d2d8d001a34457d","project":"578c4badbd223d2000cc1441","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2017-03-17T18:59:29.780Z","from_sync":false,"order":2,"slug":"getting-started-ios","title":"iOS - Platform Setup"},"parentDoc":null,"project":"578c4badbd223d2000cc1441","user":"578c4a62bd223d2000cc143e","version":{"_id":"59bc03d31d2d8d001a34457d","project":"578c4badbd223d2000cc1441","__v":2,"createdAt":"2017-09-15T16:46:11.721Z","releaseDate":"2017-09-15T16:46:11.721Z","categories":["59bc03d31d2d8d001a34457e","59bc03d31d2d8d001a34457f","59bc03d31d2d8d001a344580","59bc03d31d2d8d001a344581","59bc03d31d2d8d001a344582","59bc03d31d2d8d001a344583","59bc284b7c3f420010f965e6"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"2.0.0","version":"2.0.0"},"__v":0,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-07-18T22:08:16.973Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":1,"body":"This documentation was adapted from React Native's [Integration with Existing Apps](https://facebook.github.io/react-native/docs/integration-with-existing-apps.html) guide.\n\n# Integrating with Existing iOS Application\n\nThe instructions below explain how to integrate Viro with your existing iOS project. We use the following github project as an example: https://github.com/JoelMarcey/iOS-2048.\n\nWe'll take this app and modify it to add a Viro scene, effectively vr enabling this app. This doc will show you how to:\n1) Integrate your native iOS app with Viro.\n2) Open Viro within a native app  with with either a stereographic view that requires a cardboard headset or full screen 360 view that doesn't require a headset.\n3) Pass parameters from your native app to Viro.\n\n\n**Note that the following has been tested with React Native 0.41.2**\n\n## Prerequisite\n\nFollow the instructions under Install Dependencies in the [Installing Viro](doc:starting-a-new-viro-project-1) guide.\n\n## Checkout our sample app\n\nCheck out our existing iOS app which we will modify to have a Viro VR View, run the following in a the directory where you want this project:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"git checkout https://github.com/JoelMarcey/iOS-2048\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\n## Adding package.json and node_modules to your project.\n\n### package.json\n\nIn the root directory(where your .xcodeproj is located, create a package.json file and set it's content to the following :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"name\\\": \\\"NumberTileGame\\\",\\n  \\\"version\\\": \\\"0.0.1\\\",\\n  \\\"private\\\": true,\\n  \\\"scripts\\\": {\\n    \\\"start\\\": \\\"node node_modules/react-native/local-cli/cli.js start\\\"\\n  },\\n  \\\"dependencies\\\": {\\n    \\\"react\\\": \\\"16.0.0-alpha.12\\\",\\n    \\\"react-native\\\": \\\"0.47.2\\\",\\n    \\\"react-viro\\\": \\\"2.0.0\\\"\\n  }\\n}  \",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nAfter you add this file run the following in your terminal at your project root:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"npm install\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\n\n### Podfile\n\nIf you don't already use CocoaPods, then run the follow command from within your root project directory to create a `Podfile`:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"pod init\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\nEdit your Podfile to look like the following:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#The target name is most likely the name of your project.\\nplatform :ios, '9.3'\\ntarget 'NumberTileGame' do\\n\\n  # Your 'node_modules' directory is probably in the root of your project,\\n  # but if not, adjust the `:path` accordingly\\n  pod 'React', :path => 'node_modules/react-native', :subspecs => [\\n    'Core',\\n    'RCTText',\\n    'RCTNetwork',\\n    'RCTImage',\\n    'RCTText',\\n    'RCTActionSheet',\\n    'RCTWebSocket', # needed for debugging\\n    # Add any other subspecs you want to use in your project\\n  ]\\n\\n  pod 'ViroReact', :path => 'node_modules/react-viro/ios/'\\n\\nend\",\n      \"language\": \"yaml\"\n    }\n  ]\n}\n[/block]\nConfigure line 2 above with the right path to the /node_modules/react-viro directory if you decided to put your package.json in another directory.\n\n**If you are already using CocoaPods, then simply add the 2 pods `React`  and it's subspecs  as well as `ViroReact` to your `Podfile'. **\n\nOnce you've made your changes, from the terminal, run:\n\n`pod repo update` and `pod install`\n\n###index.ios.js\n\nCreate a file called index.ios.js at the directory root and add the below content:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"'use strict';\\n\\nimport React, { Component } from 'react';\\n\\nimport {\\n  AppRegistry,\\n  ViroSceneNavigator,\\n} from 'react-viro';\\n\\nvar HelloWorldScene = require('./js/TestScene');\\n\\nvar ViroSample = React.createClass({\\n  render: function() {\\n    // The 'viroAppProps={{...this.props}}' line below is used to pass\\n    // the initial properties from this base component to the ViroSceneNavigator\\n    // which will allow the scenes to access them.\\n  \\tlet viroAppProps = {...this.props};\\n    \\n    return (\\n      <ViroSceneNavigator\\n        initialScene={{\\n          scene: HelloWorldScene,\\n        }}\\n        viroAppProps={viroAppProps}\\n        vrModeEnabled={viroAppProps.vrModeEnabled}\\n        apiKey={\\\"YOUR_API_KEY_HERE\\\"}\\n      />\\n    );\\n  }\\n});\\n\\nAppRegistry.registerComponent('RNHighScores', () => ViroSample);\\n\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThis file is the main entry point into the iOS version of your application. Essentially, it creates a basic React class (`ViroSampleApp`) which wraps a `ViroSceneNavigator` and sets the initial scene to a `TestScene` module defined at `./js/TestScene` which we'll create in the next step. It then registers `RNHighScores` with the AppRegistry so that we can launch it by name from objective-C.\n\nNext, replace the text `YOUR_API_KEY_HERE` on line 26 above with the API Key you received.\n\n## TestScene.js\n\nCreate a separate directory at the root named `js`\n\nCreate a file in it called `TestScene.js` with the below contents:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"'use strict';\\n\\nimport React, { Component } from 'react';\\n\\nimport {StyleSheet} from 'react-native';\\n\\nimport {\\n  ViroScene,\\n  ViroText,\\n  Viro360Image,\\n} from 'react-viro';\\n\\nvar TestScene = React.createClass({\\n\\n  render: function() {\\n   \\n    var highScore = \\\"High Score: \\\" + this.props.sceneNavigator.viroAppProps.highScore;\\n    return (\\n     <ViroScene>\\n       <Viro360Image source={require('./res/guadalupe_360.jpg')} />\\n       <ViroText width={2} text={highScore} style={styles.helloWorldTextStyle} position={[0, 0, -4]} />\\n     </ViroScene>\\n    );\\n  },\\n});\\n\\nvar styles = StyleSheet.create({\\n helloWorldTextStyle: {\\n    fontFamily: 'Arial',\\n    fontSize: 30,\\n    color: '#ffffff',\\n    textAlignVertical: 'center',\\n    textAlign: 'center',\\n  },\\n});\\n\\nmodule.exports = TestScene;\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThis scene simply renders a text view with the high score parameter passed from the application.\n### Resources\n\nWe recommend keeping all your resources within one directory in your application for better file management.\n\nCreate a `res` directory at the root of your workspace, download [this](https://s3-us-west-2.amazonaws.com/viro/guadalupe_360.jpg) image and place it in the directory you just created.\n\n## Native Changes\n\nNow that we have all the Viro React components set-up, it's time to modify your iOS code to enter a Viro Scene. The easiest way to do this is to add an event (button click, etc) to an existing view controller. Then in the event callback, create and launch a  `UIViewController` with a `RCTRootView` containing the Viro React app specified in the above index.ios.js file.\n\nLet's do this with the example we are using. \n\nFirst let's edit the apps AppDelegate, in this case F3HAppDelegate. Open F3HAppDelegate.h and add the property **isViroSceneDisplaying**: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import <UIKit/UIKit.h>\\n\\n:::at:::interface F3HAppDelegate : UIResponder <UIApplicationDelegate>\\n\\n@property (strong, nonatomic) UIWindow *window;\\n@property (nonatomic, assign) BOOL isViroSceneDisplaying;\\n\\n@end\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nNow add the method below to F3HAppDelegate.m:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {\\n  // Force the oprientation into landscape mode if we are displaying a ViroSceneViewController.\\n  if(self.isViroSceneDisplaying) {\\n    return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationLandscapeRight);\\n  }\\n  return UIInterfaceOrientationMaskAllButUpsideDown;\\n}\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nThis ensures that when a Viro scene displays the rotation will be set to landscape at the app level.\nNow lets create a UIViewController derived class called ViroViewController. The header file should look like below:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"//\\n//  ViroViewController.h\\n//  NumberTileGame\\n//\\n\\n#import <Foundation/Foundation.h>\\n\\n@interface ViroViewController : UIViewController\\n  -(id)initWithVREnabledMode:(BOOL)vrEnabledMode;\\n\\n@property (nonatomic, assign) BOOL vrMode;\\n@end\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nNow in ViroViewController.m add the following methods so the file looks like below:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \" \\n\\n//\\n//  ViroViewController.m\\n//  NumberTileGame\\n//\\n\\n#import \\\"ViroViewController.h\\\"\\n#import \\\"F3HAppDelegate.h\\\"\\n#import \\\"VRTNotifications.h\\\"\\n\\n@implementation ViroViewController\\n\\nstatic NSInteger const kBackButtonSize = 38;\\nstatic NSInteger const kBackButtonInsetTop = 8;\\nstatic NSInteger const kBackButtonInsetLeft = 12;\\n\\n\\n-(id)initWithVREnabledMode:(BOOL)vrEnabledMode {\\n  self = [super init];\\n  self.vrMode = vrEnabledMode;\\n  return self;\\n}\\n\\n- (void)viewWillAppear:(BOOL)animated {\\n    F3HAppDelegate *delegate = (F3HAppDelegate *)[[UIApplication sharedApplication] delegate];\\n    delegate.isViroSceneDisplaying = YES;\\n  \\n  \\n  // Add an exit button only if we're in 360 fullscreen mode, cardboard comes with its own exit button.\\n   if (!self.vrMode) {\\n      UIImage *defaultImage = [UIImage imageNamed:@\\\"nativeapp_360_btn_back.png\\\"];\\n      UIImage* defaultImageRotated = [UIImage imageWithCGImage:defaultImage.CGImage\\n                                                  scale:defaultImage.scale\\n                                            orientation:UIImageOrientationRight];\\n      UIImage *highlightedImage = [UIImage imageNamed:@\\\"nativeapp_360_btn_back_press.png\\\"];\\n      UIImage *highlightedImageRotated = [UIImage imageWithCGImage:highlightedImage.CGImage scale:highlightedImage.scale orientation:UIImageOrientationRight];\\n      \\n      CGRect screenRect = [[UIScreen mainScreen] bounds];\\n      CGFloat screenWidth = screenRect.size.width;\\n      self.exit360Button = [[UIButton alloc] initWithFrame:CGRectMake(screenWidth- kBackButtonSize, 0, kBackButtonSize, kBackButtonSize)];\\n      self.exit360Button.imageEdgeInsets = UIEdgeInsetsMake(kBackButtonInsetTop, kBackButtonInsetLeft, 0, 0);\\n      [self.exit360Button addTarget:self\\n                           action:@selector(exitReactViro)\\n                 forControlEvents:UIControlEventTouchUpInside];\\n      [self.exit360Button setImage:defaultImageRotated forState:UIControlStateNormal];\\n      [self.exit360Button setImage:highlightedImageRotated forState:UIControlStateHighlighted];\\n      self.exit360Button.userInteractionEnabled = YES;\\n      [self.view addSubview:self.exit360Button];\\n      [self.view bringSubviewToFront:self.exit360Button];\\n    }\\n\\n  \\n  // register for the exit notification\\n  [[NSNotificationCenter defaultCenter] addObserver:self\\n                                           selector:@selector(exitReactViro)\\n                                               name:kVRTOnExitViro\\n                                             object:nil];\\n  \\n}\\n\\n- (UIInterfaceOrientationMask)supportedInterfaceOrientations {\\n  return (UIInterfaceOrientationLandscapeLeft);\\n}\\n\\n-(BOOL)shouldAutorotate {\\n  return NO;\\n}\\n\\n- (void)exitReactViro {\\n  dispatch_async(dispatch_get_main_queue(), ^{\\n    F3HAppDelegate *delegate = (F3HAppDelegate *)[[UIApplication sharedApplication] delegate];\\n    delegate.isViroSceneDisplaying = NO;\\n    if(self.vrMode) {\\n      [self willMoveToParentViewController:nil];\\n      [self.view removeFromSuperview];\\n      [self removeFromParentViewController];\\n    } else {\\n      [self dismissViewControllerAnimated:NO completion:nil];\\n    }\\n    [[NSNotificationCenter defaultCenter] removeObserver:self];\\n  });\\n}\\n\\n@end\\n\\n  \\n  \",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nLet's go thru the above code in detail to understand what it's doing. The rotation methods **shouldAutorotate** and **supportedInterfaceOrientations** ensure that when we launch into VR or 360 mode(fullscreen mode that doesn't require a cardboard headset) we ensure the app stays in landscape mode.\n\nThe **viewDidAppear** appear method is invoked when our controller is about to appear. In this method we do the following: \n1) Tell our appDelegate we are displaying our VR scene by setting **isViroSceneDisplaying** to true.\n2) Create a back button for full screen 360 mode. This will only be displayed if vrMode = false. \n **Graphics for the back button located here and here, please add them to the apps resources.**\n\n3) Register to listen for notification **kVRTOnExitViro**. This is a notification that Viro invokes to let you know that Viro is exiting so you can perform your own cleanup. In this case we state we want to invoke the **exitReactViro** method.\n\nThe **exitReactViro** method is invoked when we exit the Viro View. Depending on if vrMode is true or false, we signal to our parent controller that we are dismissing. In addition, we tell the appDelegate we are no longer displaying a Viro scene and remove ourselves as a listener for NSNotificationCenter.\n\nNow let's use our new ViroViewController and integrate it into our current app. Add a method call highScoreButtonPressed to F3HController.m like below:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"- (IBAction)highScoreButtonPressed:(id)sender {\\n  BOOL vrEnabled = true;\\n  NSDictionary *initialProperties =\\n  @{\\n    @\\\"highScore\\\" : @\\\"40\\\",\\n   @\\\"vrModeEnabled\\\" : [NSNumber numberWithBool:vrEnabled]\\n   };\\n  \\n  NSURL *jsCodeLocation = nil;\\n#ifdef DEBUG\\n  jsCodeLocation = [NSURL                        URLWithString:@\\\"https://<YOUR IP or NGROK ENDPOINT>/index.ios.bundle?platform=ios\\\"];\\n#else\\n  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\\\"index.ios\\\"                                                                 fallbackResource:nil];\\n#endif\\n\\n  RCTRootView *rootView =\\n  [[RCTRootView alloc] initWithBundleURL : jsCodeLocation\\n                       moduleName        : @\\\"RNHighScores\\\"\\n                       initialProperties :initialProperties\\n                        launchOptions    : nil];\\n  ViroViewController *vc = [[ViroViewController alloc] initWithVREnabledMode:vrEnabled];\\n  vc.view = rootView;\\n  F3HAppDelegate *delegate = (F3HAppDelegate *)[[UIApplication sharedApplication] delegate];\\n  //present the controller differently depending on whether we are in vr mode or not.\\n  if(vrMode) {\\n    [self addChildViewController:vc];\\n    vc.view.frame = CGRectMake(0,   0,self.view.frame.size.width,self.view.frame.size.height);\\n    [self.view addSubview:vc.view];\\n    [vc didMoveToParentViewController:self];\\n  } else{\\n      vc.modalPresentationStyle = UIModalPresentationFullScreen;\\n      [self presentViewController:vc animated:YES completion:nil];\\n  }\\n\\n  [self presentViewController:vc animated:YES completion:nil];\\n}\\n\\n\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nThe above method does the following: \n1) Creates a dictionary that gets passed to the initial javascript file index.ios.js.\n2) If we are in debug our source js location is assumed to be using the react native packager server which can run from your local IP or ngrok endpoint. Replace <YOUR IP or NGROK ENDPOINT> text with the ip address or ngrok endpoint of your react packager. If in release, we load the a bundled js file from disk.\n3) We then create the React Native RCTRootView and set is at the view of our new controller.\n4) Now we present the controller. Depending on whether we want stereographic vr view that requires a cardboard headset(vrEnabled = true) or a full screen 360 mode experience(vrEnabled=false), we present the controller differently due to how Google Cardboard SDK works.\n\nNow hook up the View Controller High Score text to the new method *highScoreButtonPressed* using Interface Builder like below:\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/a95d65e-Screen_Shot_2017-03-30_at_2.10.28_AM.png\",\n        \"Screen Shot 2017-03-30 at 2.10.28 AM.png\",\n        1538,\n        1128,\n        \"#353435\"\n      ]\n    }\n  ]\n}\n[/block]\nAnd *Voilà!* you've now added a Viro Scene into your application. \n\n##Modify Build Settings\nIn the build settings of the project do the following: \n1)Change enable Bitcode to **no**:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/de2e3a8-Screen_Shot_2017-03-30_at_2.19.03_AM.png\",\n        \"Screen Shot 2017-03-30 at 2.19.03 AM.png\",\n        1554,\n        788,\n        \"#40322b\"\n      ]\n    }\n  ]\n}\n[/block]\n2)Set deployment target to iOS 9.3 or higher.\n\n##Run the App\nNow you are almost ready to run your VR integrated app:\n1) In terminal, where your .xcodeproj is located, run npm start to launch the react packager that will retrieve your JS files from xcode.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"npm start\\n\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\n2) Find your IP or your ngrok endpoint if you run 'ngrok http 8081' on the terminal. Cut and paste that into where it says <YOUR IP or NGROK ENDPOINT> in F3HController.m\n3)Run your app in debug!\n\nViola, you have now added VR to an existing app!\nTap on the high score text to see the VR mode launch and display the text that was passed in from the native code!\n\n##Running your app in fullscreen 360 mode.\n\nSometimes you may wish to launch into a full screen mode, rather than a a stereoscopic mode that requires a headset. To do this, in the above code, modify the vrEnabled flag to be false. This will launch the app in full screen 360 mode. \n\nIf you wish to have the user choose what they prefer, then it's best to add an iOS dialog before you push the view controller that asks them if they have a headset or not. The vrEnabled flag can be set based on what they choose.\n\n## Building for Release.\nTo run your new VR Enabled iOS App in release you'll need to add a new 'Run Script' build phase.\nPaste the following code into the the run script phase:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"export NODE_BINARY=node\\n\\n$SRCROOT/node_modules/react-native/packager/react-native-xcode.sh $SRCROOT/index.ios.js\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\nThis above script will compile and bundle the necessary assets and js code into your app for release.\nHere's how it looks it Xcode for reference: \n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/cbf6afe-Screen_Shot_2017-03-30_at_7.14.44_PM.png\",\n        \"Screen Shot 2017-03-30 at 7.14.44 PM.png\",\n        1602,\n        864,\n        \"#dadad8\"\n      ]\n    }\n  ]\n}\n[/block]\nNow select the NumbeTileGame scheme and switch the build type to 'Release' like below: \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/e6602bd-Screen_Shot_2017-03-30_at_7.19.47_PM.png\",\n        \"Screen Shot 2017-03-30 at 7.19.47 PM.png\",\n        1770,\n        896,\n        \"#eaeaea\"\n      ]\n    }\n  ]\n}\n[/block]\nCompile and build and the app. It should run in release without connecting to any react package server. This is how your app will look in production!\n\n## Troubleshooting\n\nPlease refer to the troubleshooting section at the bottom of the [Installing Viro](doc:starting-a-new-viro-project-1#section-troubleshooting) guide.","excerpt":"","slug":"integrate-project-with-viro","type":"basic","title":"Integrating Existing Projects (iOS)"}

Integrating Existing Projects (iOS)


This documentation was adapted from React Native's [Integration with Existing Apps](https://facebook.github.io/react-native/docs/integration-with-existing-apps.html) guide. # Integrating with Existing iOS Application The instructions below explain how to integrate Viro with your existing iOS project. We use the following github project as an example: https://github.com/JoelMarcey/iOS-2048. We'll take this app and modify it to add a Viro scene, effectively vr enabling this app. This doc will show you how to: 1) Integrate your native iOS app with Viro. 2) Open Viro within a native app with with either a stereographic view that requires a cardboard headset or full screen 360 view that doesn't require a headset. 3) Pass parameters from your native app to Viro. **Note that the following has been tested with React Native 0.41.2** ## Prerequisite Follow the instructions under Install Dependencies in the [Installing Viro](doc:starting-a-new-viro-project-1) guide. ## Checkout our sample app Check out our existing iOS app which we will modify to have a Viro VR View, run the following in a the directory where you want this project: [block:code] { "codes": [ { "code": "git checkout https://github.com/JoelMarcey/iOS-2048", "language": "text" } ] } [/block] ## Adding package.json and node_modules to your project. ### package.json In the root directory(where your .xcodeproj is located, create a package.json file and set it's content to the following : [block:code] { "codes": [ { "code": "{\n \"name\": \"NumberTileGame\",\n \"version\": \"0.0.1\",\n \"private\": true,\n \"scripts\": {\n \"start\": \"node node_modules/react-native/local-cli/cli.js start\"\n },\n \"dependencies\": {\n \"react\": \"16.0.0-alpha.12\",\n \"react-native\": \"0.47.2\",\n \"react-viro\": \"2.0.0\"\n }\n} ", "language": "javascript" } ] } [/block] After you add this file run the following in your terminal at your project root: [block:code] { "codes": [ { "code": "npm install", "language": "shell" } ] } [/block] ### Podfile If you don't already use CocoaPods, then run the follow command from within your root project directory to create a `Podfile`: [block:code] { "codes": [ { "code": "pod init", "language": "shell" } ] } [/block] Edit your Podfile to look like the following: [block:code] { "codes": [ { "code": "#The target name is most likely the name of your project.\nplatform :ios, '9.3'\ntarget 'NumberTileGame' do\n\n # Your 'node_modules' directory is probably in the root of your project,\n # but if not, adjust the `:path` accordingly\n pod 'React', :path => 'node_modules/react-native', :subspecs => [\n 'Core',\n 'RCTText',\n 'RCTNetwork',\n 'RCTImage',\n 'RCTText',\n 'RCTActionSheet',\n 'RCTWebSocket', # needed for debugging\n # Add any other subspecs you want to use in your project\n ]\n\n pod 'ViroReact', :path => 'node_modules/react-viro/ios/'\n\nend", "language": "yaml" } ] } [/block] Configure line 2 above with the right path to the /node_modules/react-viro directory if you decided to put your package.json in another directory. **If you are already using CocoaPods, then simply add the 2 pods `React` and it's subspecs as well as `ViroReact` to your `Podfile'. ** Once you've made your changes, from the terminal, run: `pod repo update` and `pod install` ###index.ios.js Create a file called index.ios.js at the directory root and add the below content: [block:code] { "codes": [ { "code": "'use strict';\n\nimport React, { Component } from 'react';\n\nimport {\n AppRegistry,\n ViroSceneNavigator,\n} from 'react-viro';\n\nvar HelloWorldScene = require('./js/TestScene');\n\nvar ViroSample = React.createClass({\n render: function() {\n // The 'viroAppProps={{...this.props}}' line below is used to pass\n // the initial properties from this base component to the ViroSceneNavigator\n // which will allow the scenes to access them.\n \tlet viroAppProps = {...this.props};\n \n return (\n <ViroSceneNavigator\n initialScene={{\n scene: HelloWorldScene,\n }}\n viroAppProps={viroAppProps}\n vrModeEnabled={viroAppProps.vrModeEnabled}\n apiKey={\"YOUR_API_KEY_HERE\"}\n />\n );\n }\n});\n\nAppRegistry.registerComponent('RNHighScores', () => ViroSample);\n", "language": "javascript" } ] } [/block] This file is the main entry point into the iOS version of your application. Essentially, it creates a basic React class (`ViroSampleApp`) which wraps a `ViroSceneNavigator` and sets the initial scene to a `TestScene` module defined at `./js/TestScene` which we'll create in the next step. It then registers `RNHighScores` with the AppRegistry so that we can launch it by name from objective-C. Next, replace the text `YOUR_API_KEY_HERE` on line 26 above with the API Key you received. ## TestScene.js Create a separate directory at the root named `js` Create a file in it called `TestScene.js` with the below contents: [block:code] { "codes": [ { "code": "'use strict';\n\nimport React, { Component } from 'react';\n\nimport {StyleSheet} from 'react-native';\n\nimport {\n ViroScene,\n ViroText,\n Viro360Image,\n} from 'react-viro';\n\nvar TestScene = React.createClass({\n\n render: function() {\n \n var highScore = \"High Score: \" + this.props.sceneNavigator.viroAppProps.highScore;\n return (\n <ViroScene>\n <Viro360Image source={require('./res/guadalupe_360.jpg')} />\n <ViroText width={2} text={highScore} style={styles.helloWorldTextStyle} position={[0, 0, -4]} />\n </ViroScene>\n );\n },\n});\n\nvar styles = StyleSheet.create({\n helloWorldTextStyle: {\n fontFamily: 'Arial',\n fontSize: 30,\n color: '#ffffff',\n textAlignVertical: 'center',\n textAlign: 'center',\n },\n});\n\nmodule.exports = TestScene;", "language": "javascript" } ] } [/block] This scene simply renders a text view with the high score parameter passed from the application. ### Resources We recommend keeping all your resources within one directory in your application for better file management. Create a `res` directory at the root of your workspace, download [this](https://s3-us-west-2.amazonaws.com/viro/guadalupe_360.jpg) image and place it in the directory you just created. ## Native Changes Now that we have all the Viro React components set-up, it's time to modify your iOS code to enter a Viro Scene. The easiest way to do this is to add an event (button click, etc) to an existing view controller. Then in the event callback, create and launch a `UIViewController` with a `RCTRootView` containing the Viro React app specified in the above index.ios.js file. Let's do this with the example we are using. First let's edit the apps AppDelegate, in this case F3HAppDelegate. Open F3HAppDelegate.h and add the property **isViroSceneDisplaying**: [block:code] { "codes": [ { "code": "#import <UIKit/UIKit.h>\n\n@interface F3HAppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (strong, nonatomic) UIWindow *window;\n@property (nonatomic, assign) BOOL isViroSceneDisplaying;\n\n@end", "language": "objectivec" } ] } [/block] Now add the method below to F3HAppDelegate.m: [block:code] { "codes": [ { "code": "- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {\n // Force the oprientation into landscape mode if we are displaying a ViroSceneViewController.\n if(self.isViroSceneDisplaying) {\n return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationLandscapeRight);\n }\n return UIInterfaceOrientationMaskAllButUpsideDown;\n}", "language": "objectivec" } ] } [/block] This ensures that when a Viro scene displays the rotation will be set to landscape at the app level. Now lets create a UIViewController derived class called ViroViewController. The header file should look like below: [block:code] { "codes": [ { "code": "//\n// ViroViewController.h\n// NumberTileGame\n//\n\n#import <Foundation/Foundation.h>\n\n@interface ViroViewController : UIViewController\n -(id)initWithVREnabledMode:(BOOL)vrEnabledMode;\n\n@property (nonatomic, assign) BOOL vrMode;\n@end", "language": "objectivec" } ] } [/block] Now in ViroViewController.m add the following methods so the file looks like below: [block:code] { "codes": [ { "code": " \n\n//\n// ViroViewController.m\n// NumberTileGame\n//\n\n#import \"ViroViewController.h\"\n#import \"F3HAppDelegate.h\"\n#import \"VRTNotifications.h\"\n\n@implementation ViroViewController\n\nstatic NSInteger const kBackButtonSize = 38;\nstatic NSInteger const kBackButtonInsetTop = 8;\nstatic NSInteger const kBackButtonInsetLeft = 12;\n\n\n-(id)initWithVREnabledMode:(BOOL)vrEnabledMode {\n self = [super init];\n self.vrMode = vrEnabledMode;\n return self;\n}\n\n- (void)viewWillAppear:(BOOL)animated {\n F3HAppDelegate *delegate = (F3HAppDelegate *)[[UIApplication sharedApplication] delegate];\n delegate.isViroSceneDisplaying = YES;\n \n \n // Add an exit button only if we're in 360 fullscreen mode, cardboard comes with its own exit button.\n if (!self.vrMode) {\n UIImage *defaultImage = [UIImage imageNamed:@\"nativeapp_360_btn_back.png\"];\n UIImage* defaultImageRotated = [UIImage imageWithCGImage:defaultImage.CGImage\n scale:defaultImage.scale\n orientation:UIImageOrientationRight];\n UIImage *highlightedImage = [UIImage imageNamed:@\"nativeapp_360_btn_back_press.png\"];\n UIImage *highlightedImageRotated = [UIImage imageWithCGImage:highlightedImage.CGImage scale:highlightedImage.scale orientation:UIImageOrientationRight];\n \n CGRect screenRect = [[UIScreen mainScreen] bounds];\n CGFloat screenWidth = screenRect.size.width;\n self.exit360Button = [[UIButton alloc] initWithFrame:CGRectMake(screenWidth- kBackButtonSize, 0, kBackButtonSize, kBackButtonSize)];\n self.exit360Button.imageEdgeInsets = UIEdgeInsetsMake(kBackButtonInsetTop, kBackButtonInsetLeft, 0, 0);\n [self.exit360Button addTarget:self\n action:@selector(exitReactViro)\n forControlEvents:UIControlEventTouchUpInside];\n [self.exit360Button setImage:defaultImageRotated forState:UIControlStateNormal];\n [self.exit360Button setImage:highlightedImageRotated forState:UIControlStateHighlighted];\n self.exit360Button.userInteractionEnabled = YES;\n [self.view addSubview:self.exit360Button];\n [self.view bringSubviewToFront:self.exit360Button];\n }\n\n \n // register for the exit notification\n [[NSNotificationCenter defaultCenter] addObserver:self\n selector:@selector(exitReactViro)\n name:kVRTOnExitViro\n object:nil];\n \n}\n\n- (UIInterfaceOrientationMask)supportedInterfaceOrientations {\n return (UIInterfaceOrientationLandscapeLeft);\n}\n\n-(BOOL)shouldAutorotate {\n return NO;\n}\n\n- (void)exitReactViro {\n dispatch_async(dispatch_get_main_queue(), ^{\n F3HAppDelegate *delegate = (F3HAppDelegate *)[[UIApplication sharedApplication] delegate];\n delegate.isViroSceneDisplaying = NO;\n if(self.vrMode) {\n [self willMoveToParentViewController:nil];\n [self.view removeFromSuperview];\n [self removeFromParentViewController];\n } else {\n [self dismissViewControllerAnimated:NO completion:nil];\n }\n [[NSNotificationCenter defaultCenter] removeObserver:self];\n });\n}\n\n@end\n\n \n ", "language": "objectivec" } ] } [/block] Let's go thru the above code in detail to understand what it's doing. The rotation methods **shouldAutorotate** and **supportedInterfaceOrientations** ensure that when we launch into VR or 360 mode(fullscreen mode that doesn't require a cardboard headset) we ensure the app stays in landscape mode. The **viewDidAppear** appear method is invoked when our controller is about to appear. In this method we do the following: 1) Tell our appDelegate we are displaying our VR scene by setting **isViroSceneDisplaying** to true. 2) Create a back button for full screen 360 mode. This will only be displayed if vrMode = false. **Graphics for the back button located here and here, please add them to the apps resources.** 3) Register to listen for notification **kVRTOnExitViro**. This is a notification that Viro invokes to let you know that Viro is exiting so you can perform your own cleanup. In this case we state we want to invoke the **exitReactViro** method. The **exitReactViro** method is invoked when we exit the Viro View. Depending on if vrMode is true or false, we signal to our parent controller that we are dismissing. In addition, we tell the appDelegate we are no longer displaying a Viro scene and remove ourselves as a listener for NSNotificationCenter. Now let's use our new ViroViewController and integrate it into our current app. Add a method call highScoreButtonPressed to F3HController.m like below: [block:code] { "codes": [ { "code": "- (IBAction)highScoreButtonPressed:(id)sender {\n BOOL vrEnabled = true;\n NSDictionary *initialProperties =\n @{\n @\"highScore\" : @\"40\",\n @\"vrModeEnabled\" : [NSNumber numberWithBool:vrEnabled]\n };\n \n NSURL *jsCodeLocation = nil;\n#ifdef DEBUG\n jsCodeLocation = [NSURL URLWithString:@\"https://<YOUR IP or NGROK ENDPOINT>/index.ios.bundle?platform=ios\"];\n#else\n jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index.ios\" fallbackResource:nil];\n#endif\n\n RCTRootView *rootView =\n [[RCTRootView alloc] initWithBundleURL : jsCodeLocation\n moduleName : @\"RNHighScores\"\n initialProperties :initialProperties\n launchOptions : nil];\n ViroViewController *vc = [[ViroViewController alloc] initWithVREnabledMode:vrEnabled];\n vc.view = rootView;\n F3HAppDelegate *delegate = (F3HAppDelegate *)[[UIApplication sharedApplication] delegate];\n //present the controller differently depending on whether we are in vr mode or not.\n if(vrMode) {\n [self addChildViewController:vc];\n vc.view.frame = CGRectMake(0, 0,self.view.frame.size.width,self.view.frame.size.height);\n [self.view addSubview:vc.view];\n [vc didMoveToParentViewController:self];\n } else{\n vc.modalPresentationStyle = UIModalPresentationFullScreen;\n [self presentViewController:vc animated:YES completion:nil];\n }\n\n [self presentViewController:vc animated:YES completion:nil];\n}\n\n", "language": "objectivec" } ] } [/block] The above method does the following: 1) Creates a dictionary that gets passed to the initial javascript file index.ios.js. 2) If we are in debug our source js location is assumed to be using the react native packager server which can run from your local IP or ngrok endpoint. Replace <YOUR IP or NGROK ENDPOINT> text with the ip address or ngrok endpoint of your react packager. If in release, we load the a bundled js file from disk. 3) We then create the React Native RCTRootView and set is at the view of our new controller. 4) Now we present the controller. Depending on whether we want stereographic vr view that requires a cardboard headset(vrEnabled = true) or a full screen 360 mode experience(vrEnabled=false), we present the controller differently due to how Google Cardboard SDK works. Now hook up the View Controller High Score text to the new method *highScoreButtonPressed* using Interface Builder like below: [block:image] { "images": [ { "image": [ "https://files.readme.io/a95d65e-Screen_Shot_2017-03-30_at_2.10.28_AM.png", "Screen Shot 2017-03-30 at 2.10.28 AM.png", 1538, 1128, "#353435" ] } ] } [/block] And *Voilà!* you've now added a Viro Scene into your application. ##Modify Build Settings In the build settings of the project do the following: 1)Change enable Bitcode to **no**: [block:image] { "images": [ { "image": [ "https://files.readme.io/de2e3a8-Screen_Shot_2017-03-30_at_2.19.03_AM.png", "Screen Shot 2017-03-30 at 2.19.03 AM.png", 1554, 788, "#40322b" ] } ] } [/block] 2)Set deployment target to iOS 9.3 or higher. ##Run the App Now you are almost ready to run your VR integrated app: 1) In terminal, where your .xcodeproj is located, run npm start to launch the react packager that will retrieve your JS files from xcode. [block:code] { "codes": [ { "code": "npm start\n", "language": "shell" } ] } [/block] 2) Find your IP or your ngrok endpoint if you run 'ngrok http 8081' on the terminal. Cut and paste that into where it says <YOUR IP or NGROK ENDPOINT> in F3HController.m 3)Run your app in debug! Viola, you have now added VR to an existing app! Tap on the high score text to see the VR mode launch and display the text that was passed in from the native code! ##Running your app in fullscreen 360 mode. Sometimes you may wish to launch into a full screen mode, rather than a a stereoscopic mode that requires a headset. To do this, in the above code, modify the vrEnabled flag to be false. This will launch the app in full screen 360 mode. If you wish to have the user choose what they prefer, then it's best to add an iOS dialog before you push the view controller that asks them if they have a headset or not. The vrEnabled flag can be set based on what they choose. ## Building for Release. To run your new VR Enabled iOS App in release you'll need to add a new 'Run Script' build phase. Paste the following code into the the run script phase: [block:code] { "codes": [ { "code": "export NODE_BINARY=node\n\n$SRCROOT/node_modules/react-native/packager/react-native-xcode.sh $SRCROOT/index.ios.js", "language": "shell" } ] } [/block] This above script will compile and bundle the necessary assets and js code into your app for release. Here's how it looks it Xcode for reference: [block:image] { "images": [ { "image": [ "https://files.readme.io/cbf6afe-Screen_Shot_2017-03-30_at_7.14.44_PM.png", "Screen Shot 2017-03-30 at 7.14.44 PM.png", 1602, 864, "#dadad8" ] } ] } [/block] Now select the NumbeTileGame scheme and switch the build type to 'Release' like below: [block:image] { "images": [ { "image": [ "https://files.readme.io/e6602bd-Screen_Shot_2017-03-30_at_7.19.47_PM.png", "Screen Shot 2017-03-30 at 7.19.47 PM.png", 1770, 896, "#eaeaea" ] } ] } [/block] Compile and build and the app. It should run in release without connecting to any react package server. This is how your app will look in production! ## Troubleshooting Please refer to the troubleshooting section at the bottom of the [Installing Viro](doc:starting-a-new-viro-project-1#section-troubleshooting) guide.