Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] Add CocoaPods Podfile to the project template #23563

Closed
wants to merge 15 commits into from

Conversation

fson
Copy link
Contributor

@fson fson commented Feb 20, 2019

Summary

CocoaPods makes it easier to add new iOS dependencies to a project without having to manually edit Xcode projects. Editing Xcode projects is time consuming and merging changes to them difficult. Automating the changes to Xcode project react-native link is error prone. CocoaPods is a de-facto standard way to manage iOS dependencies and a central part of unimodules and upcoming improvements to react-native link.

This PR adds a Podfile to the default project template of React Native. To use a project with CocoaPods, after creating it, run cd ios; pod install and use the created <projectname>.xcworkspace file instead of the .xcodeproj file. (We could make this a part of react-native init so you only need to run one command when creating a project.)

Changelog

[iOS] [Added] - Add CocoaPods Podfile to the project template

Test Plan

Ran yarn pack in the repository root and then created a project and ran it successfully:

react-native init HelloWorld --version <full-path-here>/react-native/react-native-v1000.0.0.tgz
cd HelloWorld/ios
pod install
cd ..
react-native run-ios

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Feb 20, 2019
@radeno
Copy link
Contributor

radeno commented Feb 21, 2019

@fson same like in another PR. There should be iOS platform version 9.0
I like this PR

@fson fson changed the title Add CocoaPods Podfile to the project template [iOS] Add CocoaPods Podfile to the project template Feb 22, 2019
@hramos hramos added Partner p: Expo Partner: Expo labels Feb 23, 2019
@cpojer
Copy link
Contributor

cpojer commented Feb 26, 2019

@fson what's the status of this PR?

@pepicrft
Copy link

This idea is a great first step. Thanks for working on making the experience of using React Native more convenient.

I have a little question, have you tried running pod install in a clean environment where CocoaPods doesn't have the specs repository pre-fetched? At my company we run our CI builds in disposable environments so having CocoaPods updating the specs for every build would significantly increase the build time.

@zhigang1992
Copy link
Contributor

Some concerns regarding using CocoaPods by default.

https://rnfirebase.io/docs/v5.x.x/installation/ios#Option-2:-Cocoapods-(Not-Recommended)

But if we start recommending cocoapods we might be able to turn it around.

@zhigang1992
Copy link
Contributor

If we do provide Podfile should we include Podfile.lock?

Should we include Gemfile and Gemfile.lock to lock down the version of CocoaPods?

@FibreFoX
Copy link

FibreFoX commented Mar 3, 2019

@zhigang1992 is that still valid (yes, I saw that note on rnfirebase too)? As far as I can see, proper support for use_frameworks! is included since CocoaPods 1.5.0: http://blog.cocoapods.org/CocoaPods-1.5.0/
Even inside the documentation it states to have that supported (you might need to select the Single Page version): https://guides.cocoapods.org/syntax/podfile.html#tab_use_frameworks_bang

Not an iOS/XCode/CocoaPods-expert myself, but came across this note too, and having support for CocoaPods seems a more "clean" approach IMHO. 👍

@pepicrft
Copy link

pepicrft commented Mar 5, 2019

Should we include Gemfile and Gemfile.lock to lock down the version of CocoaPods?

You should include them because it'd make builds reproducible. CocoaPods has generally been good at releasing new versions that are backward compatible but I'd better pin the version.

If we do provide Podfile should we include Podfile.lock?

If the pods are part of the packages resolved by npm or yarn, I don't think there's a need to include this one @zhigang1992. I'd only include it if you have dependencies in your Podfile that are pulled from the central registry.

@pvinis
Copy link
Contributor

pvinis commented Mar 5, 2019

I'm all for that, but when do we update this? What if I use a version later than the one used here, what then?

@radeno
Copy link
Contributor

radeno commented Mar 5, 2019

@pvinis Gemfile is very similar to package.json you don't need to lock to specific version. But you can lock it to whole 1.X branch with gem 'cocoapods', '~> 1.6' in Gemfile.
Do not include Gemfile.lock, its same as yarn.lock. We don't need it in repo, it is user scope.
When platform is locked in Podfile why not locking minimal version Cocoapods ?

@pvinis
Copy link
Contributor

pvinis commented Mar 5, 2019

