-
Notifications
You must be signed in to change notification settings - Fork 132
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
install and link native modules from npm (as alternative to cocoapods/carthage) #60
Comments
This is something which has been on my mind recently as well. The experience as it stands at the minute only partly automates the process and leaves a lot of room for errors, especially with users who are not experienced with the native build systems. Android is a fairly solved issue with the Gradle dependency system and most libraries making use of the iOS, however, needs some work. For the Apple provided iOS frameworks, we could simply allow the React Native libraries to specify which ones they require in a standard way (for example For third-party libraries, I think there are two possible directions this could be taken: Create a
|
I was considering same approaches, with exactly same reasoning (which is very encouraging).
Well, one of my goals is to provide tooling for third party developers to create (and publish) such a package easily. Most common packages (modules) could be published in @native_modules (or similar) scope to npm. Third party under their npm's "private" (not so) scope. In mean time I've started work on react-native's local-cli linker/xcode project parser replacement. Even if decision will be made to go with Carthage, I think it's worth to be working on. The current one uses cordova xcode project and have some issues:
New linker/project parser will also add features like:
The linker/project parser will work nicely with carthage too, but doesn't make sense with cocoapods. EDIT: edited multiple times |
Reacting only to the first part of the sentence (cocoapods are different story). You really need some global repository of native modules, either it will be carthage or npm (or cocoapods). Even then there will be some conflicts coming from 3-rd party packages (but in much smaller scale - let's hope). EDIT: edited multiple times. |
I edited my comment above with links to how NativeScript handles plugins with dependencies and custom build settings. They have some nice idea which we could borrow.
That makes sense. Having them in NPM would still mean that new versions would need to be published after the native library itself publishes an update. We'd need to be careful to make sure that this isn't reliant on a small group of people to do it or for there to be a single point of failure where someone is the only person with access but they are no longer actively maintaining the package.
XCodeGen looks like a good solution to this. It takes a YAML or JSON file and generates XCode project files from it. The file can contain dependencies and supports Carthage out of the box. I agree that the local-cli link is pretty bad at the minute. I actually manually link most of the time as it's broken often enough that I've found it's easier to just do it myself. My background is in native app development though, which isn't typical of the React Native community at large.
I've hit that issue as well. I even had the fun of one of the native libraries which React Native itself embeds clashing with an embedded one from a non-opensource Google library. That was very hacky to solve. I believe this is why they strongly recommend using Cocoapods instead. |
Looks interesting. But don't see having it any sort of API. It looks like it only supports create project from initial configuration file. But might be wrong. Missing some API's that will update that file with configuration from package.json. Something like:
EDIT: but it could be added easily, as it's matter of updating json file (much easier than write whole parser from scratch). |
The idea would be to generate the xcodeproj files from the YAML or JSON using the XcodeGen tool. If you needed to make a change you would edit the YAML or JSON and then regenerate the xcodeproj file. This has the advantage that the edits are very simple to make; you're just editing a JSON file with a known structure. However, it does mean that we're requiring another binary and completely deleting and regenerating the users XCode project file, which won't work if the user has made changes to it manually or if they're using React Native in an existing native app. I agree that altering the project file directly is likely the best solution. The generator uses this Swift library to do it and there is also the Ruby library which Cocoapods uses. Neither of these are easy to integrate directly with a node script, but they seem to have much better support than the Cordova one which you mentioned. |
Cc @grabbou. I think he said he wrote a parser and transformer for xcodeproj files for React-Native link. |
Combination of XcodeGen, Carthage and xcodeproj transformer seems like viable solution to me. But how it will work, without any changes to core react-native? How will third party plugins link their native modules? So far I can think of, following steps would be necessary:
IMO without the react-native support every package would have to do all above steps (in postlink phase). 2. - 4. are fine, but what worries me are repeating steps 1. and 5. We could get rid of those transformations steps (1. and 5.), but it would require some support from react-native itself. React-native would have to replace the pbxproject with XcodeGenFormat and wrote some scripts that will run step 5. as part of build step. But not sure how real it is (to ask rn team to implement/merge something like this). More questions:
EDIT: My former proposal assumed no cooperation (no changes to core react-native) with rn team whatsoever. However if such cooperation is possible, then what we really need is this native module declaration, so every plugin can declare it's native dependencies in |
100% agree. Less a problem when carthage is used. In matter of fact, I already commited some PRs to add carthage support for libraries that didn't have it. matghazaryan/SOMotionDetector#35 The process of adding carthage support can be pretty much reduced to single command with https://github.com/mauron85/XcodeToolSource (uses XcodeTool and modified template) |
Relevant discussion - #18 |
Sorry I haven't taken part in this discussion earlier - I was a bit busy working on the CLI related things. This is a very important topic and something we need to figure out - not just the "best" way to handle native dependencies of 3rd party native modules, but native modules itself too. Let me read through this issue and come up with some observations soon. |
Hey, Thanks for opening up this issue and providing so many helpful informations (including few proposals and alternative solutions - this is very encouraging). We are also discussing this matter on "React Native Community Discord". Will keep you updated (or someone else as I am going to be on a leave till the end of the year). As you already noted, "link" hasn't been working much reliably in recent months. This is due to numerous changes that affected native iOS and Android projects as well as lack of the proper maintenance for the past year. It is a good indicator how expensive it is to keep such abstraction up to date. Having that in mind, I think we should circle back and design this all over, not just for the "native dependencies", but for whole React Native packages too. I would really like the process of linking and dependency management to be as easy on iOS as it is already on Android, thanks to Gradle. Thanks @mauron85 and @matt-oakes for starting this thread and listing down few options you have already explored. Out of all the proposals mentioned here so far, I like the one that uses "native dependency manager" (e.g. CocoaPods / Carthage) the most.
I believe we should just do what other native developers already do on the platform. It has the benefit of being already familiar to the native developers and makes React Native much easier to co-exist in a brownfield environment (that is, environment where there's both native and React Native codebase running at the same time). When you look at the current state of things, it turns out that we already have this kinda supported. There's React pod in the main repository that allows you to consume React Native via CocoaPods. It is also quite popular amongst the community, with many 3rd party packages already shipping their pods too. Expo is also already using CocoaPods to support "ejected" applications, which might be an additional driver for promoting this pattern throughout the community. However, I don't think we need this part:
As "link" already taught us, it is quite expensive abstraction to maintain. Also, in my opinion, providing another abstraction for handling native dependencies will never satisfy all of the use-cases that direct use of CocoaPods already does. Not to mention we would have to work on a lowest common denominator of features between both CocoaPods and Gradle in order to treat "package.json" as a source of truth for both platforms. That said, it looks that we are already there. CocoaPods support is there, community modules support it. However, since we are having this discussion, it does not work as intended. In my opinion, here's why:
In my opinion, here's what we need to do to make it better:
Curious to hear your thoughts! Please mind if it takes me longer to answer due to holidays period. |
Cocoapods is helpful for this: https://github.com/expo/expo/blob/1bdf36dcd5d4e4abc8ea7d0439f3a8c582968ee0/packages/expo-gl/ios/EXGL.podspec#L19-L22 |
@grabbou I like your approach. We have a fairly large react-native brownfield app (top 3 themepark in europe) and we are using cocoapods for our ios dependencies (both 'vanilla' native and react-native) already because it works best for us. Some of the benefits are that we are able to specify dependencies of dependencies as cocoapods already supports it (see comment of @brentvatne above), it allows us to manage react-native and 'vanilla' native dependencies the same way and native developers already know the ecosystem + it is fairly easy to learn for our RN'devs. Lots of dependencies (react-native and 'vanilla' native) already support it. We don't have any intention of migration our whole app to react-native as we are using it only where it has clear benefits. At the moment +/- 40% of our codebase compared to +/- 30% Android and +/- 30% iOS. |
The full specification for a https://guides.cocoapods.org/syntax/podspec.html#specification It supports:
As much as I dislike Cocoapods for the amount of "magic" is has inside it, it is the main tool which iOS developers will use for their dependencies and it's very uncommon to come across a library which doesn't support it. If we mandated that all React Native libraries are linked using Cocoapods then novice users would easily be able to link iOS in the same way that Gradle handles Android dependencies. The disadvantage is that Cocoapods is an "all or nothing" style dependency manager and once it's integrated it's very hard to remove from a project. For most users, this will be absolutely fine as they'll be using React Native with very little custom native code, however, it's a much bigger issue for apps where React Native is used for only a small part of the app. Open questions:
|
I share same distaste for cocoapods, but if react-native migrate its init template to cocoapods format, I can live with that and adjust all my plugins accordingly. But apart from that, I can only agree with you guys and also thanks for new ideas and explanations (and bit context and history). I'll probably continue to put effort on my former proposal anyway (as I have already started). Not saying it'll result in something useful (but hopefully it will bring at least some new helper tools). |
One way to foster a marketplace of ideas approach to discovering a good answer here would be to have react-native allow the Then one could Right now one cannot (which is the reason I implemented |
I am going to close this discussion in favour of #96 - I wrapped up all we have talked so far (thank you so much for opening this) into a broader problem that covers all native modules in general. Let's have a discussion over there! |
Introduction
Following is mostly valid for iOS.
Currently react-native-cli doesn't provide any support for plugin developers to install and link native modules like frameworks, static libraries, projects.
One can write custom link script and register it in rnpm's postlink phase and "misuse" not very well documented local-cli link scripts. However even with this approach, plugin needs to carry it's native dependencies. With more and more packages, this is slowly becoming a problem. I'm already aware of clang's linker error
"IOS build error duplicate symbols for architecture x86_64"
caused by two plugins linking same library.Another popular option is to manage plugin dependencies via cocoapods.
However IMO cocapods/carthage are kind of alien in world of react-native. User need to know, how to install it, how to create podfile, etc. Linking modules should be implementation detail and users should be able to link all modules with just single
react-native link
command.The Core of It
For all above reasons I decided to work on project I internally call native-modules. It will:
Discussion points
I understand I'm pretty brief here, but before going to deep into describing specification I would like know, if there is broad interest in such a thing.
The text was updated successfully, but these errors were encountered: