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

Use CocoaPods #3987

Merged
merged 8 commits into from
Apr 3, 2020
Merged

Use CocoaPods #3987

merged 8 commits into from
Apr 3, 2020

Conversation

chrisbobbe
Copy link
Contributor

@chrisbobbe chrisbobbe commented Mar 20, 2020

EDIT: Adding unimodules was split out into #4016.

Fixes #3983. Also adds react-native-unimodules, to prepare for #3964.

Tested on the simulator and device, and all features seem to be working. Possibly a little slower at runtime than before, at least initially, maybe not significantly.

Note in the second commit that we're stuck on a version of react-native-unimodules (0.6.0, no caret) that's not the latest, because at some point between 0.6.0 and 0.7.0-rc.4 (reportedly), support for RN v0.59 was dropped. 0.7.0-rc.4 is reportedly the earliest version that supports AndroidX, so it may be that our AndroidX work (PR #3852) will have to be done simultaneously with the RN v0.60 upgrade (issue #3548). Apparently, backwards compatibility for those on older RN versions is not a priority; see https://github.com/unimodules/react-native-unimodules/issues/100#issuecomment-566436685.

@chrisbobbe chrisbobbe requested a review from gnprice March 20, 2020 06:06
@chrisbobbe chrisbobbe changed the title Use CocoaPods Use CocoaPods and react-native-unimodules Mar 20, 2020
@chrisbobbe chrisbobbe changed the title Use CocoaPods and react-native-unimodules Use CocoaPods and add react-native-unimodules Mar 20, 2020
@gnprice
Copy link
Member

gnprice commented Mar 20, 2020

Great! Glad to see this so quickly. 😄

I'll have to go connect the Mac I have here (taken home from the office when we all started working from home) to a monitor, so I can play with this... and hmm, first clear some desk space for said monitor. 🙂

0.7.0-rc.4 is reportedly the earliest version that supports AndroidX

Hrm. As I wrote over on #3852, when an app updates to use AndroidX, it can do so even while it's still using third-party libraries that are still built to use the Android Support Library; so the migration path is, apps go first, then libraries update at their leisure.

There are a lot of people on the Internet confused about that, though -- I didn't really understand it until I did the research that produced #3852. It's possible there's something nasty react-native-unimodules is doing that actually interferes with that nice smooth migration path engineered by the AndroidX authors. But I suspect that instead the library's maintainers are just among the people confused, and that in fact it'll work just fine. I guess we can find out!

@chrisbobbe
Copy link
Contributor Author

It's possible there's something nasty react-native-unimodules is doing that actually interferes with that nice smooth migration path engineered by the AndroidX authors.
[...]
But I suspect that instead the library's maintainers are just among the people confused, and that in fact it'll work just fine.

Mm! Good point. The deprioritization of backwards compatibility and semantic versioning made me leery to dig deeper into the code. It seemed possible that the best record for the current state of the package was in its maintainers' heads, so I tended to trust them when they said certain versions wouldn't work nicely with AndroidX. But you're right, and now I remember the results of your research into AndroidX: it should Just Work (unless, like you said, react-native-unimodules has done something unexpected).

@chrisbobbe
Copy link
Contributor Author

I'll need to update the docs in that first commit, also, because pod install is a required command now. Just tested on a freshly cloned project; the build fails without running pod install (of course) but running pod install (after running yarn; order matters, since the Podfile uses paths in node_modules) is sufficient to get it up and running.

Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

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

Some small code comments, and one larger substantive one.

ios/Podfile Outdated
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'

use_unimodules!

Copy link
Member

Choose a reason for hiding this comment

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

nit: trailing whitespace (highlighted by git diff by default)

ios/Podfile Outdated
Comment on lines 13 to 28
'CxxBridge', # Include this for RN >= 0.47
'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
'RCTText',
'RCTNetwork',
'RCTWebSocket', # Needed for debugging
'RCTAnimation', # Needed for FlatList and animations running on native UI thread
'RCTImage', # Included in react-native-unimodules' example Podfile
# Add any other subspecs you want to use in your project
]
# Explicitly include Yoga if you are using RN >= 0.42.0
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
Copy link
Member

Choose a reason for hiding this comment

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