I didn't get exactly what you mean. The Gemfile having cocoapods in it is not like package.json. It would be like if package.json had the yarn version in it. That's why I ask. Right now, in many RN projects I have a Gemfile already, with cocoapods and fastlane for example. I guess that would be alright if the template has some version and I modify it, same as the template having a flowconfig version for example, that I also have modified before. I guess there will be no problem, I'm just saying.

@radeno
Copy link
Contributor

radeno commented Mar 5, 2019

@pvinis do you say about Gemfile or Podfile?
Cocoapods is Ruby gem, and Ruby gems are defined by Gemfile. Podfile is Cocoapods definition file, inspired by Gemfile. It is already used many years in iOS development workflow. Another project is Carthage for iOS development.

If Podfile should be 100% compatible with very user, you need to specify minimal Cocoapods version. And for that you need Gemfile.

@pvinis
Copy link
Contributor

pvinis commented Mar 5, 2019

I'll just wait for the example. I know what you are saying. I understand it. (I even prefer carthage for some reasons.) Anyway, forget what I said. :)

@onmyway133
Copy link

onmyway133 commented Mar 5, 2019

@fson This PR will solve issue like this duplicated React framework invertase/react-native-firebase#414 (comment)? Because for now React comes as embedded and pod install adds another React pod

@pepicrft
Copy link

pepicrft commented Mar 5, 2019

@fson let me know if you'd need any help with this work. I'm happy to make a contribution to the project.

@grabbou
Copy link
Contributor

grabbou commented Mar 11, 2019

@fson, what's the status here? We wanted to ship it with 0.60 and we are about to cut that release soon (in fact, we could do it as early as today).

@react-native-bot react-native-bot added Platform: iOS iOS applications. PR: Includes Changelog Type: Enhancement A new feature or enhancement of an existing feature. labels Mar 14, 2019
@fson fson marked this pull request as ready for review March 15, 2019 16:16
@fson
Copy link
Contributor Author

fson commented Mar 15, 2019

This PR should be ready to review and ship! (Sorry I had forgotten the draft status on 😅)

pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker, but all of the above could be grabbed via a glob for Podspecs:

Dir.glob('../node_modules/react-native/**/*.podspec').each do |react_pod| 
  name = File.basename(react_pod, "podspec")
  path = File.dirname(react_pod)
  pod name, :path => path
end

This'll probably get deprecated by react-native-community/cli#256 eventually though

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so cool we can handle built-in podspecs with that API too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@orta this is cool and much nicer for version upgrades. However, the code above doesn't produce the same result, because not all podspecs in the code base are included by default. These libraries were not linked in by default in the old Xcode project and correspondingly those pods are not dependencies of the React podspec:

./Libraries/ART/React-ART.podspec
./Libraries/CameraRoll/React-RCTCameraRoll.podspec
./Libraries/PushNotificationIOS/React-RCTPushNotification.podspec
./React/React-RCTFabric.podspec
./ReactCommon/fabric/graphics/React-graphics.podspec
./ReactCommon/React-Fabric.podspec
./ReactCommon/turbomodule/core/React-turbomodule-core.podspec

Copy link
Contributor

@orta orta Mar 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point, I wonder if we make a way keep track of the default Podspecs inside React Native's codebase?

Copy link
Contributor Author

@fson fson Mar 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now it's these podspecs:

s.dependency "React-Core", version
s.dependency "React-DevSupport", version
s.dependency "React-RCTActionSheet", version
s.dependency "React-RCTAnimation", version
s.dependency "React-RCTBlob", version
s.dependency "React-RCTGeolocation", version
s.dependency "React-RCTImage", version
s.dependency "React-RCTLinking", version
s.dependency "React-RCTNetwork", version
s.dependency "React-RCTSettings", version
s.dependency "React-RCTText", version
s.dependency "React-RCTVibration", version
s.dependency "React-RCTWebSocket", version
and their transitive dependencies.

The podspec structure is supposed to mirror the Xcode projects as closely as possible, so I put podspecs next to the corresponding Xcode projects, but perhaps we could have a designated folder for all "core" podspecs that should be picked up by default?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting thanks, I wonder if we can use that then - it's a great source of truth.

