Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Google Maps on iOS #548

Merged
merged 8 commits into from
Sep 22, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
},
},
});
53 changes: 46 additions & 7 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,16 +521,27 @@ 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') {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Platform.select might be cleaner here...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but it would mean evaluating both cases

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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's bring in the dedent module and use a template string for this. I've been using that in some other places and it is really nice.

}
const getAirMapComponent = provider => airMaps[provider || 'default'];

const AIRMapLite = requireNativeComponent('AIRMapLite', MapView, {
nativeOnly: {
Expand All @@ -519,6 +557,7 @@ MapView.Polygon = MapPolygon;
MapView.Circle = MapCircle;
MapView.UrlTile = MapUrlTile;
MapView.Callout = MapCallout;
Object.assign(MapView, 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