11

I have dug through a number of posts trying to set up a react native project using cocoapods for native ios libraries but I inevitably end up with an error for a missing file in #import <React/RCTBundleURLProvider.h> statement in my AppDelegate.m file.

What is the proper way to use cocoa pods with react-native? At the time of this post my current version of RN is 0.43.4 and I'm using Xcode 8.2.1.

This was my process, curious where I might be going wrong:

1) In the terminal, I create a new project using react-native init TestProject

2) I run pod init in the ios directory of that project

3) I add a dependency in my podFile and run pod install

4) The install process succeeds, but I see a warning that my targets override the 'OTHER_LDFLAGS' and it's suggested I use $(inherit) in my linker flags in Xcode.

5) So based on this SO post I add $(inherited) to Project> TestProject > BuildSettings > linking> Other Linker Flags which was otherwise empty. I also checked and saw that $(inherited) was already present in Targets > TestProject> Build Settings> Linking> Other Linker Flags and PreProcessor Macros as well.

6) At this point I see React/RCTBundleURLProvider.h file not found error on the #import <React/RCTBundleURLProvider.h> statement in AppDelegate.m

7) Based on this SO post I try deleting the node modules directory and back in the terminal run npm install and when complete 'react-native upgrade'. When it asks me if I want to replace AppDelegate.m and project.pbxproj files I say yes.

8) Back in xCode I clean my build but still have the error from step 6 importing <React/RCTBundleURLProvider.h>

Community
  • 1
  • 1
nwales
  • 3,521
  • 2
  • 25
  • 47
  • I just converted my normal react-native project to cocoapods and it worked perfectly fine. Just had to reset the simulator to avoid some exception. Other than that didn't face any problem. – atulkhatri Apr 26 '19 at 19:49

1 Answers1

11

I just make whole process with start from clean Xcode project. Usually I simple create RN application, eject and then translate to cocoapods ios part. It largely based on RN docs: http://facebook.github.io/react-native/docs/0.51/integration-with-existing-apps.html

So environment: macOS Sierra, Xcode 9.2, RN 0.51.0

Project name: MyApp

Prepare

  • Create new Xcode project, from 'Single View App' template, product name "MyApp", language Objective-C
  • Run, see it works
  • cd MyApp, mkdir ios, mv MyApp* ios (move all ios related files to ios subfolder)

Install npm dependencies

Create package.json in root folder of you project (very basic)

{
  "name": "MyApp",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  },
  "dependencies": {
    "react": "16.0.0",
    "react-native": "0.51.0"
  },
  "devDependencies": {
    "babel-jest": "22.0.4",
    "babel-preset-react-native": "4.0.0"
  }
}

Run npm install

Seup cocoapods

  • cd ios
  • pod init (generate Podfile)
  • declare react dependencies in Podfile in MyApp target
pod 'React', :path => '../node_modules/react-native', :subspecs => [
    'Core',
    'CxxBridge',
    'RCTAnimation',
    'RCTBlob',
    'RCTText',
    'RCTNetwork',
    'RCTWebSocket',
    'RCTImage',
    'RCTLinkingIOS',
    'DevSupport',
  ]
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'GLog', :podspec => '../node_modules/react-native/third-party-podspecs/GLog.podspec'
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'

You can add/remove React subspecs to include/remove RN functionality, this is hard process because RN components not fully independant.

  • pod install (integrate pods into project, will create MyApp.xcworkspace, it should be used to compile application)
  • open MyApp.xcworkspace, build & run, app should still work

Embed RN Root View

Replace you AppDelegate.m with this snippet:

#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#if RCT_DEV
#import <React/RCTDevLoadingView.h>
#endif

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  RCTBundleURLProvider* provider = [RCTBundleURLProvider sharedSettings];
  NSURL* jsCodeLocation = [provider jsBundleURLForBundleRoot:@"index" fallbackResource:nil];

  RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:jsCodeLocation moduleProvider:nil launchOptions:launchOptions];
#if RCT_DEV
  [bridge moduleForClass:[RCTDevLoadingView class]];
#endif
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"MyApp" initialProperties:@{}];
  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  return YES;
}

@end
  • Add ATS exception to Info.plist (or MyApp will be unable to connect to packager server with http)
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>
  • Compile & run in Simulator, you should see red screen with message "No bundle URL present." (it is because no packager server running & no compiled jsbundle exists)

Javascript part

Create MyApp/index.js with this code (it is from RN template):

import { AppRegistry } from 'react-native';
import App from './App';
AppRegistry.registerComponent('MyApp', () => App);

Create MyApp/App.js:

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});
  • start packager npm start from root project folder (MyApp)
  • run app from xcode, you should see loading indicator and then RN rendered screen with "Welcome to React Native!"

Packager

  • You also should add packager build step to embed compiled js to app bundle main.jsbundle so it can be run without packager dev server.

Add script step to MyApp target's Build phases with this content:

export NODE_BINARY=node
../node_modules/react-native/scripts/react-native-xcode.sh

This steps works for me.