Could have the podfile read the React.podspec, and add those dependencies (might end up being a bit of code (because the file paths are non-deterministic) )

I'll have a think

Copy link
Contributor

@cpojer cpojer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for working so hard on this. Let's ship it!

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cpojer is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@react-native-bot
Copy link
Collaborator

This pull request was successfully merged by @fson in cd8064b.

When will my fix make it into a release? | Upcoming Releases

@react-native-bot react-native-bot added the Merged This PR has been merged. label Mar 22, 2019
@fson fson deleted the @fson/template-podfile branch March 22, 2019 11:07
@msand
Copy link
Contributor

msand commented Mar 22, 2019

Great work! I would recommend checking that archive works correctly as well, at least before release. Historically this has been somewhat of a pain point, where everything seemed to work fine, except archive would be broken, or the release build would crash.

@cpojer
Copy link
Contributor

cpojer commented Mar 25, 2019

@msand could you add this check and send a PR?

@grabbou
Copy link
Contributor

grabbou commented Apr 23, 2019

I've removed all the CocoaPods generated things from xcodeproj now, they'll get added automatically when you run pod install. Now when I tested it it worked both with 1.5.3 and 1.6.1.

I actually think we should bring this back. I think it's a good thing to generate "a final" project we can just open and run.

Right now, there's no xcworkspace at all and we can't even get run-ios to work before running a Podfile which is a big change to the workflow. I feel like presence of a Podfile might be omitted and we can get some reports of React.xcodeproj missing from Libraries.

@grabbou
Copy link
Contributor

grabbou commented Apr 23, 2019

Also, react-native init ABC is not a git repository by default (shall we do it?)

That leaves pod install with these warnings:

fatal: not a git repository (or any of the parent directories): .git

@mikehardy
Copy link
Contributor

mikehardy commented Apr 23, 2019

Installing cocoapods for the first time is medium-fearsome. I just did it recently, I remember going "oh ___, I guess I google cocoapods then...okay should I use brew? or gem?...okay brew, then...oh wow that's a lot of data downloading (I have a small connection)...etc etc".

You can tell which way I would vote based on dev-experience anyway - the template should come out of the box ready to start essentially, IMHO

I'm actually installing it on a machine right now and it's going to take 30+minutes just for me to do the "git sync" part of pod update

@cpojer
Copy link
Contributor

cpojer commented Apr 24, 2019

I think I would like an adaptive approach that does this:

  • If git is available, git init and make an initial commit with the project files. If git is not available, ignore this step.
  • If Cocoapods is available, set up the workspace, amend the template and commit the change (if git is available). If Cocoapods is unavailable, ask people to install it only when they start using react-native link for the first time.

That way creating a new project won't be slower or get in the way for people who are just getting started, and it comes with all the benefits when somebody is already familiar with these tools (assuming that installing the tools means some familiarity). What do you think?

@FibreFoX
Copy link

I can understand the reasoning against having CocoaPod as an additional build-dependency, so like @grabbou wrote, there should be a way to opt-in to using that Podfile-stuff.

@grabbou I would not favor for having a git-repository when running react-native init, mostly due to unneeded additional files in case I'm inside an existing git-repo and want to add this react-native project. Unlike @cpojer mentioned above, detecting a git-client does not tell anything about my intentions 😸

But to be honest, having nothing, like only the pure XCode-crap ... sorry, thats not useful, there has to be some way, like adding CocoaPod. Just add some lines to the "getting started" document and let "the community" give feedback to this. But I would see this as an optional step, not a forced one.

@grabbou
Copy link
Contributor

grabbou commented Apr 24, 2019

@cpojer

That way creating a new project won't be slower or get in the way for people who are just getting started, and it comes with all the benefits when somebody is already familiar with these tools (assuming that installing the tools means some familiarity). What do you think?

Unfortunately, it will be slower, because installing CocoaPods and generating .xcworkspace takes time. You can't do it lazily (right when doing react-native link or react-native run-ios), because we don't have .xcworkspace generated.

When users would open the project directory right after react-native init, they will only see .xcodeproj which once they open, will throw them hundreds of warnings about missing React files. They will see a Podfile there, but if they are not aware of CocoaPods, they may not figure out running pod install is required to generate xcworkspace that they should use instead.