Let's drop the references to ancient RN versions -- we are in fact on >= each of these 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK. It's very difficult to find the officially recommended example Podfile for RN v0.59 (see facebook/react-native-website#1603 (comment)), so including all of its details (with those outdated comments) was a goal, in case we encountered any issues with these dependencies in the future.

But I do link to that officially recommended example Podfile for RN v0.59, in a code comment at the top, which I guess is enough. And it's true that we're >= each of those versions. I would just hope that if, e.g., 'CxxBridge' starts causing an issue, we don't find some SO answer that says we can just remove it, and do that, seeing no justification for its existence.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah. There's that link; and also when asking that kind of "why did we put this here?" question, that's always a good prompt to go looking in the Git history, so that'll give us the full context of why we added these lines.

Also ideally when we've fully digested this migration, each subspec we mention here will be here because we really do need it, and have a clear reason why. 🙂 For a chunk of them the reason might be like "these are core pieces of RN used for everything", but which ancient version they were introduced in isn't really part of that information. In our current state of knowledge, basically that link is the explanation.

ios/Podfile Outdated
require_relative '../node_modules/react-native-unimodules/cocoapods.rb'

# See
# https://github.com/facebook/react-native-website/blob/ded79d2cf4456d8b1a4f67c2cdc1391789e70617/docs/integration-with-existing-apps.md#configuring-cocoapods-dependencies
Copy link
Member

Choose a reason for hiding this comment

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

nit: a 9-digit commit ID ded79d2cf makes this a bit more readable

ios/Podfile Outdated
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'

use_unimodules!
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, does this belong yet at this commit?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mm, I thought I fixed that (I certainly saw it, at some point), but obviously not.

Originally, I did everything at once — the CocoaPods work and adding unimodules — and made a single commit. Then, when I thought it would be good to split that into two commits, my strategy was to create a commit after the original commit, deleting the code that added unimodules. And then to reverse the commits.

But to accomplish that reversal, I knew that a simple interactive rebase with the two pick commands reversed wouldn't work. That's because the "pick" command applies a computed patch, it doesn't just effect the selected commit's snapshot. Usually applying a patch is what we want, but in this case, I had snapshot A and snapshot B, and I simply wanted to reorder them so B came before A.

I ended up doing an interactive rebase and breaking before the first commit, then doing git checkout <secondCommit> -- ., committing that, then git checkout <firstCommit> -- ., committing that, then git rebase --edit-todo, I dropped the two original commits, and finished the rebase. I'm not sure if this was exactly where this mistake was introduced, but it sure seemed like a lot of maneuvering just to reverse the two commits. Do you know of a better way?

Copy link
Member

Choose a reason for hiding this comment

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

Usually applying a patch is what we want, but in this case, I had snapshot A and snapshot B, and I simply wanted to reorder them so B came before A.

One way I might do this is:

git reset --soft @^^
# Now your HEAD includes neither commit, but your worktree and index are still at B.

git commit -c @{1}
# Now you have one commit, with tree/snapshot B.

git checkout @{2}^ .
# Now the worktree and index are at A.

git commit -c @{2}^
# Now you have both commits.

The -c are optional, but convenient for preserving the author dates and commit messages (but still give you an editor to edit the commit messages.)

The @^^ and @{2}^ and so on could be replaced with explicit commit IDs copied from git log, but make handy ways to refer to the commits without needing to copy-paste.

When the commits in question are in the middle of a longer series, I might use git rebase -i with just a b / break command inserted after the two commits, and then do the above steps there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I've bookmarked this!

ios/Podfile.lock Show resolved Hide resolved
ios/Podfile Show resolved Hide resolved
ios/Podfile Outdated
Comment on lines 15 to 18
'RCTText',
'RCTNetwork',
'RCTWebSocket', # Needed for debugging
'RCTAnimation', # Needed for FlatList and animations running on native UI thread
'RCTImage', # Included in react-native-unimodules' example Podfile
# Add any other subspecs you want to use in your project
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, so, I think there's a next step to be done before we're really fully using CocoaPods. That is to name here all the subspecs we need... and remove all the corresponding pieces from our own Xcode project file. In this version, it looks like all these pieces of RN are still incorporated directly into our build there.

In fact, as long as they're mentioned directly in our Xcode config, I'll be a little uncertain whether we've really fully wired up CocoaPods at all, because it seems like things would keep working even if we haven't.

On the other hand, once we have done that -- and then gone on to do that for the various third-party dependencies we use too -- our project.pbxproj should be quite a lot simpler than it's ever been before! This Podfile looks like a much cleaner and more readable way of tracking that same information.

It looks like you can find all the available subspecs by looking in node_modules/react-native/React.podspec.

Ah, and then from searching through ios/ZulipMobile.xcodeproj/project.pbxproj for mentions of a couple of these, I think you can find something like a list of all the ones we're using with the command grep '/node_modules/react-native/.*\.xcodeproj' ios/ZulipMobile.xcodeproj/project.pbxproj. Or this variant:

$ perl -lne 'print $1 if (m{/node_modules/react-native/.*/(.*)\.xcodeproj})' \
    ios/ZulipMobile.xcodeproj/project.pbxproj
RCTActionSheet
RCTGeolocation
RCTImage
RCTNetwork
RCTVibration
RCTSettings
RCTWebSocket
React
RCTPushNotification
RCTLinking
RCTText
RCTAnimation
RCTCameraRoll
ART

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That is to name here all the subspecs we need
[...]
It looks like you can find all the available subspecs by looking in node_modules/react-native/React.podspec.

In the Podfile, should I aim to reference all of the subspecs that are listed in React.podspec? I took the example Podfile from the RN v0.59 doc thinking that was the minimum set of subspecs necessary, and that anything on top of that might be pointless or introduce bugs. I can see the argument for being more complete than we may need to be, but I wonder why the example Podfile doesn't include all the subspecs in React.podspec, if that's the intended behavior for React Native dependencies.

Do you think "all the subspecs in React.podspec" includes just the outer level of nesting, here, or might we also need to get the "subspecs of the subspecs" (if that makes sense):

$ grep '\.subspec \"[a-zA-Z]*\" do' node_modules/react-native/React.podspec

  s.subspec "Core" do |ss|
  s.subspec "CxxBridge" do |ss|
  s.subspec "DevSupport" do |ss|
  s.subspec "RCTFabric" do |ss|
  s.subspec "tvOS" do |ss|
  s.subspec "jsinspector" do |ss|
  s.subspec "jsiexecutor" do |ss|
  s.subspec "jsi" do |ss|
  s.subspec "PrivateDatabase" do |ss|
  s.subspec "cxxreact" do |ss|
  s.subspec "fabric" do |ss|
    ss.subspec "activityindicator" do |sss|
    ss.subspec "attributedstring" do |sss|
    ss.subspec "core" do |sss|
    ss.subspec "debug" do |sss|
    ss.subspec "graphics" do |sss|
    ss.subspec "scrollview" do |sss|
    ss.subspec "text" do |sss|
    ss.subspec "textlayoutmanager" do |sss|
    ss.subspec "uimanager" do |sss|
    ss.subspec "view" do |sss|
  s.subspec "RCTFabricSample" do |ss|
  s.subspec "ART" do |ss|
  s.subspec "RCTActionSheet" do |ss|
  s.subspec "RCTAnimation" do |ss|
  s.subspec "RCTBlob" do |ss|
  s.subspec "RCTCameraRoll" do |ss|
  s.subspec "RCTGeolocation" do |ss|
  s.subspec "RCTImage" do |ss|
  s.subspec "RCTNetwork" do |ss|
  s.subspec "RCTPushNotification" do |ss|
  s.subspec "RCTSettings" do |ss|
  s.subspec "RCTText" do |ss|
  s.subspec "RCTVibration" do |ss|
  s.subspec "RCTWebSocket" do |ss|
  s.subspec "fishhook" do |ss|
  s.subspec "RCTLinkingIOS" do |ss|
  s.subspec "RCTTest" do |ss|

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, so, I think there's a next step to be done before we're really fully using CocoaPods. That is to name here all the subspecs we need... and remove all the corresponding pieces from our own Xcode project file.

That's certainly something we're going to have to do at some point, but it may be more complexity than is needed for #3964. Does react-native-unimodules need a full CocoaPods conversion, or will a bare-bones Podfile without the React Native core components suffice? (The latter would probably still be a significant step towards #3983.)

Copy link
Member

Choose a reason for hiding this comment

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

Does react-native-unimodules need a full CocoaPods conversion, or will a bare-bones Podfile without the React Native core components suffice? (The latter would probably still be a significant step towards #3983.)

Yeah, if the fuller conversion turns out to be more complex, I'd be happy merging whatever smaller version suffices to unblock #3964.

Though again, I'll be more confident that we've successfully fully wired up CocoaPods when there are pieces of the build that we rely on and don't have some other way they get included 😉 Without that, it seems like we might attempt #3964 and then discover there's something else we need to do in order for a library we add there to actually get built into the app.

Copy link
Member

Choose a reason for hiding this comment

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

In the Podfile, should I aim to reference all of the subspecs that are listed in React.podspec? I took the example Podfile from the RN v0.59 doc thinking that was the minimum set of subspecs necessary, and that anything on top of that might be pointless or introduce bugs. I can see the argument for being more complete than we may need to be, but I wonder why the example Podfile doesn't include all the subspecs in React.podspec

What I think I'd ideally like is to just specify the exact same set as we currently do in the Xcode project file, and at the same time stop specifying those there. I.e. just convert over how we include those pieces, separate from any changes to which ones we include.

It's also pretty likely that there are some things we include in the build that we don't need to, largely because the Xcode config has felt so opaque and it's felt so finicky, and liable to cause problems that are annoying to debug, to modify it. So after they're all in this Podfile instead, we might go through and identify some we don't need and remove those.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

and remove all the corresponding pieces from our own Xcode project file

This sounds easier to solve than determining the correct contents of the Podfile. So far, I haven't found a clear way forward for how to cleanly remove things from the project.pbxproj file. I think this area of the Xcode UI will be helpful:

image

Note that libPods-ZulipMobile.a is in that list, and a lot of other, mostly RN-related stuff is also in the list. It seems plausible to want to shrink that list down to just the Pods item, adding each removed item to the Podfile. But for that I'll need a clear mapping from a given .a item in that list, to a corresponding line to add to the Podfile.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mm, our posts crossed! 🙂Still, to accomplish

specify the exact same set as we currently do in the Xcode project file

it sounds like the next step is for me to find a mapping from all of those .a files in that screenshot (assuming that screenshot controls the Xcode project file in the ways we want), excluding the libPods-ZulipMobile.a file, to pods/subspecs that can be added to the Podfile. That counts on there being an available Pod, and it may count on some other things too, and I'll make it my next focus to find out. 🔍

@gnprice
Copy link
Member

gnprice commented Mar 20, 2020

I'll need to update the docs in that first commit, also, because pod install is a required command now. Just tested on a freshly cloned project; the build fails without running pod install (of course) but running pod install (after running yarn; order matters, since the Podfile uses paths in node_modules) is sufficient to get it up and running.

Can we put that in postinstall in our package.json? See https://github.com/zulip/zulip-mobile/pull/3852/files#diff-b9cfc7f2cdf78a7f4b91a753d10865a2 for an example.

If there's a part that's hard to automate, then let's document; but when we can automate, automating is better 😉

Hmm, I guess we probably need to add "install CocoaPods" to the dev setup instructions, too.

And then the postinstall should only run pod install if present / if you're on macOS. Probably that's too much logic to stuff into a package.json line, so we should just say "postinstall": "tools/postinstall" there and have a script at tools/postinstall that handles it. In that case, perhaps best to first merge a version where pod install is just in the docs, and follow up to automate it.

@chrisbobbe chrisbobbe force-pushed the pr-use-cocoapods branch 2 times, most recently from 11eaf39 to 17e0931 Compare March 23, 2020 20:56
@chrisbobbe
Copy link
Contributor Author

chrisbobbe commented Mar 26, 2020

Yay! Thanks to Greg's help, we're well on our way to getting this working.

I'm investigating two other issues now (a postinstall script to avoid double-counting some font files for RN Vector icons, motivated by oblador/react-native-vector-icons#1074 (comment), and I've seen an instance where Metro doesn't start automatically, but there are clues for a workaround with an extra Build Phase in facebook/react-native@cd8064bc5), but one seems ripe for others to work on independently, so I thought I'd jot it down before lunch here.

One of our dependencies, @remobile/react-native-toast, lacks a .podspec file. It's very easy to add one (this article agrees, and gives a call to action for PRs to do that), but it hasn't been done yet. In fact, there's a three-year-old PR to do that: remobile/react-native-toast#20, but it hasn't been merged. It appears that there haven't been any updates to that repo at all, for three years. So it may be time to vendor it (make our own local fork with the desired changes), or to find another library that gives us toasts on iOS, that's well-maintained and either has a .podspec file or would readily accept a PR that adds one. (Toasts on Android are handily provided by ToastAndroid from React Native.)

Note that the .podspec file changes with an upgrade to RN v0.60.0, and it's easy for library maintainers to miss this, or introduce breaking changes by mistake; I'll dump a candidate commit message here with links to see an example:

    deps: Lock rn-fetch-blob@0.10.15; breaking change at 0.10.16.
    
    See the warning and apology for this in their README at
    https://github.com/joltup/rn-fetch-blob#version-compatibility-warning.
    
    Specifically, at
    https://github.com/joltup/rn-fetch-blob/commit/0f6c3e3cc (released
    in rn-fetch-blob@0.10.16), the Podspec was updated to match RN's new
    pattern (added in
    https://github.com/facebook/react-native/commit/2321b3fd7, released
    in react-native@0.60.0) of having separate podspecs for each Xcode
    project, instead of using subspecs for them.
    
    We can allow upgrading to 0.10.16 when we switch to
    react-native@0.60.0 (that's open as #3548).

@chrisbobbe
Copy link
Contributor Author

Adding "blocked on other work" for #4008.

@chrisbobbe chrisbobbe added the blocked on other work To come back to after another related PR, or some other task. label Mar 27, 2020
@gnprice
Copy link
Member

gnprice commented Mar 27, 2020

to avoid double-counting some font files for RN Vector icons, motivated by oblador/react-native-vector-icons#1074 (comment),

Looking at the comment above that one:

it seems like the crux of the problem is that the font files are being referred to by both the react-native.config.js and the podspec.

the reference to the font files as assets in the react-native.config.js will cause the react-native link to load the fonts as a resource for the App project.

points to a cleaner solution, I think: it's saying that because the font files appear in react-native.config.js, they've wound up in our Xcode project config for our app. And indeed they seem to be there:

$ git grep vector-icons ios/
ios/ZulipMobile.xcodeproj/project.pbxproj:              2E41C86FA25744F998C2BB02 /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = "<group>"; };
ios/ZulipMobile.xcodeproj/project.pbxproj:              51E1EDA028654E17A35C5BCA /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = "<group>"; };
[...]

So if we delete those references and let the podspec take care of it, that should resolve the conflict.

@gnprice
Copy link
Member

gnprice commented Mar 27, 2020

And it perhaps says something about the sprawling opaque complexity of doing anything with Xcode build config 😝 that people in that thread are finding it easier to run a sed script on a dependency's podspec file than to delete the items from their own app's Xcode config.

@chrisbobbe
Copy link
Contributor Author

chrisbobbe commented Mar 27, 2020

because the font files appear in react-native.config.js, they've wound up in our Xcode project config for our app

But node_modules/react-native-vector-icons/react-native.config.js is in node_modules, so a postinstall script editing that file is the most reliable way we have of making sure it doesn't contain those references, and that they never get re-introduced, right? I'm not fully sure how, but it sounds like we're both seeing that their presence there is why they wind up in our Xcode config. Removing them from the Xcode config is necessary, but will it be enough? If they've flown from node_modules to the Xcode config before, might they do so again?

sprawling opaque complexity of doing anything with Xcode build config 😝

Yup. Luckily, I recognized the sed script on the podspec idea pretty quickly as something we don't want to do; we want to use the podspec file as-is, while deleting the stuff from the Xcode config (we just have to make sure it stays deleted).

@chrisbobbe
Copy link
Contributor Author

chrisbobbe commented Mar 27, 2020

