react-native/ReactAndroid
Sebastian Markbage 8d397b4cbc Decouple Module System from Native Calls
Summary:
The JavaScript ecosystem doesn't have the notion of a built-in native module loader. Even Node is decoupled from its module loader. The module loader system is just JS that runs on top of the global `process` object which has all the built-in goodies.

Additionally there is no such thing as a global require. That is something unique to our providesModule system. In other module systems such as node, every require is contextual. Even registered npm names are localized by version.

The only global namespace that is accessible to the host environment is the global object. Normally module systems attaches itself onto the hooks provided by the host environment on the global object.

Currently, we have two forms of dispatch that reaches directly into the module system. executeJSCall which reaches directly into require. Everything now calls through the BatchedBridge module (except one RCTLog edge case that I will fix). I propose that the executors calls directly onto `BatchedBridge` through an instance on the global so that everything is guaranteed to go through it. It becomes the main communication hub.

I also propose that we drop the dynamic requires inside of MessageQueue/BatchBridge and instead have the modules register themselves with the bridge.

executeJSCall was originally modeled after the XHP equivalent. The XHP equivalent was designed that way because the act of doing the call was the thing that defined a dependency on the module from the page. However, that is not how React Native works.

The JS side is driving the dependencies by virtue of requiring new modules and frameworks and the existence of dependencies is driven by the JS side, so this design doesn't make as much sense.

The main driver for this is to be able to introduce a new module system like Prepack's module system. However, it also unlocks the possibility to do dead module elimination even in our current module system. It is currently not possible because we don't know which module might be called from native.

Since the module system now becomes decoupled we could publish all our providesModule modules as npm/CommonJS modules using a rewrite script. That's what React Core does.

That way people could use any CommonJS bundler such as Webpack, Closure Compiler, Rollup or some new innovation to create a JS bundle.

This diff expands the executeJSCalls to the BatchedBridge's three individual pieces to make them first class instead of being dynamic. This removes one layer of abstraction. Hopefully we can also remove more of the things that register themselves with the BatchedBridge (various EventEmitters) and instead have everything go through the public protocol. ReactMethod/RCT_EXPORT_METHOD.

public

Reviewed By: vjeux

Differential Revision: D2717535

fb-gh-sync-id: 70114f05483124f5ac5c4570422bb91a60a727f6
2015-12-08 16:03:37 -08:00
..
libs Release React Native for Android 2015-09-14 18:13:39 +01:00
src Decouple Module System from Native Calls 2015-12-08 16:03:37 -08:00
.npmignore Don't publish /ReactAndroid/build to npm, update version on master 2015-10-12 11:11:40 -07:00
DevExperience.md Release React Native for Android 2015-09-14 18:13:39 +01:00
README.md Merge pull request #2953 from j27cai/and-patch 2015-10-14 17:00:59 +01:00
build.gradle Ability to run unit tests in react-android-github via gradle 2015-11-27 04:20:19 -08:00
gradle.properties Ability to run unit tests in react-android-github via gradle 2015-11-27 04:20:19 -08:00
release.gradle Release React Native for Android 2015-09-14 18:13:39 +01:00

README.md

Building React Native for Android

This guide contains instructions for building the Android code and running the sample apps.

Supported Operating Systems

This setup has only been tested on Mac OS so far.

Prerequisites

Assuming you have the Android SDK installed, run android to open the Android SDK Manager.

Make sure you have the following installed:

  • Android SDK version 23 (compileSdkVersion in build.gradle)
  • SDK build tools version 23.0.1 (buildToolsVersion in build.gradle)
  • Android Support Repository >= 17 (for Android Support Library)
  • Android NDK (download & extraction instructions here)

Point Gradle to your Android SDK: either have $ANDROID_SDK and $ANDROID_NDK defined, or create a local.properties file in the root of your react-native checkout with the following contents:

sdk.dir=absolute_path_to_android_sdk
ndk.dir=absolute_path_to_android_ndk

Example:

sdk.dir=/Users/your_unix_name/android-sdk-macosx
ndk.dir=/Users/your_unix_name/android-ndk/android-ndk-r10e

Run npm install

This is needed to fetch the dependencies for the packager.

cd react-native
npm install

Building from the command line

To build the framework code:

cd react-native
./gradlew :ReactAndroid:assembleDebug

To install a snapshot version of the framework code in your local Maven repo:

./gradlew :ReactAndroid:installArchives

Running the examples

To run the UIExplorer app:

cd react-native
./gradlew :Examples:UIExplorer:android:app:installDebug
# Start the packager in a separate shell:
# Make sure you ran npm install
./packager/packager.sh
# Open UIExplorer in your emulator, Menu button -> Reload JS should work

You can run any other sample app the same way, e.g.:

./gradlew :Examples:Movies:android:app:installDebug

Building from Android Studio

You'll need to do one additional step until we release the React Native Gradle plugin to Maven central. This is because Android Studio has its own local Maven repo:

mkdir -p /Applications/Android\ Studio.app/Contents/gradle/m2repository/com/facebook/react
cp -r ~/.m2/repository/com/facebook/react/gradleplugin /Applications/Android\ Studio.app/Contents/gradle/m2repository/com/facebook/react/

Now, open Android Studio, click Import Non-Android Studio project and find your react-native repo.

In the configurations dropdown, app should be selected. Click Run.

Installing the React Native .aar in your local Maven repo

In some cases, for example when working on the react-native-cli it's useful to publish a snapshot version of React Native into your local Maven repo. This way, Gradle can pick it up when building projects that have a Maven dependency on React Native.

Run:

cd react-native-android
./gradlew :ReactAndroid:installArchives

Troubleshooting

Gradle build fails in ndk-build. See the section about local.properties file above.

Gradle build fails "Could not find any version that matches com.facebook.react:gradleplugin:...". See the section about the React Native Gradle plugin above.

Packager throws an error saying a module is not found. Try running npm install in the root of the repo.