To fix that, we would have to run pod install right after react-native init. At this point, I don't see any benefits instead of just generating xcworkspace upfront.

@cpojer
Copy link
Contributor

cpojer commented Apr 24, 2019

@FibreFoX that seems like an easy fix to not run git if you are already within a git repo.
@grabbou I see what you mean! In that case I'm in favor of having this by default. The only thing I am worried about is requiring people to install Cocoapods to be able to run react-native init. I do not think it should be required until linking the first native dependency.

@grabbou
Copy link
Contributor

grabbou commented Apr 24, 2019

@cpojer yeah, with my proposal, we generate all files upfront so you don't need to have run it while init. The template will have React Native preinstalled already with files generated.

First dependency linked is React Native itself, that's where's the "problem" we are talking about coming from.

@cpojer
Copy link
Contributor

cpojer commented Apr 24, 2019

I'm on board.

@FibreFoX
Copy link

FibreFoX commented Apr 24, 2019

@FibreFoX that seems like an easy fix to not run git if you are already within a git repo.

Maybe this can be added as some parameter instead of automagic?

Another thing to keep in mind: not all users want to use CocoaPod, some are using Carthage. So leaving the parts inside the existing .xcodeproj might be a valid option, and just having some kind of parameter while running react-native init to switch between the existing options (maybe even by using a template?!)

@orta
Copy link
Contributor

orta commented Apr 24, 2019

+1 on running pod install on the cli template before shipping, then people won't need to do a pod install after initing a new template, only on adding new deps.

I think for edge cases like Carthage support people will make their own templates, you already have to have a reasonable understanding of Xcode to use it in a react native project so I wouldn't call them the target users

@pvinis
Copy link
Contributor

pvinis commented Apr 24, 2019

hm, it does suck though a bit though. maybe we can add the pod install or even better pod check && pod install when we start the packager or run react-native run-ios?
Or otherwise have an option like react-native init MyApp --no-cocoapods?

@benjarwar
Copy link

I'm curious about @onmyway133's comment above RE ending up with duplicate copies of React and its core dependencies.

Ran into this when I tried switching from Carthage to CocoaPods. Other react-native- third party frameworks ended up breaking, because CocoaPods automatically installed a Pods-managed version of React. Our NPM-managed dependencies installed an NPM version of React, which resulted in dupe versions between the two dependency managers. We never got our project to build properly, because various collaborators couldn't resolve to their dependencies correctly at compile-time, and we stuck with Carthage.

I guess the solution might be removing the Pods-managed version of React as outlined by @skurfuerst here. But if CocoaPods becomes the defacto way to manage libs via react-native link, are we going to run into issues in the other direction (aka Pods-managed dependencies can't find a Pods-managed version of React)?

@benjarwar
Copy link

@fson I know this issue is closed, but curious about how to officially get CocoaPods working with RN. It's given us nothing but trouble, see my comment above. I'm concerned about commands like react-native link become CocoaPods dependent.

We're currently experimenting with https://github.com/orta/cocoapods-fix-react-native/ to deal with the pathing collisions/issues. But that shim is stale and seems to require updates to work with latest RN versions.

@grabbou
Copy link
Contributor

grabbou commented May 13, 2019

@benjarwar having CocoaPods to be the recommended and default way of consuming React Native iOS files, we will automatically get rid of issues with collisions and Pod definitions becoming stale.

If you have further concerns, please open them in the React Native CLI repository, where we can chat about anything that relates to CocoaPods and link.

@@ -474,6 +476,44 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
FD10A7F022414F080027D42C /* Start Packager */ = {
Copy link

@chrisbobbe chrisbobbe Mar 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious, why exactly was this build phase added? I'm on RN v0.59.10, and I'm moving everything over to CocoaPods, and it seems like one side effect is that Metro doesn't start automatically anymore, and it looks like this build phase would fix that. Maybe this issue was also encountered when this PR was in progress; if so, does anyone know why exactly Metro doesn't start automatically without this?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mm, looks like the culprit was react-native-community/cli#317. That issue was closed too hastily, I think; I've posted a few comments there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. p: Expo Partner: Expo Partner Platform: iOS iOS applications. Type: Enhancement A new feature or enhancement of an existing feature.
Projects
None yet
Development

Successfully merging this pull request may close these issues.