Separately, one person believes that using CocoaPods with React Native allows us to use the "Parallelize Build" option in Xcode. I haven't thought through this enough to say whether it's likely to be a good idea (whether we'll ever get build failures because some things shouldn't be built in parallel), but I'm still able to build without failures, and I don't notice any runtime errors either. However, one trial without parallelization took 26s, and one trial with parallelization took 24s, so it doesn't seem to shave off that much time anyway. But here's the article that gave me the idea, anyway; it's possible that its claims are valid, but I'm just not sure: https://engineering.brigad.co/demystifying-react-native-modules-linking-ae6c017a6b4a#4f80

@gnprice
Copy link
Member

gnprice commented Mar 27, 2020

making sure it doesn't contain those references, and that they never get re-introduced, right? I'm not fully sure how, but it sounds like we're both seeing that their presence there is why they wind up in our Xcode config.

I think react-native link is the thing that looks at react-native.config.js, and acts on it by putting something into our Xcode config.

In any case, the Xcode config is in version control -- so once the references are out, we'll notice if they come back in, and can easily take them out again 🙂 (and debug why they were re-introduced)

@chrisbobbe
Copy link
Contributor Author

chrisbobbe commented Mar 28, 2020

I think react-native link is the thing that looks at react-native.config.js, and acts on it by putting something into our Xcode config.

That makes sense. react-native link can be called with no arguments, just like yarn install, so it's tempting to approach it similarly to yarn install, as in "Well, I've tried a bunch of specific things, why don't I run this all-purpose, idempotent command that's supposed to fix all kinds of issues with my dependencies?" Basically, we can't recommend that approach for react-native link. But I don't think we've ever explicitly recommended it, so there's not much lost there. And the question will be moot once we move from automatic linking, with react-native link, to autolinking, without it. (Gotta love those names. 😬)

In any case, the Xcode config is in version control -- so once the references are out, we'll notice if they come back in, and can easily take them out again 🙂 (and debug why they were re-introduced)

Yep, that's true. And modifying things in node_modules in-place adds its own headaches that we've had to think about, even very recently. So it'll be nice to avoid doing that; I'm on board with not making a postinstall script. 🙂

@gnprice
Copy link
Member

gnprice commented Mar 28, 2020

Re parallelizing the build:

  • Sure, we probably should!
  • I'm not sure this is related to switching to CocoaPods, at least not directly. From what I can tell from the web -- and the closest thing I can find to actual documentation on this is a WWDC talk 😞 -- the unit of parallelization that this is about is the "target". In particular that means that... in that post's example, the box has no effect at all, because there's just one target shown there.
    • Within a target, there are generally tons of different subtasks, compiling individual files. I can't immediately tell whether Xcode already parallelizes those, or does after this is enabled. I suspect that it already did -- that it builds a whole target, with individual files in parallel where applicable, then the next target, etc. -- and that it continues doing so with this box checked. But that's just a guess.
    • It may be that most of our parallelization opportunities are within a large target, rather than between many small ones. In that case this setting may not make a big difference.
  • One thing that will strongly affect how much this helps is how many cores your CPU has. On the office Mac (which I have with me for this WFH period), there's just one physical core, two virtual "hyperthreaded" cores. YMMV.

@chrisbobbe
Copy link
Contributor Author

chrisbobbe commented Mar 28, 2020

Makes sense. I've separated that into its own commit, of course; I'm so glad to have something that doesn't have to be included in the giant commit I'm putting together.

Just to jot down a note that I found some Expo packages that will be available to us with unimodules, which we can use instead of some of our third-party dependencies if we so choose. Expo packages will be much better maintained, especially compared with any non-Expo, non-RN-Community counterparts that are designed to do the same thing. There may be others, but here's a list so far:

