diff --git a/Examples/UIExplorer/GeolocationExample.js b/Examples/UIExplorer/GeolocationExample.js
index 9bd744678..d9dd4e842 100644
--- a/Examples/UIExplorer/GeolocationExample.js
+++ b/Examples/UIExplorer/GeolocationExample.js
@@ -50,8 +50,8 @@ var GeolocationExample = React.createClass({
componentDidMount: function() {
navigator.geolocation.getCurrentPosition(
(initialPosition) => this.setState({initialPosition}),
- (error) => console.error(error),
- {enableHighAccuracy: true, timeout: 100, maximumAge: 1000}
+ (error) => alert(error.message),
+ {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
);
this.watchID = navigator.geolocation.watchPosition((lastPosition) => {
this.setState({lastPosition});
diff --git a/Examples/UIExplorer/PanResponderExample.js b/Examples/UIExplorer/PanResponderExample.js
index 05ba27cd2..649ea21cb 100644
--- a/Examples/UIExplorer/PanResponderExample.js
+++ b/Examples/UIExplorer/PanResponderExample.js
@@ -27,7 +27,7 @@ var CIRCLE_COLOR = 'blue';
var CIRCLE_HIGHLIGHT_COLOR = 'green';
-var NavigatorIOSExample = React.createClass({
+var PanResponderExample = React.createClass({
statics: {
title: 'PanResponder Sample',
@@ -133,4 +133,4 @@ var styles = StyleSheet.create({
},
});
-module.exports = NavigatorIOSExample;
+module.exports = PanResponderExample;
diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
index 101bae6f9..1976634a6 100644
--- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
+++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
@@ -30,6 +30,7 @@
1497CFB21B21F5E400C1F8F2 /* RCTSparseArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFAA1B21F5E400C1F8F2 /* RCTSparseArrayTests.m */; };
1497CFB31B21F5E400C1F8F2 /* RCTUIManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFAB1B21F5E400C1F8F2 /* RCTUIManagerTests.m */; };
14AADF051AC3DBB1002390C9 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14AADF041AC3DB95002390C9 /* libReact.a */; };
+ 14B6DA821B276C5900BF4DD1 /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58005BEE1ABA80530062E044 /* libRCTTest.a */; };
14D6D7111B220EB3001FB087 /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14D6D7101B220EB3001FB087 /* libOCMock.a */; };
14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 147CED4B1AB34F8C00DA3E4C /* libRCTActionSheet.a */; };
14D6D71F1B2222EF001FB087 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1344545A1AAFCAAE003F0779 /* libRCTAdSupport.a */; };
@@ -44,7 +45,6 @@
14D6D7281B2222EF001FB087 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */; };
14D6D7291B2222EF001FB087 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14AADF041AC3DB95002390C9 /* libReact.a */; };
14DC67F41AB71881001358AB /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14DC67F11AB71876001358AB /* libRCTPushNotification.a */; };
- 58005BF21ABA80A60062E044 /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58005BEE1ABA80530062E044 /* libRCTTest.a */; };
834C36EC1AF8DED70019C93C /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 834C36D21AF8DA610019C93C /* libRCTSettings.a */; };
D85B829E1AB6D5D7003F4FE2 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D85B829C1AB6D5CE003F4FE2 /* libRCTVibration.a */; };
/* End PBXBuildFile section */
@@ -229,7 +229,6 @@
1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */,
14DC67F41AB71881001358AB /* libRCTPushNotification.a in Frameworks */,
834C36EC1AF8DED70019C93C /* libRCTSettings.a in Frameworks */,
- 58005BF21ABA80A60062E044 /* libRCTTest.a in Frameworks */,
134180011AA9153C003F314A /* libRCTText.a in Frameworks */,
D85B829E1AB6D5D7003F4FE2 /* libRCTVibration.a in Frameworks */,
139FDEDB1B0651FB00C62182 /* libRCTWebSocket.a in Frameworks */,
@@ -240,6 +239,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 14B6DA821B276C5900BF4DD1 /* libRCTTest.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -865,7 +865,7 @@
"$(SRCROOT)/../../React/**",
);
INFOPLIST_FILE = "$(SRCROOT)/UIExplorer/Info.plist";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = UIExplorer;
@@ -883,7 +883,7 @@
"$(SRCROOT)/../../React/**",
);
INFOPLIST_FILE = "$(SRCROOT)/UIExplorer/Info.plist";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited)";
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = UIExplorer;
@@ -907,6 +907,12 @@
INFOPLIST_FILE = UIExplorerIntegrationTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-framework",
+ XCTest,
+ "-ObjC",
+ );
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UIExplorer.app/UIExplorer";
};
@@ -926,6 +932,12 @@
INFOPLIST_FILE = UIExplorerIntegrationTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-framework",
+ XCTest,
+ "-ObjC",
+ );
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UIExplorer.app/UIExplorer";
};
diff --git a/Libraries/ART/ART.xcodeproj/project.pbxproj b/Libraries/ART/ART.xcodeproj/project.pbxproj
index c3255c965..70371e318 100644
--- a/Libraries/ART/ART.xcodeproj/project.pbxproj
+++ b/Libraries/ART/ART.xcodeproj/project.pbxproj
@@ -280,7 +280,7 @@
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
);
- IPHONEOS_DEPLOYMENT_TARGET = 8.2;
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -319,7 +319,7 @@
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
);
- IPHONEOS_DEPLOYMENT_TARGET = 8.2;
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
diff --git a/Libraries/CustomComponents/Navigator/Navigator.js b/Libraries/CustomComponents/Navigator/Navigator.js
index 4852e0a47..af10348fc 100644
--- a/Libraries/CustomComponents/Navigator/Navigator.js
+++ b/Libraries/CustomComponents/Navigator/Navigator.js
@@ -28,14 +28,11 @@
'use strict';
var AnimationsDebugModule = require('NativeModules').AnimationsDebugModule;
-var BackAndroid = require('BackAndroid');
var Dimensions = require('Dimensions');
var InteractionMixin = require('InteractionMixin');
var NavigatorBreadcrumbNavigationBar = require('NavigatorBreadcrumbNavigationBar');
-var NavigatorInterceptor = require('NavigatorInterceptor');
var NavigatorNavigationBar = require('NavigatorNavigationBar');
var NavigatorSceneConfigs = require('NavigatorSceneConfigs');
-var NavigatorStaticContextContainer = require('NavigatorStaticContextContainer');
var PanResponder = require('PanResponder');
var Platform = require('Platform');
var React = require('React');
@@ -47,7 +44,6 @@ var View = require('View');
var clamp = require('clamp');
var flattenStyle = require('flattenStyle');
-var getNavigatorContext = require('getNavigatorContext');
var invariant = require('invariant');
var rebound = require('rebound');
@@ -165,40 +161,6 @@ var GESTURE_ACTIONS = [
* - `popToTop()` - Pop to the first scene in the stack, unmounting every
* other scene
*
- * ### Navigation Context
- *
- * The navigator context object is made available to scenes through the
- * `renderScene` function. Alternatively, any scene or component inside a
- * Navigator can get the navigation context by calling
- * `Navigator.getContext(this)`.
- *
- * Unlike the Navigator methods, the functions in navigation context do not
- * directly control a specific navigator. Instead, the navigator context allows
- * a scene to request navigation from its parents. Navigation requests will
- * travel up through the hierarchy of Navigators, and will be resolved by the
- * deepest active navigator.
- *
- * Navigation context objects contain the following:
- *
- * - `getCurrentRoutes()` - returns the routes for the closest navigator
- * - `jumpBack()` - Jump backward without unmounting the current scene
- * - `jumpForward()` - Jump forward to the next scene in the route stack
- * - `jumpTo(route)` - Transition to an existing scene without unmounting
- * - `parentNavigator` - a refrence to the parent navigation context
- * - `push(route)` - Navigate forward to a new scene, squashing any scenes
- * that you could `jumpForward` to
- * - `pop()` - Transition back and unmount the current scene
- * - `replace(route)` - Replace the current scene with a new route
- * - `replaceAtIndex(route, index)` - Replace a scene as specified by an index
- * - `replacePrevious(route)` - Replace the previous scene
- * - `route` - The route that was used to render the scene with this context
- * - `immediatelyResetRouteStack(routeStack)` - Reset every scene with an
- * array of routes
- * - `popToRoute(route)` - Pop to a particular scene, as specified by it's
- * route. All scenes after it will be unmounted
- * - `popToTop()` - Pop to the first scene in the stack, unmounting every
- * other scene
- *
*/
var Navigator = React.createClass({
@@ -273,17 +235,10 @@ var Navigator = React.createClass({
sceneStyle: View.propTypes.style,
},
- contextTypes: {
- // TODO (t6707746) Re-enable this when owner context switches to parent context
- // navigator: PropTypes.object,
- },
-
statics: {
BreadcrumbNavigationBar: NavigatorBreadcrumbNavigationBar,
NavigationBar: NavigatorNavigationBar,
SceneConfigs: NavigatorSceneConfigs,
- Interceptor: NavigatorInterceptor,
- getContext: getNavigatorContext,
},
mixins: [TimerMixin, InteractionMixin, Subscribable.Mixin],
@@ -328,34 +283,8 @@ var Navigator = React.createClass({
},
componentWillMount: function() {
- this.parentNavigator = getNavigatorContext(this) || this.props.navigator;
this._subRouteFocus = [];
- this.navigatorContext = {
- // Actions for child navigators or interceptors:
- setHandlerForIndex: this.setHandlerForIndex,
- request: this.request,
-
- // Contextual utilities
- parentNavigator: this.parentNavigator,
- getCurrentRoutes: this.getCurrentRoutes,
- // `route` is injected by NavigatorStaticContextContainer
-
- // Contextual nav action
- pop: this.requestPop,
-
- jumpBack: this.jumpBack,
- jumpForward: this.jumpForward,
- jumpTo: this.jumpTo,
- popToRoute: this.popToRoute,
- push: this.push,
- replace: this.replace,
- replaceAtIndex: this.replaceAtIndex,
- replacePrevious: this.replacePrevious,
- replacePreviousAndPop: this.replacePreviousAndPop,
- immediatelyResetRouteStack: this.immediatelyResetRouteStack,
- resetTo: this.resetTo,
- popToTop: this.popToTop,
- };
+ this.parentNavigator = this.props.navigator;
this._handlers = {};
this.springSystem = new rebound.SpringSystem();
this.spring = this.springSystem.createSpring();
@@ -386,91 +315,13 @@ var Navigator = React.createClass({
this._emitWillFocus(this.state.routeStack[this.state.presentedIndex]);
},
- request: function(action, arg1, arg2) {
- if (this.parentNavigator) {
- return this.parentNavigator.request.apply(null, arguments);
- }
- return this._handleRequest.apply(null, arguments);
- },
-
- requestPop: function(popToBeforeRoute) {
- return this.request('pop', popToBeforeRoute);
- },
-
- requestPopTo: function(route) {
- return this.request('popTo', route);
- },
-
- _handleRequest: function(action, arg1, arg2) {
- var childHandler = this._handlers[this.state.presentedIndex];
- if (childHandler && childHandler(action, arg1, arg2)) {
- return true;
- }
- switch (action) {
- case 'pop':
- return this._handlePop(arg1);
- case 'push':
- return this._handlePush(arg1);
- default:
- invariant(false, 'Unsupported request type ' + action);
- return false;
- }
- },
-
- _handlePop: function(popToBeforeRoute) {
- if (popToBeforeRoute) {
- var popToBeforeRouteIndex = this.state.routeStack.indexOf(popToBeforeRoute);
- if (popToBeforeRouteIndex === -1) {
- return false;
- }
- invariant(
- popToBeforeRouteIndex <= this.state.presentedIndex,
- 'Cannot pop past a route that is forward in the navigator'
- );
- this._popN(this.state.presentedIndex - popToBeforeRouteIndex + 1);
- return true;
- }
- if (this.state.presentedIndex === 0) {
- return false;
- }
- this.pop();
- return true;
- },
-
- _handlePush: function(route) {
- this.push(route);
- return true;
- },
-
- setHandlerForIndex: function(index, handler) {
- this._handlers[index] = handler;
- },
-
componentDidMount: function() {
this._handleSpringUpdate();
this._emitDidFocus(this.state.routeStack[this.state.presentedIndex]);
- if (this.parentNavigator) {
- this.parentNavigator.setHandler(this._handleRequest);
- } else if (Platform.OS === 'android') {
- // There is no navigator in our props or context, so this is the
- // top-level navigator. We will handle back button presses here
- BackAndroid.addEventListener('hardwareBackPress', this._handleAndroidBackPress);
- }
},
componentWillUnmount: function() {
- if (this.parentNavigator) {
- this.parentNavigator.setHandler(null);
- } else if (Platform.OS === 'android') {
- BackAndroid.removeEventListener('hardwareBackPress', this._handleAndroidBackPress);
- }
- },
- _handleAndroidBackPress: function() {
- var didPop = this.requestPop();
- if (!didPop) {
- BackAndroid.exitApp();
- }
},
/**
@@ -532,8 +383,7 @@ var Navigator = React.createClass({
this.spring.getSpringConfig().tension = sceneConfig.springTension;
this.spring.setVelocity(velocity || sceneConfig.defaultTransitionVelocity);
this.spring.setEndValue(1);
- var willFocusRoute = this._subRouteFocus[this.state.presentedIndex] || this.state.routeStack[this.state.presentedIndex];
- this._emitWillFocus(willFocusRoute);
+ this._emitWillFocus(this.state.routeStack[this.state.presentedIndex]);
},
/**
@@ -611,23 +461,12 @@ var Navigator = React.createClass({
},
_emitDidFocus: function(route) {
- if (this._lastDidFocus === route) {
- return;
- }
- this._lastDidFocus = route;
if (this.props.onDidFocus) {
this.props.onDidFocus(route);
}
- if (this.parentNavigator && this.parentNavigator.onDidFocus) {
- this.parentNavigator.onDidFocus(route);
- }
},
_emitWillFocus: function(route) {
- if (this._lastWillFocus === route) {
- return;
- }
- this._lastWillFocus = route;
var navBar = this._navBar;
if (navBar && navBar.handleWillFocus) {
navBar.handleWillFocus(route);
@@ -635,9 +474,6 @@ var Navigator = React.createClass({
if (this.props.onWillFocus) {
this.props.onWillFocus(route);
}
- if (this.parentNavigator && this.parentNavigator.onWillFocus) {
- this.parentNavigator.onWillFocus(route);
- }
},
/**
@@ -1237,41 +1073,20 @@ var Navigator = React.createClass({
var shouldRenderScene =
i >= this.state.updatingRangeStart &&
i <= this.state.updatingRangeStart + this.state.updatingRangeLength;
- var sceneNavigatorContext = {
- ...this.navigatorContext,
- route,
- setHandler: (handler) => {
- this.navigatorContext.setHandlerForIndex(i, handler);
- },
- onWillFocus: (childRoute) => {
- this._subRouteFocus[i] = childRoute;
- if (this.state.presentedIndex === i) {
- this._emitWillFocus(childRoute);
- }
- },
- onDidFocus: (childRoute) => {
- this._subRouteFocus[i] = childRoute;
- if (this.state.presentedIndex === i) {
- this._emitDidFocus(childRoute);
- }
- },
- };
- var scene = shouldRenderScene ?
- this._renderScene(route, i, sceneNavigatorContext) : null;
+ var scene = shouldRenderScene ? this._renderScene(route, i) : null;
return (
-
{scene}
-
+
);
},
- _renderScene: function(route, i, sceneNavigatorContext) {
+ _renderScene: function(route, i) {
var child = this.props.renderScene(
route,
- sceneNavigatorContext
+ this
);
var disabledSceneStyle = null;
if (i !== this.state.presentedIndex) {
@@ -1311,7 +1126,7 @@ var Navigator = React.createClass({
}
return React.cloneElement(this.props.navigationBar, {
ref: (navBar) => { this._navBar = navBar; },
- navigator: this.navigatorContext,
+ navigator: this,
navState: this.state,
});
},
diff --git a/Libraries/CustomComponents/Navigator/NavigatorInterceptor.js b/Libraries/CustomComponents/Navigator/NavigatorInterceptor.js
deleted file mode 100644
index efff4c9dc..000000000
--- a/Libraries/CustomComponents/Navigator/NavigatorInterceptor.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * Copyright (c) 2015, Facebook, Inc. All rights reserved.
- *
- * Facebook, Inc. (“Facebook”) owns all right, title and interest, including
- * all intellectual property and other proprietary rights, in and to the React
- * Native CustomComponents software (the “Software”). Subject to your
- * compliance with these terms, you are hereby granted a non-exclusive,
- * worldwide, royalty-free copyright license to (1) use and copy the Software;
- * and (2) reproduce and distribute the Software as part of your own software
- * (“Your Software”). Facebook reserves all rights not expressly granted to
- * you in this license agreement.
- *
- * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
- * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
- * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
- * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @providesModule NavigatorInterceptor
- */
-'use strict';
-
-var React = require('React');
-
-var getNavigatorContext = require('getNavigatorContext');
-
-var NavigatorInterceptor = React.createClass({
-
- contextTypes: {
- navigator: React.PropTypes.object,
- },
-
- componentWillMount: function() {
- this.navigator = getNavigatorContext(this);
- },
-
- componentDidMount: function() {
- this.navigator.setHandler(this._navigatorHandleRequest);
- },
-
- childContextTypes: {
- navigator: React.PropTypes.object,
- },
-
- getChildContext: function() {
- return {
- navigator: {
- ...this.navigator,
- setHandler: (handler) => {
- this._childNavigationHandler = handler;
- },
- }
- };
- },
-
- componentWillUnmount: function() {
- this.navigator.setHandler(null);
- },
-
- _navigatorHandleRequest: function(action, arg1, arg2) {
- if (this._interceptorHandle(action, arg1, arg2)) {
- return true;
- }
- if (this._childNavigationHandler && this._childNavigationHandler(action, arg1, arg2)) {
- return true;
- }
- },
-
- _interceptorHandle: function(action, arg1, arg2) {
- if (this.props.onRequest && this.props.onRequest(action, arg1, arg2)) {
- return true;
- }
- switch (action) {
- case 'pop':
- return this.props.onPopRequest && this.props.onPopRequest(arg1, arg2);
- case 'popTo':
- return this.props.onPopToRequest && this.props.onPopToRequest(arg1, arg2);
- case 'push':
- return this.props.onPushRequest && this.props.onPushRequest(arg1, arg2);
- default:
- return false;
- }
- },
-
- render: function() {
- return this.props.children;
- },
-
-});
-
-module.exports = NavigatorInterceptor;
diff --git a/Libraries/CustomComponents/Navigator/NavigatorStaticContextContainer.js b/Libraries/CustomComponents/Navigator/NavigatorStaticContextContainer.js
deleted file mode 100644
index ded8048e4..000000000
--- a/Libraries/CustomComponents/Navigator/NavigatorStaticContextContainer.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Copyright (c) 2015, Facebook, Inc. All rights reserved.
- *
- * Facebook, Inc. (“Facebook”) owns all right, title and interest, including
- * all intellectual property and other proprietary rights, in and to the React
- * Native CustomComponents software (the “Software”). Subject to your
- * compliance with these terms, you are hereby granted a non-exclusive,
- * worldwide, royalty-free copyright license to (1) use and copy the Software;
- * and (2) reproduce and distribute the Software as part of your own software
- * (“Your Software”). Facebook reserves all rights not expressly granted to
- * you in this license agreement.
- *
- * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
- * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
- * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
- * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @providesModule NavigatorStaticContextContainer
- */
-'use strict';
-
-var React = require('React');
-var StaticContainer = require('StaticContainer.react');
-
-var PropTypes = React.PropTypes;
-
-var NavigatorStaticContextContainer = React.createClass({
-
- childContextTypes: {
- navigator: PropTypes.object,
- },
-
- getChildContext: function() {
- return {
- navigator: this.props.navigatorContext,
- };
- },
-
- render: function() {
- return (
-
- );
- },
-});
-
-module.exports = NavigatorStaticContextContainer;
diff --git a/Libraries/CustomComponents/Navigator/getNavigatorContext.js b/Libraries/CustomComponents/Navigator/getNavigatorContext.js
deleted file mode 100644
index 0c169fe0f..000000000
--- a/Libraries/CustomComponents/Navigator/getNavigatorContext.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Copyright (c) 2015, Facebook, Inc. All rights reserved.
- *
- * Facebook, Inc. (“Facebook”) owns all right, title and interest, including
- * all intellectual property and other proprietary rights, in and to the React
- * Native CustomComponents software (the “Software”). Subject to your
- * compliance with these terms, you are hereby granted a non-exclusive,
- * worldwide, royalty-free copyright license to (1) use and copy the Software;
- * and (2) reproduce and distribute the Software as part of your own software
- * (“Your Software”). Facebook reserves all rights not expressly granted to
- * you in this license agreement.
- *
- * THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
- * OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
- * IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
- * EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * @providesModule getNavigatorContext
- */
-'use strict';
-
-
-var ReactInstanceMap = require('ReactInstanceMap');
-
-function getNavigatorContext(el) {
- // TODO (t6707746): replace with `el.context.navigator` when parent context is supported
- return ReactInstanceMap.get(el)._context.navigator;
-}
-
-module.exports = getNavigatorContext;
diff --git a/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj b/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj
index a9a8f3f42..89fcdffb1 100644
--- a/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj
+++ b/Libraries/LinkingIOS/RCTLinking.xcodeproj/project.pbxproj
@@ -152,7 +152,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -186,7 +186,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
diff --git a/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj/project.pbxproj b/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj/project.pbxproj
index 8bca741b4..1585e6c42 100644
--- a/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj/project.pbxproj
+++ b/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj/project.pbxproj
@@ -151,7 +151,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -186,7 +186,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
diff --git a/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj b/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj
index e4a210466..9cbc4e4dd 100644
--- a/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj
+++ b/Libraries/Settings/RCTSettings.xcodeproj/project.pbxproj
@@ -152,7 +152,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -186,7 +186,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
diff --git a/React/Base/RCTBridge.h b/React/Base/RCTBridge.h
index 5f84ed9da..5c5cfe49b 100644
--- a/React/Base/RCTBridge.h
+++ b/React/Base/RCTBridge.h
@@ -21,17 +21,17 @@
/**
* This notification triggers a reload of all bridges currently running.
*/
-extern NSString *const RCTReloadNotification;
+RCT_EXTERN NSString *const RCTReloadNotification;
/**
* This notification fires when the bridge has finished loading.
*/
-extern NSString *const RCTJavaScriptDidLoadNotification;
+RCT_EXTERN NSString *const RCTJavaScriptDidLoadNotification;
/**
* This notification fires when the bridge failed to load.
*/
-extern NSString *const RCTJavaScriptDidFailToLoadNotification;
+RCT_EXTERN NSString *const RCTJavaScriptDidFailToLoadNotification;
/**
* This block can be used to instantiate modules that require additional
@@ -43,6 +43,13 @@ extern NSString *const RCTJavaScriptDidFailToLoadNotification;
*/
typedef NSArray *(^RCTBridgeModuleProviderBlock)(void);
+/**
+ * Register the given class as a bridge module. All modules must be registered
+ * prior to the first bridge initialization.
+ *
+ */
+RCT_EXTERN void RCTRegisterModule(Class);
+
/**
* This function returns the module name for a given class.
*/
diff --git a/React/Base/RCTBridge.m b/React/Base/RCTBridge.m
index 841d7c0b1..998fb7bca 100644
--- a/React/Base/RCTBridge.m
+++ b/React/Base/RCTBridge.m
@@ -70,6 +70,30 @@ typedef struct section RCTHeaderSection;
NSString *const RCTEnqueueNotification = @"RCTEnqueueNotification";
NSString *const RCTDequeueNotification = @"RCTDequeueNotification";
+static NSDictionary *RCTModuleIDsByName;
+static NSArray *RCTModuleNamesByID;
+static NSArray *RCTModuleClassesByID;
+void RCTRegisterModule(Class moduleClass)
+{
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ RCTModuleIDsByName = [[NSMutableDictionary alloc] init];
+ RCTModuleNamesByID = [[NSMutableArray alloc] init];
+ RCTModuleClassesByID = [[NSMutableArray alloc] init];
+ });
+
+ RCTAssert([moduleClass conformsToProtocol:@protocol(RCTBridgeModule)],
+ @"%@ does not conform to the RCTBridgeModule protocol",
+ NSStringFromClass(moduleClass));
+
+ // Register module
+ NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);
+ ((NSMutableDictionary *)RCTModuleIDsByName)[moduleName] = @(RCTModuleNamesByID.count);
+ [(NSMutableArray *)RCTModuleNamesByID addObject:moduleName];
+ [(NSMutableArray *)RCTModuleClassesByID addObject:moduleClass];
+
+}
+
/**
* This function returns the module name for a given class.
*/
@@ -122,93 +146,6 @@ static NSArray *RCTJSMethods(void)
return JSMethods;
}
-/**
- * This function scans all exported modules available at runtime and returns an
- * array. As a backup, it also scans all classes that implement the
- * RTCBridgeModule protocol to ensure they've been exported. This scanning
- * functionality is disabled in release mode to improve startup performance.
- */
-static NSDictionary *RCTModuleIDsByName;
-static NSArray *RCTModuleNamesByID;
-static NSArray *RCTModuleClassesByID;
-static NSArray *RCTBridgeModuleClassesByModuleID(void)
-{
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
-
- RCTModuleIDsByName = [[NSMutableDictionary alloc] init];
- RCTModuleNamesByID = [[NSMutableArray alloc] init];
- RCTModuleClassesByID = [[NSMutableArray alloc] init];
-
- Dl_info info;
- dladdr(&RCTBridgeModuleClassesByModuleID, &info);
-
- const RCTHeaderValue mach_header = (RCTHeaderValue)info.dli_fbase;
- unsigned long size;
- const uint8_t *sectionData = getsectiondata(mach_header, "__DATA", "RCTExportModule", &size);
- if (sectionData) {
- for (const uint8_t *addr = sectionData;
- addr < sectionData + size;
- addr += sizeof(const char **)) {
-
- // Get data entry
- NSString *entry = @(*(const char **)addr);
- NSArray *parts = [[entry substringWithRange:(NSRange){2, entry.length - 3}]
- componentsSeparatedByString:@" "];
-
- // Parse class name
- NSString *moduleClassName = parts[0];
- NSRange categoryRange = [moduleClassName rangeOfString:@"("];
- if (categoryRange.length) {
- moduleClassName = [moduleClassName substringToIndex:categoryRange.location];
- }
-
- // Get class
- Class cls = NSClassFromString(moduleClassName);
- RCTAssert([cls conformsToProtocol:@protocol(RCTBridgeModule)],
- @"%@ does not conform to the RCTBridgeModule protocol",
- NSStringFromClass(cls));
-
- // Register module
- NSString *moduleName = RCTBridgeModuleNameForClass(cls);
- ((NSMutableDictionary *)RCTModuleIDsByName)[moduleName] = @(RCTModuleNamesByID.count);
- [(NSMutableArray *)RCTModuleNamesByID addObject:moduleName];
- [(NSMutableArray *)RCTModuleClassesByID addObject:cls];
- }
- }
-
- if (RCT_DEBUG) {
-
- // We may be able to get rid of this check in future, once people
- // get used to the new registration system. That would potentially
- // allow you to create modules that are not automatically registered
-
- static unsigned int classCount;
- Class *classes = objc_copyClassList(&classCount);
- for (unsigned int i = 0; i < classCount; i++)
- {
- Class cls = classes[i];
- Class superclass = cls;
- while (superclass)
- {
- if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule)))
- {
- if (![RCTModuleClassesByID containsObject:cls]) {
- RCTLogError(@"Class %@ was not exported. Did you forget to use RCT_EXPORT_MODULE()?", NSStringFromClass(cls));
- }
- break;
- }
- superclass = class_getSuperclass(superclass);
- }
- }
- free(classes);
- }
-
- });
-
- return RCTModuleClassesByID;
-}
-
// TODO: Can we just replace RCTMakeError with this function instead?
static NSDictionary *RCTJSErrorFromNSError(NSError *error)
{
@@ -278,25 +215,42 @@ static NSDictionary *RCTJSErrorFromNSError(NSError *error)
dispatch_block_t _methodQueue;
}
-- (instancetype)initWithReactMethodName:(NSString *)reactMethodName
- objCMethodName:(NSString *)objCMethodName
- JSMethodName:(NSString *)JSMethodName
+- (instancetype)initWithObjCMethodName:(NSString *)objCMethodName
+ JSMethodName:(NSString *)JSMethodName
+ moduleClass:(Class)moduleClass
{
if ((self = [super init])) {
+ static NSRegularExpression *typeRegex;
+ static NSRegularExpression *selectorRegex;
+ if (!typeRegex) {
+ NSString *unusedPattern = @"(?:(?:__unused|__attribute__\\(\\(unused\\)\\)))";
+ NSString *constPattern = @"(?:const)";
+ NSString *constUnusedPattern = [NSString stringWithFormat:@"(?:(?:%@|%@)\\s*)", unusedPattern, constPattern];
+ NSString *pattern = [NSString stringWithFormat:@"\\(%1$@?(\\w+?)(?:\\s*\\*)?%1$@?\\)", constUnusedPattern];
+ typeRegex = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:NULL];
- NSArray *parts = [[reactMethodName substringWithRange:(NSRange){2, reactMethodName.length - 3}] componentsSeparatedByString:@" "];
-
- // Parse class and method
- _moduleClassName = parts[0];
- NSRange categoryRange = [_moduleClassName rangeOfString:@"("];
- if (categoryRange.length) {
- _moduleClassName = [_moduleClassName substringToIndex:categoryRange.location];
+ selectorRegex = [[NSRegularExpression alloc] initWithPattern:@"(?<=:).*?(?=[a-zA-Z_]+:|$)" options:0 error:NULL];
}
- NSString *selectorString = [parts[1] substringFromIndex:14];
- _selector = NSSelectorFromString(selectorString);
- _JSMethodName = JSMethodName ?: ({
- NSString *methodName = selectorString;
+ NSMutableArray *argumentNames = [NSMutableArray array];
+ [typeRegex enumerateMatchesInString:objCMethodName options:0 range:NSMakeRange(0, objCMethodName.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
+ NSString *argumentName = [objCMethodName substringWithRange:[result rangeAtIndex:1]];
+ [argumentNames addObject:argumentName];
+ }];
+
+ // Remove the parameters' type and name
+ objCMethodName = [selectorRegex stringByReplacingMatchesInString:objCMethodName
+ options:0
+ range:NSMakeRange(0, objCMethodName.length)
+ withTemplate:@""];
+ // Remove any spaces since `selector : (Type)name` is a valid syntax
+ objCMethodName = [objCMethodName stringByReplacingOccurrencesOfString:@" " withString:@""];
+
+ _moduleClass = moduleClass;
+ _moduleClassName = NSStringFromClass(_moduleClass);
+ _selector = NSSelectorFromString(objCMethodName);
+ _JSMethodName = JSMethodName.length > 0 ? JSMethodName : ({
+ NSString *methodName = NSStringFromSelector(_selector);
NSRange colonRange = [methodName rangeOfString:@":"];
if (colonRange.length) {
methodName = [methodName substringToIndex:colonRange.location];
@@ -304,31 +258,6 @@ static NSDictionary *RCTJSErrorFromNSError(NSError *error)
methodName;
});
- static NSRegularExpression *regExp;
- if (!regExp) {
- NSString *unusedPattern = @"(?:(?:__unused|__attribute__\\(\\(unused\\)\\)))";
- NSString *constPattern = @"(?:const)";
- NSString *constUnusedPattern = [NSString stringWithFormat:@"(?:(?:%@|%@)\\s*)", unusedPattern, constPattern];
- NSString *pattern = [NSString stringWithFormat:@"\\(%1$@?(\\w+?)(?:\\s*\\*)?%1$@?\\)", constUnusedPattern];
- regExp = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:NULL];
- }
-
- NSMutableArray *argumentNames = [NSMutableArray array];
- [regExp enumerateMatchesInString:objCMethodName options:0 range:NSMakeRange(0, objCMethodName.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
- NSString *argumentName = [objCMethodName substringWithRange:[result rangeAtIndex:1]];
- [argumentNames addObject:argumentName];
- }];
-
- // Extract class and method details
- _moduleClass = NSClassFromString(_moduleClassName);
-
- if (RCT_DEBUG) {
-
- // Sanity check
- RCTAssert([_moduleClass conformsToProtocol:@protocol(RCTBridgeModule)],
- @"You are attempting to export the method %@, but %@ does not \
- conform to the RCTBridgeModule Protocol", objCMethodName, _moduleClassName);
- }
// Get method signature
_methodSignature = [_moduleClass instanceMethodSignatureForSelector:_selector];
@@ -554,44 +483,33 @@ static RCTSparseArray *RCTExportedMethodsByModuleID(void)
static RCTSparseArray *methodsByModuleID;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
+ methodsByModuleID = [[RCTSparseArray alloc] initWithCapacity:[RCTModuleClassesByID count]];
- Dl_info info;
- dladdr(&RCTExportedMethodsByModuleID, &info);
+ [RCTModuleClassesByID enumerateObjectsUsingBlock:^(Class moduleClass, NSUInteger moduleID, BOOL *stop) {
- const RCTHeaderValue mach_header = (RCTHeaderValue)info.dli_fbase;
+ methodsByModuleID[moduleID] = [[NSMutableArray alloc] init];
- unsigned long size;
- const uint8_t *sectionData = getsectiondata(mach_header, "__DATA", "RCTExport", &size);
+ unsigned int methodCount;
+ Method *methods = class_copyMethodList(object_getClass(moduleClass), &methodCount);
- if (sectionData == NULL) {
- return;
- }
+ for (unsigned int i = 0; i < methodCount; i++) {
+ Method method = methods[i];
+ SEL selector = method_getName(method);
+ if ([NSStringFromSelector(selector) hasPrefix:@"__rct_export__"]) {
+ NSArray *entries = ((NSArray *(*)(id, SEL))objc_msgSend)(moduleClass, selector);
+ RCTModuleMethod *moduleMethod =
+ [[RCTModuleMethod alloc] initWithObjCMethodName:entries[1]
+ JSMethodName:entries[0]
+ moduleClass:moduleClass];
- NSArray *classes = RCTBridgeModuleClassesByModuleID();
- NSMutableDictionary *methodsByModuleClassName = [NSMutableDictionary dictionaryWithCapacity:[classes count]];
+ [methodsByModuleID[moduleID] addObject:moduleMethod];
+ }
+ }
- for (const uint8_t *addr = sectionData;
- addr < sectionData + size;
- addr += sizeof(const char **) * 3) {
+ free(methods);
- // Get data entry
- const char **entries = (const char **) addr;
-
- // Create method
- RCTModuleMethod *moduleMethod =
- [[RCTModuleMethod alloc] initWithReactMethodName:@(entries[0])
- objCMethodName:@(entries[1])
- JSMethodName:strlen(entries[2]) ? @(entries[2]) : nil];
- // Cache method
- NSArray *methods = methodsByModuleClassName[moduleMethod.moduleClassName];
- methodsByModuleClassName[moduleMethod.moduleClassName] =
- methods ? [methods arrayByAddingObject:moduleMethod] : @[moduleMethod];
- }
-
- methodsByModuleID = [[RCTSparseArray alloc] initWithCapacity:[classes count]];
- [classes enumerateObjectsUsingBlock:^(Class moduleClass, NSUInteger moduleID, BOOL *stop) {
- methodsByModuleID[moduleID] = methodsByModuleClassName[NSStringFromClass(moduleClass)];
}];
+
});
return methodsByModuleID;
@@ -630,7 +548,7 @@ static NSDictionary *RCTRemoteModulesConfig(NSDictionary *modulesByName)
dispatch_once(&onceToken, ^{
remoteModuleConfigByClassName = [[NSMutableDictionary alloc] init];
- [RCTBridgeModuleClassesByModuleID() enumerateObjectsUsingBlock:^(Class moduleClass, NSUInteger moduleID, BOOL *stop) {
+ [RCTModuleClassesByID enumerateObjectsUsingBlock:^(Class moduleClass, NSUInteger moduleID, BOOL *stop) {
NSArray *methods = RCTExportedMethodsByModuleID()[moduleID];
NSMutableDictionary *methodsByName = [NSMutableDictionary dictionaryWithCapacity:methods.count];
@@ -768,6 +686,38 @@ static NSDictionary *RCTLocalModulesConfig()
static id _latestJSExecutor;
+#if RCT_DEBUG
++ (void)initialize
+{
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+
+ static unsigned int classCount;
+ Class *classes = objc_copyClassList(&classCount);
+
+ for (unsigned int i = 0; i < classCount; i++)
+ {
+ Class cls = classes[i];
+ Class superclass = cls;
+ while (superclass)
+ {
+ if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule)))
+ {
+ if (![RCTModuleClassesByID containsObject:cls]) {
+ RCTLogError(@"Class %@ was not exported. Did you forget to use RCT_EXPORT_MODULE()?", NSStringFromClass(cls));
+ }
+ break;
+ }
+ superclass = class_getSuperclass(superclass);
+ }
+ }
+
+ free(classes);
+
+ });
+}
+#endif
+
- (instancetype)initWithBundleURL:(NSURL *)bundleURL
moduleProvider:(RCTBridgeModuleProviderBlock)block
launchOptions:(NSDictionary *)launchOptions
@@ -1006,7 +956,7 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
// Instantiate modules
_modulesByID = [[RCTSparseArray alloc] init];
NSMutableDictionary *modulesByName = [preregisteredModules mutableCopy];
- [RCTBridgeModuleClassesByModuleID() enumerateObjectsUsingBlock:^(Class moduleClass, NSUInteger moduleID, BOOL *stop) {
+ [RCTModuleClassesByID enumerateObjectsUsingBlock:^(Class moduleClass, NSUInteger moduleID, BOOL *stop) {
NSString *moduleName = RCTModuleNamesByID[moduleID];
// Check if module instance has already been registered for this name
id module = modulesByName[moduleName];
diff --git a/React/Base/RCTBridgeModule.h b/React/Base/RCTBridgeModule.h
index d64e81693..fc662778c 100644
--- a/React/Base/RCTBridgeModule.h
+++ b/React/Base/RCTBridgeModule.h
@@ -9,6 +9,8 @@
#import
+#import "RCTDefines.h"
+
@class RCTBridge;
/**
@@ -62,8 +64,9 @@ extern const dispatch_queue_t RCTJSThread;
* match the Objective-C class name.
*/
#define RCT_EXPORT_MODULE(js_name) \
- + (NSString *)moduleName { __attribute__((used, section("__DATA,RCTExportModule" \
- ))) static const char *__rct_export_entry__ = { __func__ }; return @#js_name; }
+ RCT_EXTERN void RCTRegisterModule(Class); \
+ + (NSString *)moduleName { return @#js_name; } \
+ + (void)load { RCTRegisterModule([self class]); }
/**
* Wrap the parameter line of your method implementation with this macro to
@@ -173,11 +176,10 @@ extern const dispatch_queue_t RCTJSThread;
* Like RCT_EXTERN_REMAP_METHOD, but allows setting a custom JavaScript name.
*/
#define RCT_EXTERN_REMAP_METHOD(js_name, method) \
- - (void)__rct_export__##method { \
- __attribute__((used, section("__DATA,RCTExport"))) \
- __attribute__((__aligned__(1))) \
- static const char *__rct_export_entry__[] = { __func__, #method, #js_name }; \
- }
+ + (NSArray *)RCT_CONCAT(__rct_export__, __COUNTER__) { \
+ return @[@#js_name, @#method]; \
+ } \
+
/**
* The queue that will be used to call all exported methods. If omitted, this
diff --git a/React/Base/RCTDefines.h b/React/Base/RCTDefines.h
index 83a60d61a..33328789b 100644
--- a/React/Base/RCTDefines.h
+++ b/React/Base/RCTDefines.h
@@ -74,3 +74,11 @@
#define RCT_NSASSERT 0
#endif
#endif
+
+/**
+ * Concat two literals. Supports macro expansions
+ *
+ * i.e. RCT_CONCAT(foo, __FILE__)
+ */
+#define RCT_CONCAT2(A, B) A ## B
+#define RCT_CONCAT(A, B) RCT_CONCAT2(A, B)