diff --git a/Examples/UIExplorer/AdSupportIOSExample.js b/Examples/UIExplorer/AdSupportIOSExample.js
new file mode 100644
index 00000000000..1da508fd946
--- /dev/null
+++ b/Examples/UIExplorer/AdSupportIOSExample.js
@@ -0,0 +1,73 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * @providesModule AdSupportIOSExample
+ */
+/* eslint no-console: 0 */
+'use strict';
+
+var AdSupportIOS = require('AdSupportIOS');
+
+var React = require('react-native');
+var {
+ StyleSheet,
+ Text,
+ View,
+} = React;
+
+exports.framework = 'React';
+exports.title = 'Advertising ID';
+exports.description = 'Example of using the ad support API.';
+
+exports.examples = [
+ {
+ title: 'Ad Support IOS',
+ render: function() {
+ return ;
+ },
+ }
+];
+
+var AdSupportIOSExample = React.createClass({
+ getInitialState: function() {
+ return {
+ deviceID: 'No IDFA yet',
+ };
+ },
+
+ componentDidMount: function() {
+ AdSupportIOS.getAdvertisingId(
+ this._onSuccess,
+ this._onFailure
+ );
+ },
+
+ _onSuccess: function(deviceID) {
+ this.setState({
+ 'deviceID': deviceID,
+ });
+ },
+
+ _onFailure: function(e) {
+ this.setState({
+ 'deviceID': 'Error!',
+ });
+ },
+
+ render: function() {
+ return (
+
+
+ Advertising ID:
+ {JSON.stringify(this.state.deviceID)}
+
+
+ );
+ }
+});
+
+var styles = StyleSheet.create({
+ title: {
+ fontWeight: 'bold',
+ },
+});
diff --git a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
index d397eea3689..05b0eaf7fd6 100644
--- a/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
+++ b/Examples/UIExplorer/UIExplorer.xcodeproj/project.pbxproj
@@ -16,6 +16,7 @@
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
+ 832C81C71AAF73C5007FA2F7 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832C81A61AAF6EFF007FA2F7 /* libRCTAdSupport.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -54,6 +55,13 @@
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RCTGeolocation;
};
+ 832C81A51AAF6EFF007FA2F7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 832C81A11AAF6EFE007FA2F7 /* RCTAdSupport.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
+ remoteInfo = RCTAdSupport;
+ };
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
@@ -69,6 +77,7 @@
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
+ 832C81A11AAF6EFE007FA2F7 /* RCTAdSupport.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAdSupport.xcodeproj; path = ../../Libraries/AdSupport/RCTAdSupport.xcodeproj; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -76,6 +85,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 832C81C71AAF73C5007FA2F7 /* libRCTAdSupport.a in Frameworks */,
134A8A2A1AACED7A00945AAE /* libRCTGeolocation.a in Frameworks */,
1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */,
134180011AA9153C003F314A /* libRCTText.a in Frameworks */,
@@ -91,10 +101,11 @@
isa = PBXGroup;
children = (
13417FFA1AA91531003F314A /* ReactKit.xcodeproj */,
- 134180261AA91779003F314A /* RCTNetwork.xcodeproj */,
+ 832C81A11AAF6EFE007FA2F7 /* RCTAdSupport.xcodeproj */,
134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */,
- 13417FEA1AA914B8003F314A /* RCTText.xcodeproj */,
13417FE31AA91428003F314A /* RCTImage.xcodeproj */,
+ 134180261AA91779003F314A /* RCTNetwork.xcodeproj */,
+ 13417FEA1AA914B8003F314A /* RCTText.xcodeproj */,
);
name = Libraries;
sourceTree = "";
@@ -152,6 +163,14 @@
name = UIExplorer;
sourceTree = "";
};
+ 832C81A21AAF6EFE007FA2F7 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 832C81A61AAF6EFF007FA2F7 /* libRCTAdSupport.a */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
@@ -210,6 +229,10 @@
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = "";
projectReferences = (
+ {
+ ProductGroup = 832C81A21AAF6EFE007FA2F7 /* Products */;
+ ProjectRef = 832C81A11AAF6EFE007FA2F7 /* RCTAdSupport.xcodeproj */;
+ },
{
ProductGroup = 134A8A211AACED6A00945AAE /* Products */;
ProjectRef = 134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */;
@@ -274,6 +297,13 @@
remoteRef = 134A8A241AACED6A00945AAE /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
+ 832C81A61AAF6EFF007FA2F7 /* libRCTAdSupport.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libRCTAdSupport.a;
+ remoteRef = 832C81A51AAF6EFF007FA2F7 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
diff --git a/Examples/UIExplorer/UIExplorerList.js b/Examples/UIExplorer/UIExplorerList.js
index ff0d71be8ff..63c98383883 100644
--- a/Examples/UIExplorer/UIExplorerList.js
+++ b/Examples/UIExplorer/UIExplorerList.js
@@ -39,6 +39,7 @@ var EXAMPLES = [
require('./SliderExample'),
require('./CameraRollExample.ios'),
require('./MapViewExample'),
+ require('./AdSupportIOSExample'),
];
var UIExplorerList = React.createClass({
diff --git a/Libraries/AdSupport/AdSupportIOS.js b/Libraries/AdSupport/AdSupportIOS.js
new file mode 100644
index 00000000000..598befd3121
--- /dev/null
+++ b/Libraries/AdSupport/AdSupportIOS.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * @providesModule AdSupportIOS
+ */
+'use strict';
+
+var AdSupport = require('NativeModules').RCTAdSupport;
+
+module.exports = {
+ getAdvertisingId: function(onSuccess, onFailure) {
+ AdSupport.getAdvertisingId(onSuccess, onFailure);
+ },
+};
diff --git a/Libraries/AdSupport/RCTAdSupport.h b/Libraries/AdSupport/RCTAdSupport.h
new file mode 100644
index 00000000000..2fbd3a8c00b
--- /dev/null
+++ b/Libraries/AdSupport/RCTAdSupport.h
@@ -0,0 +1,7 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#import "RCTBridgeModule.h"
+
+@interface RCTAdSupport : NSObject
+
+@end
diff --git a/Libraries/AdSupport/RCTAdSupport.m b/Libraries/AdSupport/RCTAdSupport.m
new file mode 100644
index 00000000000..0cff2401255
--- /dev/null
+++ b/Libraries/AdSupport/RCTAdSupport.m
@@ -0,0 +1,20 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#import "RCTAdSupport.h"
+
+#import
+
+@implementation RCTAdSupport
+
+- (void)getAdvertisingId:(RCTResponseSenderBlock)callback withErrorCallback:(RCTResponseSenderBlock)errorCallback
+{
+ RCT_EXPORT();
+
+ if ([ASIdentifierManager class]) {
+ callback(@[[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]]);
+ } else {
+ return errorCallback(@[@"as_identifier_unavailable"]);
+ }
+}
+
+@end
diff --git a/Libraries/Picker/PickerIOS.android.js b/Libraries/Picker/PickerIOS.android.js
new file mode 100644
index 00000000000..72cc87a7555
--- /dev/null
+++ b/Libraries/Picker/PickerIOS.android.js
@@ -0,0 +1,10 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * @providesModule PickerIOS
+ *
+ * This is a controlled component version of RKPickerIOS
+ */
+'use strict';
+
+module.exports = require('UnimplementedView');
diff --git a/Libraries/Picker/PickerIOS.ios.js b/Libraries/Picker/PickerIOS.ios.js
new file mode 100644
index 00000000000..04559a70009
--- /dev/null
+++ b/Libraries/Picker/PickerIOS.ios.js
@@ -0,0 +1,120 @@
+/**
+ * Copyright 2004-present Facebook. All Rights Reserved.
+ *
+ * @providesModule PickerIOS
+ *
+ * This is a controlled component version of RKPickerIOS
+ */
+'use strict';
+
+var NativeMethodsMixin = require('NativeMethodsMixin');
+var React = require('React');
+var ReactChildren = require('ReactChildren');
+var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
+var RKPickerIOSConsts = require('NativeModules').RKUIManager.RCTPicker.Constants;
+var StyleSheet = require('StyleSheet');
+var View = require('View');
+
+var createReactIOSNativeComponentClass =
+ require('createReactIOSNativeComponentClass');
+var merge = require('merge');
+
+var PICKER = 'picker';
+
+var PickerIOS = React.createClass({
+ mixins: [NativeMethodsMixin],
+
+ propTypes: {
+ onValueChange: React.PropTypes.func,
+ selectedValue: React.PropTypes.any, // string or integer basically
+ },
+
+ getInitialState: function() {
+ return this._stateFromProps(this.props);
+ },
+
+ componentWillReceiveProps: function(nextProps) {
+ this.setState(this._stateFromProps(nextProps));
+ },
+
+ // Translate PickerIOS prop and children into stuff that RKPickerIOS understands.
+ _stateFromProps: function(props) {
+ var selectedIndex = 0;
+ var items = [];
+ ReactChildren.forEach(props.children, function (child, index) {
+ if (child.props.value === props.selectedValue) {
+ selectedIndex = index;
+ }
+ items.push({value: child.props.value, label: child.props.label});
+ });
+ return {selectedIndex, items};
+ },
+
+ render: function() {
+ return (
+
+
+
+ );
+ },
+
+ _onChange: function(event) {
+ if (this.props.onChange) {
+ this.props.onChange(event);
+ }
+ if (this.props.onValueChange) {
+ this.props.onValueChange(event.nativeEvent.newValue);
+ }
+
+ // The picker is a controlled component. This means we expect the
+ // on*Change handlers to be in charge of updating our
+ // `selectedValue` prop. That way they can also
+ // disallow/undo/mutate the selection of certain values. In other
+ // words, the embedder of this component should be the source of
+ // truth, not the native component.
+ if (this.state.selectedIndex !== event.nativeEvent.newIndex) {
+ this.refs[PICKER].setNativeProps({
+ selectedIndex: this.state.selectedIndex
+ });
+ }
+ },
+});
+
+PickerIOS.Item = React.createClass({
+ propTypes: {
+ value: React.PropTypes.any, // string or integer basically
+ label: React.PropTypes.string,
+ },
+
+ render: function() {
+ // These items don't get rendered directly.
+ return null;
+ },
+});
+
+var styles = StyleSheet.create({
+ rkPickerIOS: {
+ // The picker will conform to whatever width is given, but we do
+ // have to set the component's height explicitly on the
+ // surrounding view to ensure it gets rendered.
+ height: RKPickerIOSConsts.ComponentHeight,
+ },
+});
+
+var rkPickerIOSAttributes = merge(ReactIOSViewAttributes.UIView, {
+ items: true,
+ selectedIndex: true,
+});
+
+var RKPickerIOS = createReactIOSNativeComponentClass({
+ validAttributes: rkPickerIOSAttributes,
+ uiViewClassName: 'RCTPicker',
+});
+
+module.exports = PickerIOS;
diff --git a/ReactKit/ReactKit.xcodeproj/project.pbxproj b/ReactKit/ReactKit.xcodeproj/project.pbxproj
index e1c76e3afd7..c2efa2125eb 100644
--- a/ReactKit/ReactKit.xcodeproj/project.pbxproj
+++ b/ReactKit/ReactKit.xcodeproj/project.pbxproj
@@ -212,6 +212,8 @@
13B07FE81A69327A00A75B9A /* RCTAlertManager.m */,
13B07FE91A69327A00A75B9A /* RCTExceptionsManager.h */,
13B07FEA1A69327A00A75B9A /* RCTExceptionsManager.m */,
+ 5F5F0D971A9E456B001279FA /* RCTLocationObserver.h */,
+ 5F5F0D981A9E456B001279FA /* RCTLocationObserver.m */,
13723B4E1A82FD3C00F88898 /* RCTStatusBarManager.h */,
13723B4F1A82FD3C00F88898 /* RCTStatusBarManager.m */,
13B07FED1A69327A00A75B9A /* RCTTiming.h */,