Basically I'm looking at https://github.com/expo/expo/tree/master/packages and going to see if there's a ios/*.podspec.

chrisbobbe pushed a commit to chrisbobbe/zulip-mobile that referenced this pull request Mar 28, 2020
Greg notes a lack of good documentation about this feature; there is
this a WWDC talk:
https://developer.apple.com/videos/play/wwdc2018/408/?time=115.

To paraphrase Greg at zulip#3987, it appears that the unit of
parallelization is the "target", so this could be beneficial for us
if there are a lot of targets. It turns out that there are, now that
we're using CocoaPods. In the Xcode UI, the Pods project shows many
items under "Targets": one for each line in the Podfile.

So, enable it, with a plan to disable if we ever encounter errors
that can be traced to an attempt to build two things in parallel,
when they shouldn't be.

The speed increase will be strongly influenced by the number of
cores one's CPU has.
@chrisbobbe
Copy link
Contributor Author

OK, I've pushed my work for today -- this includes the branch from #4008, but that's only because it's necessary to get working code; that PR should be reviewed and merged before this one.

chrisbobbe pushed a commit to chrisbobbe/zulip-mobile that referenced this pull request Mar 30, 2020
Greg notes a lack of good documentation about this feature; there is
this a WWDC talk:
https://developer.apple.com/videos/play/wwdc2018/408/?time=115.

To paraphrase Greg at zulip#3987, it appears that the unit of
parallelization is the "target", so this could be beneficial for us
if there are a lot of targets. It turns out that there are, now that
we're using CocoaPods. In the Xcode UI, the Pods project shows many
items under "Targets": one for each line in the Podfile.

So, enable it, with a plan to disable if we ever encounter errors
that can be traced to an attempt to build two things in parallel,
when they shouldn't be.

The speed increase will be strongly influenced by the number of
cores one's CPU has.
chrisbobbe pushed a commit to chrisbobbe/zulip-mobile that referenced this pull request Mar 30, 2020
In particular, we plan to use expo-apple-authentication soon, for
in place of some existing dependencies, such as (non-exhaustively)
react-native-safe-area and react-native-orientation.

So, add it, without yet using it, following instructions at
https://github.com/unimodules/react-native-unimodules/blob/30da302a8/README.md.

Also, on Android, pass an additional argument to a constructor in
MainApplication.java, in a fix given by a maintainer at
https://github.com/unimodules/react-native-unimodules/issues/128#issuecomment-606027692.

Note that we omit the caret in 0.6.0, to disallow silent minor
version upgrades. The maintainers are not adhering to semantic
versioning, and they expect that you're using the latest version of
React Native if you're using the latest version of unimodules,
including minor versions; see
https://github.com/unimodules/react-native-unimodules/issues/100#issuecomment-566436685.

In that same comment, a maintainer says that 0.7.0-rc.4 is the
minimum version with AndroidX compatibility. If this is true, then
we may have a slight problem, because 0.7.0-rc.4, just like 0.6.0,
does not work with RN 0.59.10. That would mean we had to do the
AndroidX upgrade (PR zulip#3852) at the same time as the RN v0.60 upgrade
(issue zulip#3548). Greg thinks it's likely that the maintainer is
mistaken that there's a minimum version of unimodules required to
use AndroidX; the AndroidX engineers designed a smooth migration
path such that this shouldn't happen (see Greg's comment at
zulip#3987 (comment)).

Note: The following failure occurred with `tools/test deps`:

```
Package "ua-parser-js" wants ^0.7.18 and could get 0.7.21, but got 0.7.20

Found duplicate dependencies in yarn.lock which could be dedup'd.
Run:

  yarn yarn-deduplicate && yarn
```

The suggested command was run, and `tools/test deps` succeeded.

Fixes: zulip#3987
unstaged. Later, you can always [squash that commit with other
commits][fixing-commits], if appropriate.

[fixing-commits]: https://zulip.readthedocs.io/en/latest/git/fixing-commits.html
Copy link
Member

Choose a reason for hiding this comment

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

formatting nit: last line should end with newline too

Comment on lines 45 to +58
### Tips when running on your iOS device
When you change the BundleIdentifier and Team (required in order to run on a device),
it **will** modify your `.pbxproj` file, which you do **not** want unless you intend
to. For instance, if you linking a new dependency, your `.pbxproj` will be modified to
reflect the new changes.

If you are simply testing it on the iOS device, simply do not stage the said file to
be committed. On the other hand, if you are also adding a dependency, it is recommended
that you first `git commit` the dependency link modification itself, and then start
developing. This way, when you stage your intended changes, you can do a `git reset
path/to/.pbxproj` to discard any changes relating to the modification of the BundleIdentifier
and Team, and then continue to commit the rest of the files. When you prepare to push your
changes, you can just squash the initial commit with your later commits to retain a clean
commit history. This way, you won't have to deal with any merge conflicts or manual
deletion of the lines in your `.pbxproj` when you submit your code for a review.
to.

If you are simply testing it on the iOS device, simply do not stage
the said file to be committed.

If other changes to the `.pbxproj` file are needed (and they shouldn't
usually be, especially after we started managing our iOS dependencies
with CocoaPods), it's recommended that you put them in their own
commit, first, and leave the BundleIdentifier and Team changes
unstaged. Later, you can always [squash that commit with other
commits][fixing-commits], if appropriate.
Copy link
Member

Choose a reason for hiding this comment

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

Ah, good to fix this too, thanks!

Comment on lines -9 to -22
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "83CBBA2D1A601D0E00E9B192"
BuildableName = "libReact.a"
BlueprintName = "React"
ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj">
</BuildableReference>
</BuildActionEntry>
Copy link
Member

Choose a reason for hiding this comment

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

Ah indeed -- the React.xcodeproj seems a strong indication that this can go away too :)

ios/ZulipMobile.xcodeproj/project.pbxproj Show resolved Hide resolved
Chris Bobbe added 3 commits April 3, 2020 12:28
See the warning and apology for this in their README at
https://github.com/joltup/rn-fetch-blob#version-compatibility-warning.

Specifically, at
joltup/rn-fetch-blob@0f6c3e3cc (released
in rn-fetch-blob@0.10.16), the Podspec was updated to match RN's new
pattern (added in
facebook/react-native@2321b3fd7, released
in react-native@0.60.0) of having separate podspecs for each Xcode
project, instead of using subspecs for them.

We can allow upgrading to 0.10.16 when we switch to
react-native@0.60.0 (that's open as zulip#3548).
We've been using two different formats for importing header files:

\#import "RNNotifications.h"
\#import <RNNotifications.h>

The exact behavior of the compiler is left unspecified in the
standard: https://en.cppreference.com/w/cpp/preprocessor/include

Clang, the compiler Xcode uses, isn't very clear:
https://clang.llvm.org/docs/Modules.html#includes-as-imports

But GCC (https://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html) and
Microsoft
(https://docs.microsoft.com/en-us/cpp/preprocessor/hash-include-directive-c-cpp?view=vs-2019)
are clearer.

Greg says:

"""
The general idea seems to be like:

* With `<...>`, search the directories in the include path, which is
provided by things like `-I` or `/I` flags, or presumably
`HEADER_SEARCH_PATHS`.

* With `"..."`, first search the directory the including file is in.
Then maybe its parent directory, and so on up the tree. Then if
still not found, search the same include path as for `<...>`.
"""

We'll always be using HEADER_SEARCH_PATHS for our third-party header
files (they'll never be in the same directory as our own custom
code), and the <...> syntax seems to be the more direct way to
trigger the use of HEADER_SEARCH_PATHS, so we might as well use it
for our third-party header files.

In this commit, `#import <RCTLog.h>` would have worked just as well
as `#import <React/RCTLog.h>`, but only because
`"$(SRCROOT)/../node_modules/react-native/React/**"` is in our own
project's HEADER_SEARCH_PATHS. Later in this series, the React
dependency will live in CocoaPods as a target, and that target will
have its own HEADER_SEARCH_PATHS we can rely on, letting us remove
the HEADER_SEARCH_PATHS entry from our own project. The `React/`
prefix will ensure the React target will be located in order for its
HEADER_SEARCH_PATHS to be used. Also, note that this is the pattern
used in nearby React imports, and it's what the RN template app does
too (see template/ios/HelloWorldTests/HelloWorldTests.m at
react-native@c20070f10).
It seems like the compiler already has these in the search path
implicitly. Also, the React Native template project removed them in
545072b02. Furthermore, Greg confirmed that a brand-new iOS app (not
even using React Native) doesn't have these in any
HEADER_SEARCH_PATHS.

So, remove this item from HEADER_SEARCH_PATHS in our projects and
targets.
Copy link
Member

@gnprice gnprice left a comment

Choose a reason for hiding this comment

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

Thanks again @chrisbobbe !

This looks great. One thing mentioned below which has a one-line fix, and there's a formatting nit above. I'll fix them both up and merge.

tools/ios Outdated
@@ -41,6 +41,7 @@ archive_path="${rootdir}"/ios/build/ZulipMobile.xcarchive

do_build() {
yarn
pod install --project-directory=ios
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, I suggested this above, but: I'd forgotten that in this script, the working directory is ios/! See the cd command above.

Probably this is a sign that I should revise this script to use the repo root as its working directory, same as our other scripts. 🙂 For the moment, I'll just fix this up while merging.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, right, makes sense!

Chris Bobbe added 5 commits April 3, 2020 12:44
There was an attempt to use CocoaPods in aded466, 2017-03-19.

That was removed in 4096e71, 2017-07-18.

Some cleanup was done in 861744b, 2020-02-05.

To paraphrase Greg on zulip#3983:

CocoaPods is a tool for managing iOS libraries. It means instead of
having an `.xcodeproj` file for every library, and manually
connecting them to your app's own `.xcodeproj`, a separate
`Pods.xcodeproj` is generated from a simple, declarative Podfile,
and all you have to do to update or add dependencies is edit the
Podfile and run `pod install`. Many people use it in their React
Native apps, but there some tricky bits that have impeded universal
adoption.

RN v0.60 signals a full embrace of the use of CocoaPods by RN, by
making it work more smoothly. CocoaPods becomes required in v0.61.

Originally, we were going to start using CocoaPods as part of the RN
v0.60 upgrade, but we have a fresh reason to want to use CocoaPods,
with its own deadline: zulip#3964, Apple auth. Someone has made a handy
Expo package to handle Apple auth, but we can't use Expo packages
without either fully committing to using the Expo SDK (a dramatic
step) or using a package called react-native-unimodules, which lets
you select individual Expo packages. react-native-unimodules
requires the use of CocoaPods.

So, use CocoaPods now. Note that the Podfile will have to be
different when we upgrade to RN v0.60.0; see the parent for details.

Unfortunately, this has to be one giant commit instead of multiple
commits. From experimentation, this seems to be the minimal set of
changes that doesn't break functionality, which makes sense
intuitively when changing entirely between management strategies for
(somewhat) complex dependencies. We were also prompted to try this
strategy from solution 3 at this SO post:
https://stackoverflow.com/questions/53312887/error-on-archiving-react-native-app-in-xcode-multiple-commands-produce-libyog/55328241#5532824
But Greg has the most plausible theory for the actual reason why
this is necessary:

"""
One possibility is something like: we were getting React, as a
whole, from the direct references in the Xcode config; and so that
version of the built React library had versions of RCTImageView etc.
only when those were configured through RCTImage.xcodeproj etc., via
direct references to those in our Xcode config.

Whereas the built React library from React.podfile and our Podspec
had the RCTImageView that was built due to the RCTImage subspec in
our Podfile... but perhaps we just didn't get that one because it
had to compete with the libReact.a (or whatever) from our Xcode
config. And once we no longer had the latter, we started getting the
former instead.
"""

We started with a Podfile based on the example
Podfile given for react-native v0.59, at
https://github.com/facebook/react-native-website/blob/ded79d2cf4456d8b1a4f67c2cdc1391789e70617/docs/integration-with-existing-apps.md.
(That doc isn't live on the react-native docs website because of
facebook/react-native-website#1603.)

Then, we realized that more RN-provided libraries were present in
our Xcode config, so we added those.

We also added a number of dependencies that depend on React Native
(react-native-image-picker, etc.).
`grep -Rlw 'React' --include=\*.podspec node_modules/` verified
that they do indeed depend on the 'React' pod, which is React
Native.

Also, add a build phase to start Metro. For some reason that we
haven't found yet, Metro doesn't start automatically after the
switch to CocoaPods. It seems that this was recognized by the RN
maintainers as they were updating the template app to switch to
CocoaPods. They separated the addition of this build phase into its
own commit,
facebook/react-native@1f719ae43,
but it doesn't mention the reason it was added.

In that commit, the name "Start Packager" was used. Here, we use
"Start Metro" because a proper noun is more helpful, and this name
is what RN uses in a more recent commit,
facebook/react-native@e636eb60d, which
creates a RNTesterPods project and workspace for testing some
aspects of CocoaPods separately. (It's not clear without further
digging what aspects those are, but it hasn't been relevant to using
CocoaPods on RN v0.59.10.)

Notes on individual dependencies:

RNDeviceInfo (react-native-device-info):

The install instructions at
https://github.com/react-native-community/react-native-device-info#manual
for RN v0.59.0 using CocoaPods wrongly say not to use CocoaPods (by
omitting the line in the Podfile). The author's comment at
react-native-device-info/react-native-device-info#748 (comment)
suggests that he never found the successful strategy of doing an
all-at-once adoption of CocoaPods, as we do here, and rather
concluded that a bug was caused by RN v0.59.x having shaky support
for CocoaPods. Including the pod works fine.

Fixes: zulip#3983
CocoaPods is supported in 0.1.1, but required in 1.0.0. So, now that
we're using CocoaPods, take advantage of the latest version.

At
vonovak/react-native-simple-toast#27 (comment),
the maintainer incorrectly says, "For RN < 0.60, please install the
version before 1.0.0". The correct recommendation would be, "If not
using CocoaPods, please install the version before 1.0.0". The next
comment is correct: "Or you can try installing the native dep
according to the instructions here".

The reason it was failing for that user on 1.0.0 with non-CocoaPods
linking is that a native dependency,
https://github.com/scalessec/Toast, ceases to be bundled with the
app in 1.0.0, and is instead downloaded on running `pod install`,
which of course requires using CocoaPods. (See also the 1.0.0
release notes:
https://github.com/vonovak/react-native-simple-toast/releases/tag/v1.0.0.)

There's no problem using 1.0.0 with RN v0.59.10 as long as you're
using CocoaPods.
Greg notes a lack of good documentation about this feature; there is
this a WWDC talk:
https://developer.apple.com/videos/play/wwdc2018/408/?time=115.

To paraphrase Greg at zulip#3987, it appears that the unit of
parallelization is the "target", so this could be beneficial for us
if there are a lot of targets. It turns out that there are, now that
we're using CocoaPods. In the Xcode UI, the Pods project shows many
items under "Targets": one for each line in the Podfile.

So, enable it, with a plan to disable if we ever encounter errors
that can be traced to an attempt to build two things in parallel,
when they shouldn't be.

The speed increase will be strongly influenced by the number of
cores one's CPU has.
In 436800e, we added config to "have all the imports match a single
computer-maintainable style, so that the computer can be asked
to clean up imports routinely without causing any new churn."

At some point, the imports must have been edited without running the
auto-"optimize" shortcut, Ctrl+Alt+O. So, do that.
…ava 13.

Following debugging conversation around
https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/Android.20build.3A.20unimodules/near/844331.

I was somehow on Java 13, probably from an automatic update when I
upgraded to macOS 10.15 Catalina.
@gnprice gnprice merged commit 83ec41d into zulip:master Apr 3, 2020
@gnprice
Copy link
Member

gnprice commented Apr 3, 2020

Followup items collected from above (and please comment if you see one I've missed):

  • small, good to do soon: Use CocoaPods #3987 (comment):

    it also sounds right, even if we do automate it, to simulate not having successfully run pod install, and add a troubleshooting entry for that; I can do that tomorrow.

  • bigger, for another time: Use CocoaPods #3987 (comment)
    (move "Start Metro" script into a script file, make it not run on release build)

And then of course #4016 is the major next step 🙂 , taking us toward #3964.

@chrisbobbe
Copy link
Contributor Author

chrisbobbe commented Apr 3, 2020

Followup items collected from above (and please comment if you see one I've missed):

  • The actual automation of pod install with a postinstall script (probably small)
  • Small (hopefully?), not introduced in this PR: potential cleanup of "libz.tbd in Frameworks": Use CocoaPods #3987 (comment)

    This one isn't in the upstream template -- but it also looks like it never was. It entered our project file in a18c95b (Initial Implementation of Sentry. #881).

    Well, I guess that makes any cleanup of it orthogonal to this PR, then.

  • This one just occurred to me — we have to note in the docs that people should open .xcworkspace instead of .xcodeproj in Xcode.

chrisbobbe pushed a commit to chrisbobbe/zulip-mobile that referenced this pull request Apr 3, 2020
This lets us use individual Expo packages. In particular, we plan to
use expo-apple-authentication soon, for in place of some existing
dependencies, such as (non-exhaustively) react-native-safe-area and
react-native-orientation.

So, add it, without yet using it, following instructions at
https://github.com/unimodules/react-native-unimodules/blob/30da302a8/README.md.

Note that we omit the caret in 0.6.0, to disallow silent minor
version upgrades. The maintainers are not adhering to semantic
versioning, and they expect that you're using the latest version of
React Native if you're using the latest version of unimodules,
including minor versions; see
https://github.com/unimodules/react-native-unimodules/issues/100#issuecomment-566436685.

In that same comment, a maintainer says that 0.7.0-rc.4 is the
minimum version with AndroidX compatibility. If this is true, then
we may have a slight problem, because 0.7.0-rc.4, just like 0.6.0,
does not work with RN 0.59.10. That would mean we had to do the
AndroidX upgrade (PR zulip#3852) at the same time as the RN v0.60 upgrade
(issue zulip#3548). Greg thinks it's likely that the maintainer is
mistaken that there's a minimum version of unimodules required to
use AndroidX; the AndroidX engineers designed a smooth migration
path such that this shouldn't happen (see Greg's comment at
zulip#3987 (comment)).

A couple of fixes had to be made to get it to work on Android:

First, pass an additional argument to a constructor in
MainApplication.java, in a fix given by a maintainer at
https://github.com/unimodules/react-native-unimodules/issues/128#issuecomment-606027692.

Second, specify a new dependency for
`unimodules-react-native-adapter` in our own `android/build.gradle`,
in a fix that is necessary because we're locked on version 0.6.0 of
react-native-unimodules. Filed as
https://github.com/unimodules/react-native-unimodules/issues/130.

Also (not Android-specific), the following failure occurred with
`tools/test deps`:

```
Package "ua-parser-js" wants ^0.7.18 and could get 0.7.21, but got 0.7.20

Found duplicate dependencies in yarn.lock which could be dedup'd.
Run:

  yarn yarn-deduplicate && yarn
```

The suggested command was run, and `tools/test deps` succeeded.

Fixes: zulip#3987
chrisbobbe pushed a commit to chrisbobbe/zulip-mobile that referenced this pull request Apr 7, 2020
This lets us use individual Expo packages. In particular, we plan to
use expo-apple-authentication soon, for in place of some existing
dependencies, such as (non-exhaustively) react-native-safe-area and
react-native-orientation.

So, add it, without yet using it, following instructions at
https://github.com/unimodules/react-native-unimodules/blob/30da302a8/README.md.

Note that we omit the caret in 0.6.0, to disallow silent minor
version upgrades. The maintainers are not adhering to semantic
versioning, and they expect that you're using the latest version of
React Native if you're using the latest version of unimodules,
including minor versions; see
https://github.com/unimodules/react-native-unimodules/issues/100#issuecomment-566436685.

In that same comment, a maintainer says that 0.7.0-rc.4 is the
minimum version with AndroidX compatibility. If this is true, then
we may have a slight problem, because 0.7.0-rc.4, just like 0.6.0,
does not work with RN 0.59.10. That would mean we had to do the
AndroidX upgrade (PR zulip#3852) at the same time as the RN v0.60 upgrade
(issue zulip#3548). Greg thinks it's likely that the maintainer is
mistaken that there's a minimum version of unimodules required to
use AndroidX; the AndroidX engineers designed a smooth migration
path such that this shouldn't happen (see Greg's comment at
zulip#3987 (comment)).

A couple of fixes had to be made to get it to work on Android:

First, pass an additional argument to a constructor in
MainApplication.java, in a fix given by a maintainer at
https://github.com/unimodules/react-native-unimodules/issues/128#issuecomment-606027692.

Second, specify a new dependency for
`unimodules-react-native-adapter` in our own `android/build.gradle`,
in a fix that is necessary because we're locked on version 0.6.0 of
react-native-unimodules. Filed as
https://github.com/unimodules/react-native-unimodules/issues/130.

Also (not Android-specific), ran `yarn yarn-deduplicate` to
deduplicate `ua-parser-js`, following a prompt from
`tools/test deps`.

Fixes: zulip#3987
gnprice pushed a commit to chrisbobbe/zulip-mobile that referenced this pull request Apr 7, 2020
This lets us use individual Expo packages. In particular, we plan to
use expo-apple-authentication soon, for in place of some existing
dependencies, such as (non-exhaustively) react-native-safe-area and
react-native-orientation.

So, add it, without yet using it, following instructions at
https://github.com/unimodules/react-native-unimodules/blob/30da302a8/README.md.

Note that we omit the caret in 0.6.0, to disallow silent minor
version upgrades. The maintainers are not adhering to semantic
versioning, and they expect that you're using the latest version of
React Native if you're using the latest version of unimodules,
including minor versions; see
https://github.com/unimodules/react-native-unimodules/issues/100#issuecomment-566436685.

In that same comment, a maintainer says that 0.7.0-rc.4 is the
minimum version with AndroidX compatibility. If this is true, then
we may have a slight problem, because 0.7.0-rc.4, just like 0.6.0,
does not work with RN 0.59.10. That would mean we had to do the
AndroidX upgrade (PR zulip#3852) at the same time as the RN v0.60 upgrade
(issue zulip#3548). Greg thinks it's likely that the maintainer is
mistaken that there's a minimum version of unimodules required to
use AndroidX; the AndroidX engineers designed a smooth migration
path such that this shouldn't happen (see Greg's comment at
zulip#3987 (comment)).

A couple of fixes had to be made to get it to work on Android:

First, pass an additional argument to a constructor in
MainApplication.java, in a fix given by a maintainer at
https://github.com/unimodules/react-native-unimodules/issues/128#issuecomment-606027692.

Second, specify a new dependency for
`unimodules-react-native-adapter` in our own `android/build.gradle`,
in a fix that is necessary because we're locked on version 0.6.0 of
react-native-unimodules. Filed as
https://github.com/unimodules/react-native-unimodules/issues/130.

Also (not Android-specific), ran `yarn yarn-deduplicate` to
deduplicate `ua-parser-js`, following a prompt from
`tools/test deps`.

Fixes: zulip#3987
chrisbobbe pushed a commit to chrisbobbe/zulip-mobile that referenced this pull request Apr 8, 2020
This lets us use individual Expo packages. In particular, we plan to
use expo-apple-authentication soon, for in place of some existing
dependencies, such as (non-exhaustively) react-native-safe-area and
react-native-orientation.

So, add it, without yet using it, following instructions at
https://github.com/unimodules/react-native-unimodules/blob/30da302a8/README.md.

It looks like Unimodules has also gone by the name Universal
Modules, but this may be an old name that has been superseded:
unimodules/unimodules.org@23c53dd...bdc80d9

Note that we omit the caret in 0.6.0, to disallow silent minor
version upgrades. The maintainers are not adhering to semantic
versioning, and they expect that you're using the latest version of
React Native if you're using the latest version of unimodules,
including minor versions; see
https://github.com/unimodules/react-native-unimodules/issues/100#issuecomment-566436685.

In that same comment, a maintainer says that 0.7.0-rc.4 is the
minimum version with AndroidX compatibility. If this is true, then
we may have a slight problem, because 0.7.0-rc.4, just like 0.6.0,
does not work with RN 0.59.10. That would mean we had to do the
AndroidX upgrade (PR zulip#3852) at the same time as the RN v0.60 upgrade
(issue zulip#3548). Greg thinks it's likely that the maintainer is
mistaken that there's a minimum version of unimodules required to
use AndroidX; the AndroidX engineers designed a smooth migration
path such that this shouldn't happen (see Greg's comment at
zulip#3987 (comment)).

A later commit in this series describes another concern with Expo's
handling of version constraints, with expo-application (and others),
with a reference to expo/expo#7728, which
I just filed.

A couple of fixes had to be made to get it to work on Android:

First, pass an additional argument to a constructor in
MainApplication.java, in a fix given by a maintainer at
https://github.com/unimodules/react-native-unimodules/issues/128#issuecomment-606027692.

Second, specify a new dependency for
`unimodules-react-native-adapter` in our own `android/build.gradle`,
in a fix that is necessary because we're locked on version 0.6.0 of
react-native-unimodules. Filed as
https://github.com/unimodules/react-native-unimodules/issues/130.

Also (not Android-specific), ran `yarn yarn-deduplicate` to
deduplicate `ua-parser-js`, following a prompt from
`tools/test deps`.

Fixes: zulip#3987
@chrisbobbe
Copy link
Contributor Author

I responded about libz at #4026 (comment).

gnprice pushed a commit to chrisbobbe/zulip-mobile that referenced this pull request Apr 8, 2020
This lets us use individual Expo packages. In particular, we plan to
use expo-apple-authentication soon, for in place of some existing
dependencies, such as (non-exhaustively) react-native-safe-area and
react-native-orientation.

So, add it, without yet using it, following instructions at
https://github.com/unimodules/react-native-unimodules/blob/30da302a8/README.md.

It looks like Unimodules has also gone by the name Universal
Modules, but this may be an old name that has been superseded:
unimodules/unimodules.org@23c53dd...bdc80d9

Note that we omit the caret in 0.6.0, to disallow silent minor
version upgrades. The maintainers are not adhering to semantic
versioning, and they expect that you're using the latest version of
React Native if you're using the latest version of unimodules,
including minor versions; see
https://github.com/unimodules/react-native-unimodules/issues/100#issuecomment-566436685.

In that same comment, a maintainer says that 0.7.0-rc.4 is the
minimum version with AndroidX compatibility. If this is true, then
we may have a slight problem, because 0.7.0-rc.4, just like 0.6.0,
does not work with RN 0.59.10. That would mean we had to do the
AndroidX upgrade (PR zulip#3852) at the same time as the RN v0.60 upgrade
(issue zulip#3548). Greg thinks it's likely that the maintainer is
mistaken that there's a minimum version of unimodules required to
use AndroidX; the AndroidX engineers designed a smooth migration
path such that this shouldn't happen (see Greg's comment at
zulip#3987 (comment)).

A later commit in this series describes another concern with Expo's
handling of version constraints, with expo-application (and others),
with a reference to expo/expo#7728, which
I just filed.

A couple of fixes had to be made to get it to work on Android:

First, pass an additional argument to a constructor in
MainApplication.java, in a fix given by a maintainer at
https://github.com/unimodules/react-native-unimodules/issues/128#issuecomment-606027692.

Second, specify a new dependency for
`unimodules-react-native-adapter` in our own `android/build.gradle`,
in a fix that is necessary because we're locked on version 0.6.0 of
react-native-unimodules. Filed as
https://github.com/unimodules/react-native-unimodules/issues/130.

Also (not Android-specific), ran `yarn yarn-deduplicate` to
deduplicate `ua-parser-js`, following a prompt from
`tools/test deps`.

Fixes: zulip#3987
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this pull request May 18, 2020
A lot of work has already been done toward this:

- adjusting to the newer Flow version (zulip#3827)
- updating to AndroidX (zulip#3852)
- migrating to using CocoaPods at all (zulip#3987)

Also, do what needs to be done atomically with the upgrade.

----- Platform-agnostic --------------------------------------------

After the upgrade, we get this peer dep warning:

warning " > react-native-webview@5.12.1" has incorrect peer dependency "react-native@>=0.57 <0.60".

`react-native-webview@7.0.0` is the minimum supported with RN
v0.60.0. But if we try to get `react-native-webview@7.0.0 before the
upgrade, we get this warning:

warning " > react-native-webview@7.0.0" has incorrect peer dependency "react-native@>=0.60 <0.62".

So, handle `react-native-webview` in the same commit as `react-native`.

----- iOS ----------------------------------------------------------

As far as I've seen, facebook/react-native@2321b3fd7 is the only
cause of iOS changes that must happen atomically with the RN v0.60.0
upgrade.

In that commit, all the "subspecs" that were nested under the
"React" pod are un-nested so they each become their own pod, with
many of these living in their own directory under
node_modules/react-native/Libraries [0].

In our own code, this means changing our Podfile to refer to all
these new pods, instead of the "React" pod's subspecs. So, do.

Our Podfile has a list of "Pods we need that depend on React
Native". We must also be sure all the dependencies in this list
adapt to facebook/react-native@2321b3fd7.

The syntax for pointing explicitly to a subspec is a slash, as in
"React/Core" [1]. Knowing this, we check that list for pods that
explicitly depended on those subspecs, with "React/[...]":

grep -Rl dependency.*React/ --include=\*.podspec --exclude="node_modules/react-native/*" node_modules

There are two, and here's how they handled the change in new
versions that we take in this commit:

 - `zmxv/react-native-sound@2f2c25a69`: "React/Core" -> "React"
 - `joltup/rn-fetch-blob`, `01f10cb10^..0f6c3e3cc`: "React/Core" -> "React-Core"

So, those respond to *explicit* dependencies on a subspec. There are
quite a few that depended on the "React" pod before, and they still
depend on the "React" pod now. So, let's find out if any of these
might have been *implicitly* depending on a subspec.

For that, first note that React Native was a special case before the
upgrade: the React podspec declared a `default_subspec` [1] [2] of
"Core". From reading the docs, that seems to mean that a dependency
on the "Core" subspec, specifically, could have been spelled in one
of two ways: "React/Core", or just "React" [3]. From reading the doc
on `default_subspec`, it seems that this flexibility did not apply
to *all* of the subspecs, though it would have if `default_subspec`
were absent.

So, the only remaining worry is that a "React/Core" / "React-Core"
dependency can no longer be spelled as "React" after the upgrade. If
so, it's possible that some of these "React"-dependent pods were
secretly depending on "React/Core" before, and will need to get an
`s.dependency "React-Core"` line added to them now.

I don't think we have to worry about this. Here's one theory:
"React.podspec", after `facebook/react-native@2321b3fd7`, newly
declares `s.dependency "React-Core"` [4]. I suspect this
accomplishes much the same thing as having "Core" as a
`default_subspec`, as far as we're concerned here: namely, that if
you want "React-Core", you can still just say "React". I wish it
were clear in the CocoaPods docs, or that React Native had cleared
this up in the RN v0.60 release notes and said it's fine to just
depend on "React" when you want "React-Core".

The `zmxv/react-native-sound@2f2c25a69` story (going from
"React/Core" to just "React") may support the conclusion even more
strongly, in that the "React/Core" specificity may have been
intentional (there's very little to say either way, though), and
there was demonstrably no harm in losing it.

`rn-fetch-blob` showed less certainty about handling the upgrade. In
`01f10cb10`, they chose "React". Then, in the same PR [5], they
moved to "React-Core" in 0f6c3e3cc. That PR is a little ambiguous to
read, but to me, it looks like things were working fine with
"React", and they moved to "React-Core" more or less at random.

To be sure, test for ourselves. Before and after making this change
(and clearing `ios/Pods` and running `pod install`):

node_modules/rn-fetch-blob/rn-fetch-blob.podspec
```diff
- s.dependency 'React-Core'
+ s.dependency 'React'
```

there are no build failures, and I can still log `NativeModules`
from `react-native` and see `RNFetchBlob` there. I also see
`RNSound`.

So, it looks like we've done what we need to for
facebook/react-native@2321b3fd7.

[0]: They do still live in node_modules. It's possible for pods to
be hosted online and downloaded on `pod install`, npm-style. For an
example, see the 'Toast' dependency in
node_modules/react-native-simple-toast/react-native-simple-toast.podspec.
But that's not what's happening here, yet.
facebook/react-native@2321b3fd7 hints that this will be the way of
the future for React Native, "to make the experience nicer for
library consumers".

[1]: https://guides.cocoapods.org/syntax/podspec.html#subspec

[2]: https://guides.cocoapods.org/syntax/podspec.html#default_subspecs

[3]: One blog post has an example of this; see
http://www.dbotha.com/2014/12/04/optional-cocoapod-dependencies/#default-subspec.

[4]: It also newly declares a lot of those formerly-subspec
dependencies, like "React-RCTImage", etc. I don't see why this would
have been strictly necessary, and it means we newly can't avoid
linking these things (which we could before, since only "Core" was
listed as a `default_subspec`) and potentially enlarging the iOS
app. Ah well, not a big problem.

[5]: joltup/rn-fetch-blob#397
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this pull request May 23, 2020
Using the RN Upgrade Helper at
https://react-native-community.github.io/upgrade-helper/?from=0.59.10&to=0.60.0.

A lot of work has already been done toward this:

- adjusting to the newer Flow version (zulip#3827)
- updating to AndroidX (zulip#3852)
- migrating to using CocoaPods at all (zulip#3987)

Also, do what needs to be done atomically with the upgrade.

Run `yarn yarn-deduplicate && yarn`, following a prompt to do so
from `tools/test deps` that also said this:

"""
Package "babel-preset-fbjs" wants ^3.2.0 and could get 3.3.0, but
got 3.2.0
"""

----- Platform-agnostic --------------------------------------------

We decided never to take a few small changes in this series:

- Edits to `"scripts": { ... }` in our package.json; these are
  configured as we like them to be.

After the upgrade, we get this peer dep warning:

warning " > react-native-webview@5.12.1" has incorrect peer dependency "react-native@>=0.57 <0.60".

`react-native-webview@7.0.0` is the minimum supported with RN
v0.60.0. But if we try to get `react-native-webview@7.0.0 before the
upgrade, we get this warning:

warning " > react-native-webview@7.0.0" has incorrect peer dependency "react-native@>=0.60 <0.62".

So, handle `react-native-webview` in this commit.

----- Android ------------------------------------------------------

Some Android changes never appear in this series:

- Adding the `debug.keystore` file and its config in
  `android/app/build.gradle`. See more explanation and a code
  comment there in another commit in this series.

- Adding `android.useAndroidX=true` and
  `android.enableJetifier=true` in `android/gradle.properties`.
  These were done in e433197.

- Deleting `android/keystores/BUCK` and
  `android/keystores/debug.keystore.properties`: We don't use Buck
  (removal of some of its boilerplate was 1c86488), and we don't
  have an `android/keystores` directory. As mentioned in another
  commit in this series, we're happy with the Android
  Studio-provided debug keystore, and our own release keystore
  described in our release guide.

There are no updates on the Android side that must happen atomically
with the RN upgrade.

----- iOS ----------------------------------------------------------

Some iOS changes don't appear in this series. They fall neatly into
a few touched files:

- ios/ZulipMobile-tvOS/Info.plist: We're not (yet) in the TV
  business. ;)

- ios/ZulipMobile.xcodeproj/project.pbxproj: The purge of many large
  chunks of this file, often known as "the Xcode config file", was
  already done, in 33f4b41.

- ios/ZulipMobile.xcworkspace/contents.xcworkspacedata: After
  33f4b41, this file already looks the way it should.

- ios/ZulipMobile/Info.plist: These changes are done upstream in
  facebook/react-native@7b44fe56f. They fix a duplication issue and
  a code-comment issue, which were apparently causing build
  failures. Our code doesn't have these issues to begin with.

As far as I've seen, facebook/react-native@2321b3fd7 is the only
cause of iOS changes that must happen atomically with the RN v0.60.0
upgrade.

In that commit, all the "subspecs" that were nested under the
"React" pod are un-nested so they each become their own pod, with
many of these living in their own directory under
node_modules/react-native/Libraries [1].

In our own code, this means changing our Podfile to refer to all
these new pods, instead of the "React" pod's subspecs. So, do.

Our Podfile has a list of "Pods we need that depend on React
Native". We must also be sure all the dependencies in this list
adapt to facebook/react-native@2321b3fd7.

The syntax for pointing explicitly to a subspec is a slash, as in
"React/Core" [2]. Knowing this, we check that list for pods that
explicitly depended on those subspecs, with "React/[...]":

```
grep -Rl dependency.*React/ --include=\*.podspec \
  --exclude="node_modules/react-native/*" node_modules
```

There are two, and they both have new versions that adapt to the new accepted shape:

- `zmxv/react-native-sound@2f2c25a69`: "React/Core" -> "React"
- `joltup/rn-fetch-blob`, `01f10cb10^..0f6c3e3cc`: "React/Core" -> "React-Core"

So, take these new versions.

[1]: They do still live in node_modules. It's possible for pods to
     be hosted online and downloaded on `pod install`, npm-style.
     For an example, see the 'Toast' dependency in
     node_modules/react-native-simple-toast/react-native-simple-toast.podspec.
     But that's not what's happening here, yet.
     facebook/react-native@2321b3fd7 hints that this will be the way
     of the future for React Native, "to make the experience nicer
     for library consumers".

[2]: https://guides.cocoapods.org/syntax/podspec.html#subspec
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this pull request Jun 1, 2020
Closes zulip#3548!

Using the RN Upgrade Helper, a web app showing the diff from the
release/0.59.10 and the release/0.60.6 branches of the
`react-native-community/rn-diff-purge` repo, at
https://react-native-community.github.io/upgrade-helper/?from=0.59.10&to=0.60.6.

A lot of work has already been done toward this:

- most of the fixes necessary to adapt to Flow 0.98, without
  upgrading Flow yet (zulip#3827). We do the upgrade in this commit, with
  warnings temporarily suppressed, for smaller commits.

- updating to AndroidX (zulip#3852)

- migrating to using CocoaPods at all (zulip#3987)

Also, do what needs to be done atomically with the upgrade, as
follows.

----- Platform-agnostic --------------------------------------------

After the upgrade, we get this peer dep warning:

warning " > react-native-webview@5.12.1" has incorrect peer dependency "react-native@>=0.57 <0.60".

`react-native-webview@7.0.0` is the minimum supported with RN
v0.60.0. But if we try to get `react-native-webview@7.0.0 before the
upgrade, we get this warning:

warning " > react-native-webview@7.0.0" has incorrect peer dependency "react-native@>=0.60 <0.62".

So, handle `react-native-webview` in this commit.

Also run `yarn yarn-deduplicate && yarn`, as prompted by
`tools/test deps`.

We've left "scripts" in `package.json` alone; ours work fine as-is.

----- Android ------------------------------------------------------

There are no updates on the Android side that must happen atomically
with the RN upgrade.

Some Android changes never appear in this series:

- Adding the `debug.keystore` file and its config in
  `android/app/build.gradle`. See more explanation and a code
  comment there in another commit in this series.

- Adding `android.useAndroidX=true` and
  `android.enableJetifier=true` in `android/gradle.properties`.
  These were done in e433197.

- Deleting `android/keystores/BUCK` and
  `android/keystores/debug.keystore.properties`: We don't use Buck
  (removal of some of its boilerplate was 1c86488), and we don't
  have an `android/keystores` directory. As mentioned in another
  commit in this series, we're happy with the Android
  Studio-provided debug keystore, and our own release keystore
  described in our release guide.

----- iOS ----------------------------------------------------------

facebook/react-native@2321b3fd7 appears to be the only cause of iOS
changes that must happen atomically with the RN v0.60 upgrade.

In that commit, all the "subspecs" that were nested under the
"React" pod are un-nested so they each become their own pod, with
many of these living in their own directory under
node_modules/react-native/Libraries [1].

In our own code, this means changing our Podfile to refer to all
these new pods, instead of the "React" pod's subspecs. So, do.

Our Podfile has a list of "Pods we need that depend on React
Native". We must also be sure all the dependencies in this list
adapt to facebook/react-native@2321b3fd7.

The syntax for pointing explicitly to a subspec is a slash, as in
"React/Core" [2]. Knowing this, we check that list for pods that
explicitly depended on those subspecs, with "React/[...]":

```
grep -Rl dependency.*React/ --include=\*.podspec \
  --exclude="node_modules/react-native/*" node_modules
```

There are two, and they both have new versions that adapt to the new accepted shape:

- `zmxv/react-native-sound@2f2c25a69`: "React/Core" -> "React"
- `joltup/rn-fetch-blob`, `01f10cb10^..0f6c3e3cc`: "React/Core" -> "React-Core"

So, take these new versions, and job done.

Some iOS changes from the upgrade guide don't appear in this series.
They fall neatly into a few touched files:

- ios/ZulipMobile-tvOS/Info.plist: We're not (yet) in the TV
  business. ;)

- ios/ZulipMobile.xcodeproj/project.pbxproj: The purge of many large
  chunks of this file, often known as "the Xcode config file", was
  already done, in 33f4b41.

- ios/ZulipMobile.xcworkspace/contents.xcworkspacedata: After
  33f4b41, this file already looks the way it should.

- ios/ZulipMobile/Info.plist: These changes are done upstream in
  facebook/react-native@7b44fe56f. They fix a duplication issue and
  a code-comment issue, which were apparently causing build
  failures. Our code doesn't have these issues to begin with.

[1]: They do still live in node_modules. It's possible for pods to
     be hosted online and downloaded on `pod install`, npm-style.
     For an example, see the 'Toast' dependency in
     node_modules/react-native-simple-toast/react-native-simple-toast.podspec.
     But that's not what's happening here, yet.
     facebook/react-native@2321b3fd7 hints that this will be the way
     of the future for React Native, "to make the experience nicer
     for library consumers".

[2]: https://guides.cocoapods.org/syntax/podspec.html#subspec
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this pull request Jun 1, 2020
Closes zulip#3548!

Using the RN Upgrade Helper, a web app showing the diff from the
release/0.59.10 and the release/0.60.6 branches of the
`react-native-community/rn-diff-purge` repo, at
https://react-native-community.github.io/upgrade-helper/?from=0.59.10&to=0.60.6.

A lot of work has already been done toward this:

- most of the fixes necessary to adapt to Flow 0.98, without
  upgrading Flow yet (zulip#3827). We do the upgrade in this commit, with
  warnings temporarily suppressed, for smaller commits.

- updating to AndroidX (zulip#3852)

- migrating to using CocoaPods at all (zulip#3987)

Also, do what needs to be done atomically with the upgrade, as
follows.

Note: The following warning appears and will be fixed with follow-up
work:

```
warn The following packages use deprecated "rnpm" config that will
stop working from next release:
  - react-native-orientation:
    https://github.com/yamill/react-native-orientation#readme
  - rn-fetch-blob: https://npmjs.com/package/rn-fetch-blob
```

----- Platform-agnostic --------------------------------------------

After the upgrade, we get this peer dep warning:

warning " > react-native-webview@5.12.1" has incorrect peer dependency "react-native@>=0.57 <0.60".

`react-native-webview@7.0.0` is the minimum supported with RN
v0.60.0. But if we try to get `react-native-webview@7.0.0 before the
upgrade, we get this warning:

warning " > react-native-webview@7.0.0" has incorrect peer dependency "react-native@>=0.60 <0.62".

So, handle `react-native-webview` in this commit.

Also run `yarn yarn-deduplicate && yarn`, as prompted by
`tools/test deps`.

We've left "scripts" in `package.json` alone; ours work fine as-is.

----- Android ------------------------------------------------------

There are no updates on the Android side that must happen atomically
with the RN upgrade.

Some Android changes never appear in this series:

- Adding the `debug.keystore` file and its config in
  `android/app/build.gradle`. See more explanation and a code
  comment there in another commit in this series.

- Adding `android.useAndroidX=true` and
  `android.enableJetifier=true` in `android/gradle.properties`.
  These were done in e433197.

- Deleting `android/keystores/BUCK` and
  `android/keystores/debug.keystore.properties`: We don't use Buck
  (removal of some of its boilerplate was 1c86488), and we don't
  have an `android/keystores` directory. As mentioned in another
  commit in this series, we're happy with the Android
  Studio-provided debug keystore, and our own release keystore
  described in our release guide.

----- iOS ----------------------------------------------------------

facebook/react-native@2321b3fd7 appears to be the only cause of iOS
changes that must happen atomically with the RN v0.60 upgrade.

In that commit, all the "subspecs" that were nested under the
"React" pod are un-nested so they each become their own pod, with
many of these living in their own directory under
node_modules/react-native/Libraries [1].

In our own code, this means changing our Podfile to refer to all
these new pods, instead of the "React" pod's subspecs. So, do.

Our Podfile has a list of "Pods we need that depend on React
Native". We must also be sure all the dependencies in this list
adapt to facebook/react-native@2321b3fd7.

The syntax for pointing explicitly to a subspec is a slash, as in
"React/Core" [2]. Knowing this, we check that list for pods that
explicitly depended on those subspecs, with "React/[...]":

```
grep -Rl dependency.*React/ --include=\*.podspec \
  --exclude="node_modules/react-native/*" node_modules
```

There are two, and they both have new versions that adapt to the new accepted shape:

- `zmxv/react-native-sound@2f2c25a69`: "React/Core" -> "React"
- `joltup/rn-fetch-blob`, `01f10cb10^..0f6c3e3cc`: "React/Core" -> "React-Core"

So, take these new versions, and job done.

Some iOS changes from the upgrade guide don't appear in this series.
They fall neatly into a few touched files:

- ios/ZulipMobile-tvOS/Info.plist: We're not (yet) in the TV
  business. ;)

- ios/ZulipMobile.xcodeproj/project.pbxproj: The purge of many large
  chunks of this file, often known as "the Xcode config file", was
  already done, in 33f4b41.

- ios/ZulipMobile.xcworkspace/contents.xcworkspacedata: After
  33f4b41, this file already looks the way it should.

- ios/ZulipMobile/Info.plist: These changes are done upstream in
  facebook/react-native@7b44fe56f. They fix a duplication issue and
  a code-comment issue, which were apparently causing build
  failures. Our code doesn't have these issues to begin with.

[1]: They do still live in node_modules. It's possible for pods to
     be hosted online and downloaded on `pod install`, npm-style.
     For an example, see the 'Toast' dependency in
     node_modules/react-native-simple-toast/react-native-simple-toast.podspec.
     But that's not what's happening here, yet.
     facebook/react-native@2321b3fd7 hints that this will be the way
     of the future for React Native, "to make the experience nicer
     for library consumers".

[2]: https://guides.cocoapods.org/syntax/podspec.html#subspec
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this pull request Jun 3, 2020
Using the RN Upgrade Helper, a web app showing the diff from the
release/0.59.10 and the release/0.60.6 branches of the
`react-native-community/rn-diff-purge` repo, at
https://react-native-community.github.io/upgrade-helper/?from=0.59.10&to=0.60.6.

- Upgrade `react-native`, `react`, and `flow-bin` following the
  templates.

- Upgrade `react-native-webview` to satisfy peer dependencies and
  remove the outdated libdef (to be replaced in an upcoming commit).

- Adapt our Podfile to RN v0.60's new layout of pods, following the templates.

- Upgrade `react-native-sound` and `rn-fetch-blob` to versions with
  podspecs compatible with the new pod layout in RN v0.60. A lot of
  work has already been done toward this:

- We ignore or have already handled several changes to the Xcode and
  Gradle configs.

A lot of work has already been done toward the upgrade:

- most of the fixes necessary to adapt to Flow 0.98, without
  upgrading Flow yet (zulip#3827). We do the upgrade in this commit, with
  warnings temporarily suppressed, for smaller commits.

- updating to AndroidX (zulip#3852)

- migrating to using CocoaPods at all (zulip#3987)

Note: The following warning appears when running Metro and will be
fixed with follow-up work:

```
warn The following packages use deprecated "rnpm" config that will
stop working from next release:
  - react-native-orientation:
    https://github.com/yamill/react-native-orientation#readme
  - rn-fetch-blob: https://npmjs.com/package/rn-fetch-blob
```

----- Platform-agnostic --------------------------------------------

After the upgrade, we get this peer dep warning:

"""
warning " > react-native-webview@5.12.1" has incorrect peer
dependency "react-native@>=0.57 <0.60".
"""

`react-native-webview@7.0.0` is the minimum supported with RN
v0.60.0. But if we try to get `react-native-webview@7.0.0 before the
upgrade, we get this warning:

"""
warning " > react-native-webview@7.0.0" has incorrect peer
dependency "react-native@>=0.60 <0.62".
"""

In a previous commit, we removed the outdated libdef, with a
suppression. We upgrade `react-native-webview` to at least 7.0.0 in
this commit, then add the updated libdef in an upcoming commit.

`react-native-webview` does declare that it follows semantic
versioning [1], so we can feel comfortable taking a 7.x version
later than 7.0.0. We take 7.6.0, the latest. Nicely, this gets us
the changes from one of our PRs, released in 7.0.3; see 1982f3f
and its reversion in the commit that followed, bbfac73.

Handling the declared breaking changes [1] is straightforward:

- Update to AndroidX (v6.0.2). If this is a real breaking change, we
  handled it in e433197.

- UIWebView removed (7.0.1). This prompted the `scalesPageToFit`
  prop to be removed, but we don't use it. The `useWebKit` prop was
  also removed because it doesn't make sense for it to be anything
  but `true` now. So, remove our use of it.

Also run `yarn yarn-deduplicate && yarn`, as prompted by
`tools/test deps`.

We've left "scripts" in `package.json` alone; ours work fine as-is.

[1]: https://github.com/react-native-community/react-native-webview#versioning

----- Android ------------------------------------------------------

There are no updates on the Android side that must happen atomically
with the RN upgrade.

Some Android changes never appear in this series:

- Adding the `debug.keystore` file and its config in
  `android/app/build.gradle`; we don't take these changes at all.
  See 9ccaa21.

- Adding `android.useAndroidX=true` and
  `android.enableJetifier=true` in `android/gradle.properties`.
  These were done in e433197.

- Deleting `android/keystores/BUCK` and
  `android/keystores/debug.keystore.properties`: We don't use Buck
  (removal of some of its boilerplate was 1c86488), and we don't
  have an `android/keystores` directory. As mentioned in 9ccaa21,
  we're happy with the Android Studio-provided debug keystore, and
  our own release keystore described in our release guide.

----- iOS ----------------------------------------------------------

facebook/react-native@2321b3fd7 appears to be the only cause of iOS
changes that must happen atomically with the RN v0.60 upgrade.

In that commit, all the "subspecs" that were nested under the
"React" pod are un-nested so they each become their own pod, with
many of these living in their own directory under
node_modules/react-native/Libraries [1].

In our own code, this means changing our Podfile to refer to all
these new pods, instead of the "React" pod's subspecs. So, do.

Our Podfile has a list of "Pods we need that depend on React
Native". We must also be sure all the dependencies in this list
adapt to facebook/react-native@2321b3fd7.

The syntax for pointing explicitly to a subspec is a slash, as in
"React/Core" [2]. Knowing this, we check that list for pods that
explicitly depended on those subspecs, with "React/[...]":

```
grep -Rl dependency.*React/ --include=\*.podspec \
  --exclude="node_modules/react-native/*" node_modules
```

There are two, and they both have new versions that adapt to the new
accepted shape:

- `zmxv/react-native-sound@2f2c25a69`: "React/Core" -> "React"
- `joltup/rn-fetch-blob`, `01f10cb10^..0f6c3e3cc`: "React/Core" -> "React-Core"

So, take these new versions, and job done.

Some iOS changes from the upgrade guide don't appear in this series.
They fall neatly into a few touched files:

- ios/ZulipMobile-tvOS/Info.plist: We're not (yet) in the TV
  business. ;)

- ios/ZulipMobile.xcodeproj/project.pbxproj: The purge of many large
  chunks of this file, often known as "the Xcode config file", was
  already done, in 33f4b41.

- ios/ZulipMobile.xcworkspace/contents.xcworkspacedata: After
  33f4b41, this file already looks the way it should.

- ios/ZulipMobile/Info.plist: These changes are done upstream in
  facebook/react-native@7b44fe56f. They fix a duplication issue and
  a code-comment issue, which were apparently causing build
  failures. Our code doesn't have these issues to begin with.

[1]: They do still live in node_modules. It's possible for pods to
     be hosted online and downloaded on `pod install`, npm-style.
     For an example, see the 'Toast' dependency in
     node_modules/react-native-simple-toast/react-native-simple-toast.podspec.
     But that's not what's happening here, yet.
     facebook/react-native@2321b3fd7 hints that this will be the way
     of the future for React Native, "to make the experience nicer
     for library consumers".

[2]: https://guides.cocoapods.org/syntax/podspec.html#subspec

Fixes: zulip#3548
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this pull request Jun 3, 2020
Using the RN Upgrade Helper, a web app showing the diff from the
release/0.59.10 and the release/0.60.6 branches of the
`react-native-community/rn-diff-purge` repo, at
https://react-native-community.github.io/upgrade-helper/?from=0.59.10&to=0.60.6.

In this commit:

- Upgrade `react-native`, `react`, and `flow-bin` following the
  templates

- Upgrade `react-native-webview` to satisfy peer dependencies

- Adapt our Podfile to RN v0.60's new layout of pods, following the
  templates

- Upgrade `react-native-sound` and `rn-fetch-blob` to versions with
  podspecs compatible with the new pod layout in RN v0.60

A lot of work has already been done toward the upgrade:

- most of the fixes necessary to adapt to Flow 0.98, without
  upgrading Flow yet (zulip#3827). We do the upgrade in this commit, with
  warnings temporarily suppressed, for smaller commits.

- updating to AndroidX (zulip#3852)

- migrating to using CocoaPods at all (zulip#3987)

- We ignore or have already handled several changes, e.g., to the
  Xcode and Gradle configs (see comment at zulip#3548).

Note: The following warning appears when running Metro and will be
fixed with follow-up work (e.g., zulip#4118):

```
warn The following packages use deprecated "rnpm" config that will
stop working from next release:
  - react-native-orientation:
    https://github.com/yamill/react-native-orientation#readme
  - rn-fetch-blob: https://npmjs.com/package/rn-fetch-blob
```

----- Platform-agnostic --------------------------------------------

We upgrade `react-native-webview` in this commit because versions
before 7.x aren't compatible with RN v0.60, and versions 7.x aren't
compatible with RN v0.59 (judging by peer dependency warnings). We
take the latest 7.x version, 7.6.0.

Nicely, this gets us the changes from one of our PRs, released in
7.0.3; see 1982f3f and its reversion in the commit that followed,
bbfac73.

There's just one declared breaking change [1] in 7.x.x:

- UIWebView removed (7.0.1).

This prompted the `scalesPageToFit` prop to be removed, but we don't
use it. The `useWebKit` prop was also removed because it doesn't
make sense for it to be anything but `true` now. So, remove our use
of it.

Also run `yarn yarn-deduplicate && yarn`, as prompted by
`tools/test deps`.

[1]: https://github.com/react-native-community/react-native-webview#versioning

----- Android ------------------------------------------------------

There are no updates on the Android side that must happen atomically
with the RN upgrade.

----- iOS ----------------------------------------------------------

facebook/react-native@2321b3fd7 appears to be the only cause of iOS
changes that must happen atomically with the RN v0.60 upgrade.

In that commit, all the "subspecs" that were nested under the
"React" pod are un-nested so they each become their own pod, with
many of these living in their own directory under
node_modules/react-native/Libraries [1].

In our own code, this means changing our Podfile to refer to all
these new pods, instead of the "React" pod's subspecs. So, do.

Our Podfile has a list of "Pods we need that depend on React
Native". We must also be sure all the dependencies in this list
adapt to facebook/react-native@2321b3fd7.

The syntax for pointing explicitly to a subspec is a slash, as in
"React/Core" [2]. Knowing this, we check that list for pods that
explicitly depended on those subspecs, with "React/[...]":

```
grep -Rl dependency.*React/ --include=\*.podspec \
  --exclude="node_modules/react-native/*" node_modules
```

There are two, and they both have new versions that adapt to the new
accepted shape:

- `zmxv/react-native-sound@2f2c25a69`: "React/Core" -> "React"
- `joltup/rn-fetch-blob`, `01f10cb10^..0f6c3e3cc`: "React/Core" -> "React-Core"

So, take these new versions, and job done.

[1]: They do still live in node_modules. It's possible for pods to
     be hosted online and downloaded on `pod install`, npm-style.
     For an example, see the 'Toast' dependency in
     node_modules/react-native-simple-toast/react-native-simple-toast.podspec.
     But that's not what's happening here, yet.
     facebook/react-native@2321b3fd7 hints that this will be the way
     of the future for React Native, "to make the experience nicer
     for library consumers".

[2]: https://guides.cocoapods.org/syntax/podspec.html#subspec

Fixes: zulip#3548
@chrisbobbe chrisbobbe deleted the pr-use-cocoapods branch November 6, 2020 03:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Set up CocoaPods
3 participants