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

Draft: Packaging guide for iOS #3861

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

michalchudziak
Copy link

This PR introduces a comprehensive guide on packaging React Native modules as .framework for iOS:

  • Describes the motivation to package React Native modules for integration with native apps.
  • Provides step-by-step instructions, from creating a new React Native app to building the framework.
  • ... TODO

The goal of this new documentation is to equip developers with the knowledge needed for seamless integration of React Native modules into native iOS projects.

@netlify
Copy link

netlify bot commented Sep 28, 2023

Deploy Preview for react-native ready!

Name Link
🔨 Latest commit fe76e97
🔍 Latest deploy log https://app.netlify.com/sites/react-native/deploys/651565d07809a400089802ce
😎 Deploy Preview https://deploy-preview-3861--react-native.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@cipolleschi
Copy link
Contributor

Hi @michalchudziak, thanks for this guide, but I have a few questions:

  1. how can I see the preview from netlify? I see that the guide is not connected with the sidebar and if I navigate to docs/packaging-ios, I can't see it.
  2. There are some linting error that should be fixed
  3. What's the goal with this guide? From which need does it come from? I am not sure that this is what we actually want to promote as a way to package libraries: we already have a guide to package iOS (and Android) modules use NPM and that should be the suggested way to ship those libraries. On top of that, packaging the code as XCFramework is not that straightforward if we think about the New Architecture and the code generated by Codegen: the framework you'd like to ship will not build as it needs the files generate by codegen that lives in the app space and not in the framework space.
    So, as of today, I don;t think that we can/should ship a guide like this: it is quite advanced and it can create confusion in the majority of React Native users.

Begin by generating a fresh React Native project:

```bash
npx react-native init HighScores2048
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
npx react-native init HighScores2048
npx react-native@latest init HighScores2048

@michalchudziak
Copy link
Author

michalchudziak commented Sep 29, 2023

Hey @cipolleschi! The PR isn't finished, which is why it's in a draft state. I haven't yet focused on fixing the linting issues and testing the actual preview (it's certainly not ready for merging yet).

Regarding point 3, I see significant value in the XCFramework approach, especially when considering brownfield applications. I've outlined the rationale behind this in the Why Package React Native? section of the docs.

When incorporating React Native modules into a native app, it's frequently necessary to bring in JavaScript-specific tooling, such as yarn, metro-bundler, jest, and other related tools. However, this can create challenges, as it might raise the entry barrier for native development teams. Furthermore, it's not uncommon for React Native teams to operate independently from native teams. In situations like these, dividing development across separate repositories can be beneficial. This is where packaging becomes invaluable.

I believe it aligns well with specific code organization patterns and organizational structures.

We're definitely keeping the new architecture in mind, and we want to ensure we consider it before finalizing this guide. Unless I'm mistaken, I believe that moving the generated files can be managed with a post-install script. I'm considering adding this information to the guide, alongside the Swift guide.

Do you think that if we address this, there would be room for such a guide in the docs? Maybe in the advanced section?


## Creating a 2048 High Scores Package

In this guide, you'll craft a High Scores screen, similar to the one made in the [guide to integrate with native apps](https://reactnative.dev/docs/integration-with-existing-apps?language=objc). You'll package it as a standalone `.xcframework` file. Afterward, you can use it directly in a native app like any native library, eliminating the need for installing any JavaScript dependencies.
Copy link

Choose a reason for hiding this comment

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

What if I like to use only a certain component not a whole "screen"? I understand the doc "how can I integrate a component" so a single view not exactly whole screen. I would like to see guidance for this case + the whole screen if the implementation paths are different for them.

Copy link
Author

Choose a reason for hiding this comment

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

The guide covers that case, but perhaps we should make it more explicit. Simply register the component in AppDelegate, and you should be good to go. The guide how to export a UIView instance, not a ViewController or anything that would make it work only as a screen.

Copy link

Choose a reason for hiding this comment

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

The guide how to export a UIView instance, not a ViewController - perhaps I misunderstood sth but I believe we want to export RN code to work in XCode project not UIView into RN project.


### Starting a New React Native App

Begin by generating a fresh React Native project:
Copy link

Choose a reason for hiding this comment

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

Why do I need to create a whole project if it is said we can integrate components? I would like to see explanation if this is the only way.

Copy link
Author

Choose a reason for hiding this comment

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

Right. In that case we can register multiple root views and duplicate the binding files. I think it would be good to explain that explicitly in the docs tho.

AppRegistry.registerComponent('HighScores', () => HighScores);
```

