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)