Skip to content

Commit

Permalink
Support Google Maps on iOS (#548)
Browse files Browse the repository at this point in the history
  • Loading branch information
gilbox committed Sep 22, 2016
1 parent f4219a2 commit f78c0ee
Show file tree
Hide file tree
Showing 58 changed files with 2,098 additions and 446 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ local.properties
#
node_modules/
npm-debug.log
Pods/
AirMapsExplorer.xcworkspace/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ React Native Map components for iOS + Android

See [Installation Instructions](docs/installation.md).

See [Setup Instructions for the Included Example Project](docs/examples-setup.md).

## Compatibility

Due to the rapid changes being made in the React Native ecosystem, we are not officially going to
Expand Down
18 changes: 14 additions & 4 deletions components/MapCallout.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React, { PropTypes } from 'react';
import {
View,
requireNativeComponent,
StyleSheet,
} from 'react-native';
import decorateMapComponent, {
SUPPORTED,
USES_DEFAULT_IMPLEMENTATION,
} from './decorateMapComponent';

const propTypes = {
...View.propTypes,
Expand All @@ -17,6 +20,7 @@ const defaultProps = {

class MapCallout extends React.Component {
render() {
const AIRMapCallout = this.getAirComponent();
return <AIRMapCallout {...this.props} style={[styles.callout, this.props.style]} />;
}
}
Expand All @@ -30,6 +34,12 @@ const styles = StyleSheet.create({
},
});

const AIRMapCallout = requireNativeComponent('AIRMapCallout', MapCallout);

module.exports = MapCallout;
module.exports = decorateMapComponent(MapCallout, {
componentType: 'Callout',
providers: {
google: {
ios: SUPPORTED,
android: USES_DEFAULT_IMPLEMENTATION,
},
},
});
18 changes: 14 additions & 4 deletions components/MapCircle.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React, { PropTypes } from 'react';
import {
View,
requireNativeComponent,
} from 'react-native';
import decorateMapComponent, {
USES_DEFAULT_IMPLEMENTATION,
NOT_SUPPORTED,
} from './decorateMapComponent';

const propTypes = {
...View.propTypes,
Expand Down Expand Up @@ -123,6 +126,7 @@ const defaultProps = {

class MapCircle extends React.Component {
render() {
const AIRMapCircle = this.getAirComponent();
return (
<AIRMapCircle {...this.props} />
);
Expand All @@ -132,6 +136,12 @@ class MapCircle extends React.Component {
MapCircle.propTypes = propTypes;
MapCircle.defaultProps = defaultProps;

const AIRMapCircle = requireNativeComponent('AIRMapCircle', MapCircle);

module.exports = MapCircle;
module.exports = decorateMapComponent(MapCircle, {
componentType: 'Circle',
providers: {
google: {
ios: NOT_SUPPORTED,
android: USES_DEFAULT_IMPLEMENTATION,
},
},
});
28 changes: 18 additions & 10 deletions components/MapMarker.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { PropTypes } from 'react';
import {
View,
requireNativeComponent,
StyleSheet,
Platform,
NativeModules,
Expand All @@ -10,9 +9,13 @@ import {
} from 'react-native';

import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
import decorateMapComponent, {
SUPPORTED,
USES_DEFAULT_IMPLEMENTATION,
} from './decorateMapComponent';

const viewConfig = {
uiViewClassName: 'AIRMapMarker',
uiViewClassName: 'AIR<provider>MapMarker',
validAttributes: {
coordinate: true,
},
Expand Down Expand Up @@ -226,16 +229,13 @@ class MapMarker extends React.Component {
case 'android':
NativeModules.UIManager.dispatchViewManagerCommand(
this._getHandle(),
NativeModules.UIManager.AIRMapMarker.Commands[name],
this.getUIManagerCommand(name),
args
);
break;

case 'ios':
NativeModules.AIRMapMarkerManager[name].apply(
NativeModules.AIRMapMarkerManager[name],
[this._getHandle(), ...args]
);
this.getMapManagerCommand(name)(this._getHandle(), ...args);
break;

default:
Expand All @@ -250,6 +250,8 @@ class MapMarker extends React.Component {
image = image.uri;
}

const AIRMapMarker = this.getAirComponent();

return (
<AIRMapMarker
ref={ref => { this.marker = ref; }}
Expand All @@ -272,8 +274,14 @@ const styles = StyleSheet.create({
},
});

const AIRMapMarker = requireNativeComponent('AIRMapMarker', MapMarker);

MapMarker.Animated = Animated.createAnimatedComponent(MapMarker);

module.exports = MapMarker;
module.exports = decorateMapComponent(MapMarker, {
componentType: 'Marker',
providers: {
google: {
ios: SUPPORTED,
android: USES_DEFAULT_IMPLEMENTATION,
},
},
});
18 changes: 14 additions & 4 deletions components/MapPolygon.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React, { PropTypes } from 'react';
import {
View,
requireNativeComponent,
} from 'react-native';
import decorateMapComponent, {
USES_DEFAULT_IMPLEMENTATION,
NOT_SUPPORTED,
} from './decorateMapComponent';

const propTypes = {
...View.propTypes,
Expand Down Expand Up @@ -128,6 +131,7 @@ const defaultProps = {

class MapPolygon extends React.Component {
render() {
const AIRMapPolygon = this.getAirComponent();
return (
<AIRMapPolygon {...this.props} />
);
Expand All @@ -137,6 +141,12 @@ class MapPolygon extends React.Component {
MapPolygon.propTypes = propTypes;
MapPolygon.defaultProps = defaultProps;

const AIRMapPolygon = requireNativeComponent('AIRMapPolygon', MapPolygon);

module.exports = MapPolygon;
module.exports = decorateMapComponent(MapPolygon, {
componentType: 'Polygon',
providers: {
google: {
ios: NOT_SUPPORTED,
android: USES_DEFAULT_IMPLEMENTATION,
},
},
});
18 changes: 14 additions & 4 deletions components/MapPolyline.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import React, { PropTypes } from 'react';
import {
View,
requireNativeComponent,
} from 'react-native';
import decorateMapComponent, {
USES_DEFAULT_IMPLEMENTATION,
NOT_SUPPORTED,
} from './decorateMapComponent';

const propTypes = {
...View.propTypes,
Expand Down Expand Up @@ -123,6 +126,7 @@ const defaultProps = {

class MapPolyline extends React.Component {
render() {
const AIRMapPolyline = this.getAirComponent();
return (
<AIRMapPolyline {...this.props} />
);
Expand All @@ -132,6 +136,12 @@ class MapPolyline extends React.Component {
MapPolyline.propTypes = propTypes;
MapPolyline.defaultProps = defaultProps;

const AIRMapPolyline = requireNativeComponent('AIRMapPolyline', MapPolyline);

module.exports = MapPolyline;
module.exports = decorateMapComponent(MapPolyline, {
componentType: 'Polyline',
providers: {
google: {
ios: NOT_SUPPORTED,
android: USES_DEFAULT_IMPLEMENTATION,
},
},
});
69 changes: 55 additions & 14 deletions components/MapView.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ import MapPolygon from './MapPolygon';
import MapCircle from './MapCircle';
import MapCallout from './MapCallout';
import MapUrlTile from './MapUrlTile';
import {
contextTypes as childContextTypes,
getAirMapName,
googleMapIsInstalled,
createNotSupportedComponent,
} from './decorateMapComponent';
import * as ProviderConstants from './ProviderConstants';

const MAP_TYPES = {
STANDARD: 'standard',
Expand All @@ -30,14 +37,23 @@ const ANDROID_ONLY_MAP_TYPES = [
];

const viewConfig = {
uiViewClassName: 'AIRMap',
uiViewClassName: 'AIR<provider>Map',
validAttributes: {
region: true,
},
};

const propTypes = {
...View.propTypes,
/**
* When provider is "google", we will use GoogleMaps.
* Any value other than "google" will default to using
* MapKit in iOS or GoogleMaps in android as the map provider.
*/
provider: PropTypes.oneOf([
'google',
]),

/**
* Used to style and layout the `MapView`. See `StyleSheet.js` and
* `ViewStylePropTypes.js` for more info.
Expand Down Expand Up @@ -341,6 +357,10 @@ class MapView extends React.Component {
this._onLayout = this._onLayout.bind(this);
}

getChildContext() {
return { provider: this.props.provider };
}

componentDidMount() {
const { region, initialRegion } = this.props;
if (region && this.state.isReady) {
Expand Down Expand Up @@ -421,6 +441,14 @@ class MapView extends React.Component {
this._runCommand('takeSnapshot', [width, height, finalRegion, callback]);
}

_uiManagerCommand(name) {
return NativeModules.UIManager[getAirMapName(this.props.provider)].Commands[name];
}

_mapManagerCommand(name) {
return NativeModules[`${getAirMapName(this.props.provider)}Manager`][name];
}

_getHandle() {
return findNodeHandle(this.map);
}
Expand All @@ -430,16 +458,13 @@ class MapView extends React.Component {
case 'android':
NativeModules.UIManager.dispatchViewManagerCommand(
this._getHandle(),
NativeModules.UIManager.AIRMap.Commands[name],
this._uiManagerCommand(name),
args
);
break;

case 'ios':
NativeModules.AIRMapManager[name].apply(
NativeModules.AIRMapManager[name],
[this._getHandle(), ...args]
);
this._mapManagerCommand(name)(this._getHandle(), ...args);
break;

default:
Expand Down Expand Up @@ -483,6 +508,8 @@ class MapView extends React.Component {
);
}

const AIRMap = getAirMapComponent(this.props.provider);

return (
<AIRMap
ref={ref => { this.map = ref; }}
Expand All @@ -494,31 +521,45 @@ class MapView extends React.Component {

MapView.propTypes = propTypes;
MapView.viewConfig = viewConfig;
MapView.childContextTypes = childContextTypes;

MapView.MAP_TYPES = MAP_TYPES;

const AIRMap = requireNativeComponent('AIRMap', MapView, {
const nativeComponent = Component => requireNativeComponent(Component, MapView, {
nativeOnly: {
onChange: true,
onMapReady: true,
handlePanDrag: true,
},
});
const airMaps = {
default: nativeComponent('AIRMap'),
};
if (Platform.OS === 'android') {
airMaps.google = airMaps.default;
} else {
airMaps.google = googleMapIsInstalled ? nativeComponent('AIRGoogleMap') :
createNotSupportedComponent('react-native-maps: AirGoogleMaps dir must be added to your xCode project to support GoogleMaps on iOS.'); // eslint-disable-line max-len
}
const getAirMapComponent = provider => airMaps[provider || 'default'];

const AIRMapLite = requireNativeComponent('AIRMapLite', MapView, {
nativeOnly: {
onChange: true,
onMapReady: true,
handlePanDrag: true,
},
});
const AIRMapLite = NativeModules.UIManager.AIRMapLite &&
requireNativeComponent('AIRMapLite', MapView, {
nativeOnly: {
onChange: true,
onMapReady: true,
handlePanDrag: true,
},
});

MapView.Marker = MapMarker;
MapView.Polyline = MapPolyline;
MapView.Polygon = MapPolygon;
MapView.Circle = MapCircle;
MapView.UrlTile = MapUrlTile;
MapView.Callout = MapCallout;
Object.assign(MapView, ProviderConstants);
MapView.ProviderPropType = PropTypes.oneOf(Object.values(ProviderConstants));

MapView.Animated = Animated.createAnimatedComponent(MapView);

Expand Down
2 changes: 2 additions & 0 deletions components/ProviderConstants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const PROVIDER_DEFAULT = null;
export const PROVIDER_GOOGLE = 'google';
Loading

0 comments on commit f78c0ee

Please sign in to comment.