Finally, modify the code in `AppDelegate.mm` so it references the correct component. Also, feed mocked data to the view for development testing.
Copy link

Choose a reason for hiding this comment

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

I have not noticed when you created an iOS project. Besides, you assume there is AppDelegate. Not sure about ObjC but using Swift there is more likely you see SceneDelegate and no AppDelegate. The description seems to be incomplete.

Copy link
Author

Choose a reason for hiding this comment

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

I'm reusing the project generated by the RN template, I haven't accounted for creating a fresh project form the scratch. Also it only serves as a playground, so I don't consider it crucial for the whole integration.

Copy link

Choose a reason for hiding this comment

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

But wait, we would like to use RN components inside MY OWN XCODE PROJECT. I understand we need to create a framework using RN project to finally use it inside XCode project. I miss more explicit explanation what is the goal and steps to achieve this.

@cipolleschi
Copy link
Contributor

@michalchudziak I agree that XCFrameworks can bring benefit, but we can have this page in the official documentation, unfortunately.

This can make for an amazing post in your company blogpost, but for the official documentation we want to have something that is battle-tested and work in all the scenarios, including the New Architecture, and that integrates well with the current tooling (e.g. autolinking).
At the moment, none of these requirements are true:

  • We are not using packaged Xcframeworks internally (except from hermes-engine, which required a non trivial amount of work to have it working properly) => Not battle tested
  • It doesn't work well in all the scenarios => the New Architecture is not supported
  • It does not integrates well with the current tooling => it doesn't work with autolinking (as you have to reference the target manually and to modify the AppDelegate.mm) and it requires multiple steps to integrate from our users.

Also considering that now we can build dependencies with use_frameworks! and dynamic linking, the pros of packaging the library as XCFramework are obtainable in another way and with much less effort.


### Setting Up a New Package Target

Now, create a separate Xcode target to build our `.xcframework` package. Open the `ios/HighScores2048.workspace` file. In Xcode, navigate to the targets section and select **Add new target (+)**.
Copy link

Choose a reason for hiding this comment

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

You create in in Xcode (your XCode project) or this is a RN project's iOS part? Why do you create a framework? It is said we will integrate RN code in to XCode project. The vast majority of cases user will have an XCode app project not a framework. There is no explanation why you do so.
MY goal and understanding:
Integrate some RN components into my own standalone XCode app project. I do not see this here.

@michalchudziak
Copy link
Author

@cipolleschi I completely understand your point. Just to be clear, it does work with auto-linking without any issues. The change to the app delegate is not essential for the packaging process; it's solely about changing the name to demonstrate the ability to have multiple root views. In fact, AppDelegate is not used in this process at all.

I also think that achieving support for new architecture is possible with minimal overhead (at least in a simple setup), as described in the comment above. Also, I can't fully agree with the use_frameworks! argument, as I believe it addresses a slightly different use case, but I can't argue with the "battle-tested" point, hence I think I'll follow your suggestion and address this in a blog post. Thanks for the review!


![Screenshot](/docs/assets/PackagingCreateNewTarget.png)

If done correctly, you'll see a `HighScore2048Module` folder on the left sidebar and a new yellow suitcase icon in the targets section.
Copy link

Choose a reason for hiding this comment

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

typeo in name of the module (missing s). Should be: HighScores2048Module


![Screenshot](/docs/assets/PackagingAddNewTarget.png)

From the options, pick `Framework` and name it **HighScore2048Module**. Ensure the **Embed in Application** option remains off.
Copy link

Choose a reason for hiding this comment

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

typeo in name of the module (missing s). Should be: HighScores2048Module

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.

None yet

6 participants