xref: /expo/ios/CONTRIBUTING.md (revision 8b4c59e5)
1# Contributing to Expo for iOS
2
3This guide provides an overview of what you need to know to contribute to the Expo iOS project. It does not touch specifically on how to build Expo SDK native modules; there is a separate guide for that.
4
5## Prerequisites / Getting Started
6
7To get the Expo Client running (on either platform), follow the README in the parent directory.
8
9## Branch Organization
10
11- We try to stay on, or near, `main`.
12- When we release a new SDK version, we push a release branch of the form `ios/sdkNN`.
13- Specific versions of the iOS Expo Client are tagged from that release branch, such as `ios/1.19.0`.
14- New changes are written on `main`. When we cut a new release, we either cherry-pick from `main` to the release branch (for small changes) or just recreate the release branch.
15- If we're near the end of a SDK cycle, we may be operating on a SDK candidate branch instead of `main`.
16
17## Pull Requests
18
19- Target `main` most of the time. If there's a SDK candidate branch (a few days near the end of the cycle), target that instead.
20- We don't maintain an explicit style guide, so for now it's best to just observe what the rest of the codebase does and mimic that.
21- Make sure your xcode file tree reflects the directory structure on disk.
22
23## Contexts in which this project may run
24
25This code can be run in a few contexts:
26
27- As the Expo Client app.
28- As a standalone (shell) app. In this case, the project is pre-built, and then some tooling modifies configurations in the NSBundle to cause it to run as a standalone app.
29
30The `EXShellManager` class keeps track of how the code is being run. Mostly it reads the contents of a couple `.plist` files in the bundle.
31
32## Dependencies
33
34We use CocoaPods to manage dependencies. Rather than committing `Podfile`, we use `template-files/ios/dependencies.json`. To add a dependency:
35
36- Add it to `dependencies.json`
37- Run `et ios-generate-dynamic-macros`. This will write `Podfile` (for the Expo Client) and `ExpoKit.podspec` (for standalone apps, which use almost all of the same code as Expo Client, and therefore have the same dependencies).
38
39## Testing
40
41You can run our API tests from `apps/test-suite` against a native XCTest target called `ExponentIntegrationTests`.
42
431. Make sure `ExponentIntegrationTests/EXTestEnvironment.plist` contains a url to the `test-suite` project. If you are running from our monorepo, you can run `powertools configure-ios-test-suite-url` to do this automatically.
442. Open the workspace in Xcode and `Test` it. (Cmd+U)
45
46## Versioning
47
48Expo Client can run Expo projects using any of the last several Expo SDK versions. To support this, it includes native code for each of those SDK versions. This code lives under `versioned-react-native`.
49
50Code for each SDK version includes a copy of React Native corresponding to that SDK version, as well as a set of Expo SDK classes. In order to prevent naming conflicts at compile time, all symbols in versioned code are prefixed.
51
52Contributions to the Expo Client happened in "unversioned" code; that is, code which has not been included in an Expo SDK yet, without any symbol prefix.
53
54To test changes in the "unversioned" code, change your `sdkVersion` from `app.json` to `UNVERSIONED`.
55
56```json
57{
58  "expo": {
59    "sdkVersion": "UNVERSIONED"
60  }
61}
62```
63
64## Project Architecture
65
66The Expo Client is an iOS app containing the Expo Kernel. The Kernel is a piece of code which can run and manage multiple React Native apps at once. Most of the technical challenges of the codebase arise from these constraints:
67
68- Multiple React Native bridges can be running at once.
69- They can be running different versions of React Native from each other.
70- They are sandboxed from one another.
71- They may be production apps (minified, no dev tools) or development (running from a packager, possibly enabling dev tools).
72
73### Expo Client entry point
74
75Almost everything in the project is included in the ExpoKit library (see `ExpoKit.podspec`). The Expo Client is just a special user of ExpoKit. Therefore it includes some extra classes to provide an entry point to the application:
76
77- `EXAppDelegate`: The app delegate. Try to keep this file small. Mostly it should call into `ExpoKit` methods, unless you really want to add functionality that is specific to Expo Client and should not work in standalone apps.
78- `EXRootViewController`: Same story as AppDelegate. This implements any view controller functionality which only needs to apply to Expo Client and not standalone apps.
79
80### Versioned directory
81
82Everything under this directory will be duplicated and namespaced when we release the next SDK version. It includes:
83- All of the Expo SDK native modules, components, view managers, etc. This code is the "unversioned" Expo SDK.
84- A few utility classes which help run namespaced and scoped modules. In particular, any utilities which need to be namespaced/duplicated with each SDK version.
85- You can see older versions of this directory under `versioned-react-native/ABI*/Exponent`.
86
87### ExpoKit directory
88
89This contains the public ExpoKit API exposed by the ExpoKit CocoaPod, which basically ends up being used only in standalone iOS apps.
90
91### ReactAppManager
92
93A ReactAppManager owns a single React Native bridge and root view. There are two subclasses: `EXKernelReactAppManager`, which owns a privileged instance of the Expo Home experience, and `EXFrameReactAppManager`, which owns a normal (non-Home) Expo app.
94
95There may be many instances of `EXFrameReactAppManager` at once, but there will only ever be one instance of `EXKernelReactAppManager`.
96
97A ReactAppManager keeps track of the lifecycle of a React Native app. Though it is unversioned, it uses reflection to instantiate a versioned bridge and root view and act as their delegate. It also acts as an interface to their devtools. ReactAppManager utilities which need to be versioned are contained in EXVersionManager.
98
99### Kernel directory
100
101This directory contains the native code powering the Expo kernel. Here's roughly how the kernel is structured:
102
103![image](https://user-images.githubusercontent.com/1316332/29846489-f362b0c6-8ccb-11e7-8d69-a4bebaf19c70.png)
104
105The Bridge Registry keeps track of all the React Native bridges running at a given time, including where they are in their loading/error lifecycle, which one is visible to the user, which one (if any) is being developed from a packager, etc.
106
107Each bridge is wrapped in a ReactAppManager (explained elsewhere in this guide).
108
109The Services Registry contains a set of "services" which represent shared device resources. They are singleton and unversioned. Native modules in the Expo SDK have a mechanism for receiving a pointer to an unversioned kernel service at runtime (see `EXScopedModuleRegistry` for details). It is their job to broker shared device resources between various sandboxed and versioned React Native apps.
110