☕ How I Actually Got Google Maps Working in React Native (and Why It Took Me Way Longer Than It Should Have)
So last week, I’m building this Coffee Shop Locator app. Simple idea, right? Show users nearby cafés on a map.
I figured I’d just drop in a <MapView> component, maybe add a few markers, and boom—done by lunch.
Yeah... that didn’t happen. 😅
Three hours later, I’m staring at a blank gray screen, Googling “why is my react native map not showing” for the hundredth time, and questioning all my life choices.
But I finally got it working. And honestly? Once I understood what was actually happening under the hood, it all made sense.
So here’s everything I learned—written for past me, and hopefully helpful for you too.
🧩 Why Maps Aren’t Just “Install and Go…
☕ How I Actually Got Google Maps Working in React Native (and Why It Took Me Way Longer Than It Should Have)
So last week, I’m building this Coffee Shop Locator app. Simple idea, right? Show users nearby cafés on a map.
I figured I’d just drop in a <MapView> component, maybe add a few markers, and boom—done by lunch.
Yeah... that didn’t happen. 😅
Three hours later, I’m staring at a blank gray screen, Googling “why is my react native map not showing” for the hundredth time, and questioning all my life choices.
But I finally got it working. And honestly? Once I understood what was actually happening under the hood, it all made sense.
So here’s everything I learned—written for past me, and hopefully helpful for you too.
🧩 Why Maps Aren’t Just “Install and Go”
Here’s the thing nobody tells you upfront: React Native doesn’t come with maps built-in.
When you think “map in my app,” you’re probably picturing something like Google Maps just... working. But that’s not quite how it goes.
Under the hood, maps work completely differently on each platform:
- Android uses the Google Maps SDK (native Java/Kotlin stuff)
- iOS uses Apple’s MapKit (native Swift code)
Your React Native app? That’s all JavaScript. The map itself lives in native land.
So you need something that bridges the gap—something that lets you write simple JavaScript like this:
<MapView>
<Marker coordinate={{ latitude: 28.61, longitude: 77.23 }} />
</MapView>
...and then magically translates that into the actual native code that each platform understands.
That bridge is react-native-maps. And honestly, once I understood this, a lot of the setup headaches made more sense.
🌍 What react-native-maps Actually Does
Think of it like a translator at a conference.
You (JavaScript developer) speak one language. The native SDKs (Google Maps, Apple Maps) speak another. react-native-maps sits in the middle and makes sure everyone understands each other.
Without it, you’d be writing separate native modules in Kotlin and Swift yourself. No thanks. 😬
⚙️ The Part Where I Actually Set This Up (Android Edition)
Alright, this is where most tutorials lose me with vague instructions. So I’m gonna walk through exactly what I did, step by step.
🧭 Step 1: Get Your Google Maps API Key
Head over to the Google Cloud Console.
Click “Create API Key” and make sure you enable these three things:
- ✅ Maps SDK for Android
- ✅ Maps SDK for iOS
- ✅ Places API (if you want search/autocomplete later)
Copy that API key. You’ll need it in a second.
🔑 Step 2: Tell Android About Your API Key
Open up your Android manifest file:
android/app/src/main/AndroidManifest.xml
Inside the <application> tag, paste this:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_GOOGLE_MAPS_API_KEY"/>
This is basically how your Android app knows which API key to use when it talks to Google’s servers.
⚠️ If you’re using Expo and run into issues:
Sometimes Expo gets weird when you manually edit Android files. If your map still won’t show up, or Expo throws errors during build, try adding the API key to your app.json instead:
"android": {
"package": "com.example.coffeemap",
"config": {
"googleMaps": {
"apiKey": "${GOOGLE_MAPS_API_KEY}"
}
}
}
I ran into this myself—spent way too long trying to figure out why the manifest approach wasn’t working. Turns out Expo sometimes overrides those manual changes during build. Using app.json lets Expo handle it properly.
📝 Pro tip: Don’t leave your API key wide open. Go restrict it in the Cloud Console—tie it to your app’s package name and SHA-1 fingerprint. (I’ll show you how to get those in the next step.)
🔍 Step 3: Get Your SHA-1 Fingerprint
Okay, this part confused me at first. What even is a SHA-1 fingerprint?
Basically, it’s a unique digital signature for your app. It comes from the keystore file that signs your APK. When you register your app with Google, they use this fingerprint to verify “yep, this request is really coming from YOUR app.”
Each keystore = different SHA-1 = different identity.
Here’s how to get it:
📂 Navigate to your Android folder
cd android
💻 Run the signing report
On Windows (Command Prompt or PowerShell):
gradlew signingReport
On macOS or Linux:
./gradlew signingReport
You’ll see a bunch of output. Look for something like this:
Variant: debug
SHA1: 12:34:56:AB:CD:EF:98:76:54:32:10:FF:EE:DD:CC:BB:AA:99:88
Package name: com.example.coffeemap
Copy both the SHA-1 and your package name (also called applicationId).
Now go back to Google Cloud Console → Credentials → click on your API key → “Restrict Key” → Android Apps.
Add your package name and SHA-1 there.
⚠️ Important: Make sure you’re using the right SHA-1 for your build type! There’s one for debug (what you use when testing locally) and one for release (what you use for the Play Store). Use the debug one while you’re developing.
🧹 Step 4: Clean Everything and Rebuild
Sometimes Android gets stubborn and caches old stuff. So do this:
cd android
./gradlew clean
cd ..
npx react-native run-android
If the map is still blank (which happened to me), uninstall the app completely from your device/emulator and reinstall it. That finally did the trick for me.
🗺️ The Moment of Truth: A Working Map 🎉
Okay, after all that setup... here’s the payoff. This is the simplest version that actually works:
import React from "react";
import { View, StyleSheet } from "react-native";
import MapView, { Marker } from "react-native-maps";
export default function CoffeeMap() {
return (
<View style={styles.container}>
<MapView
provider="google"
style={styles.map}
initialRegion={{
latitude: 28.6139, // New Delhi
longitude: 77.2090,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
}}
onMapReady={() => console.log("✅ Map is ready!")}
>
<Marker
coordinate={{ latitude: 28.6139, longitude: 77.2090 }}
title="Central Café"
description="Your daily caffeine fix ☕"
/>
</MapView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
map: { flex: 1 },
});
When I finally saw that map load with my little red pin on it... honestly, such a satisfying moment. 😊
🧠 Understanding What These Components Actually Do
Once you have a working map, you’ll probably want to do more with it. Here’s a breakdown of the main components I used:
| Component | What It Does | Example |
|---|---|---|
<MapView> | The actual map | Base canvas for everything |
<Marker> | A pin on the map | Mark café locations |
<Callout> | Info popup when you tap a marker | Show details, ratings, hours |
<Polyline> | Draw lines on the map | Show routes or paths |
<Circle> | Highlight a circular area | Show delivery radius, etc. |
Let me break down each one a bit more...
🗺️ <MapView> — Your Map Canvas
<MapView
provider="google"
style={{ flex: 1 }}
initialRegion={{
latitude: 37.7749,
longitude: -122.4194,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
}}
showsUserLocation={true}
onMapReady={() => console.log("Map loaded!")}
/>
Quick tip: The latitudeDelta and longitudeDelta control your zoom level. Smaller numbers = more zoomed in. I usually just play with these values until it looks right.
📍 <Marker> — The Pin
<Marker
coordinate={{ latitude: 37.7749, longitude: -122.4194 }}
title="Best Bites Restaurant"
description="Open till 11 PM!"
pinColor="#FF5733"
/>
You can also use your own custom image instead of the default red pin:
image={require('../assets/restaurant-pin.png')}
I did this for my coffee shops—added little coffee cup icons. Makes it feel more polished.
💬 <Callout> — Info Popup
<Marker coordinate={{ latitude: 37.7749, longitude: -122.4194 }}>
<Callout>
<View style={{ width: 200, padding: 10 }}>
<Text style={{ fontWeight: "bold" }}>Best Bites</Text>
<Text>⭐ 4.5 • Fast Delivery</Text>
</View>
</Callout>
</Marker>
This is where you can get creative—show ratings, photos, business hours, whatever makes sense for your app.
🛣️ <Polyline> — Draw Routes
<Polyline
coordinates={[
{ latitude: 37.7749, longitude: -122.4194 },
{ latitude: 37.7849, longitude: -122.4094 },
]}
strokeColor="#007AFF"
strokeWidth={4}
/>
Perfect for showing delivery routes, walking paths, driving directions—anything that connects point A to point B.
🔵 <Circle> — Highlight Areas
<Circle
center={{ latitude: 37.7749, longitude: -122.4194 }}
radius={3000} // 3 km radius
strokeColor="#FF0000"
fillColor="rgba(255,0,0,0.2)"
/>
I used this to show the delivery range for each café. Users could see at a glance if they’re within range.
Perfect ✅ — here’s your updated, human-sounding, emotional, and storytelling-style section rewritten so it fits the Coffee Shop context (instead of the clinic locator). Everything sounds natural and still feels developer-friendly 👇
🚀 Going Beyond the Basics: Making It Interactive
Here’s where it got fun for me. Just showing a static map felt... boring. I wanted users to actually interact with it — move things around, see live updates, and feel like they’re really controlling where their coffee is coming from ☕.
So instead of a simple static café map, I built an interactive Coffee Shop Locator — where users can:
✅ Use their current GPS location
✅ Drag the coffee pin to pick their favorite café spot
✅ See live latitude and longitude updates
✅ Watch the map respond in real-time as they explore
Here’s the full code for that magic 👇
import React, { useEffect, useState } from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
ActivityIndicator,
} from "react-native";
import MapView, { Marker } from "react-native-maps";
import * as Location from "expo-location";
import Constants from "expo-constants";
import { scale, verticalScale } from "react-native-size-matters";
export default function CoffeeShopMapSelectionScreen() {
const [region, setRegion] = useState({
latitude: 20.5937,
longitude: 78.9629,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
});
const [loadingLocation, setLoadingLocation] = useState(false);
const [hasPermission, setHasPermission] = useState(false);
const googleApiKey = Constants.expoConfig?.extra?.GOOGLE_MAPS_API_KEY;
console.log("Using API key:", googleApiKey);
const requestLocationPermission = async () => {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
alert("Permission to access location was denied.");
return;
}
setHasPermission(true);
};
const fetchCurrentLocation = async () => {
try {
setLoadingLocation(true);
const { coords } = await Location.getCurrentPositionAsync({});
setRegion((prev) => ({
...prev,
latitude: coords.latitude,
longitude: coords.longitude,
}));
} catch (error) {
console.log("Error fetching current location:", error);
} finally {
setLoadingLocation(false);
}
};
useEffect(() => {
requestLocationPermission();
}, []);
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerTitle}>☕ Pick Your Coffee Spot</Text>
<TouchableOpacity
onPress={fetchCurrentLocation}
style={styles.currentLocationBtn}
>
{loadingLocation ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={styles.currentLocationText}>Use Current Location</Text>
)}
</TouchableOpacity>
</View>
<MapView
style={styles.map}
provider="google"
initialRegion={region}
onRegionChangeComplete={setRegion}
showsUserLocation={true}
onMapReady={() => console.log("✅ Map ready")}
>
<Marker
coordinate={{
latitude: region.latitude,
longitude: region.longitude,
}}
draggable
onDragEnd={(e) => {
const { latitude, longitude } = e.nativeEvent.coordinate;
setRegion({ ...region, latitude, longitude });
}}
pinColor="#b76e79"
title="Your Coffee Spot"
description="Drag to adjust location"
/>
</MapView>
<View style={styles.locationDetails}>
<Text style={styles.coordText}>
🌍 Latitude: {region.latitude.toFixed(6)}
</Text>
<Text style={styles.coordText}>
📍 Longitude: {region.longitude.toFixed(6)}
</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: "#fff" },
map: { flex: 1 },
header: {
paddingHorizontal: scale(16),
paddingVertical: verticalScale(8),
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
},
headerTitle: {
fontSize: 16,
fontWeight: "600",
color: "#222",
},
currentLocationBtn: {
backgroundColor: "#8B4513",
paddingHorizontal: scale(12),
paddingVertical: verticalScale(6),
borderRadius: 10,
},
currentLocationText: {
color: "#fff",
fontSize: 14,
fontWeight: "500",
},
locationDetails: {
backgroundColor: "#F9F9F9",
paddingVertical: verticalScale(10),
paddingHorizontal: scale(16),
borderTopWidth: 1,
borderColor: "#EAEAEA",
},
coordText: {
fontSize: 14,
color: "#333",
marginBottom: 4,
},
});
Then apply it:
import mapStyle from '../assets/map-style.json';
<MapView
customMapStyle={mapStyle}
style={{ flex: 1 }}
/>
Pro tip: Use the Google Map Styling Wizard to visually design your style. Way easier than hand-writing JSON. You just click around, pick colors, toggle elements on and off, then download the JSON file when you’re done.
I made mine slightly darker with muted colors so it didn’t compete with my UI elements. Made a huge difference in how professional the app felt.
Final Thoughts
Look, I’m not gonna lie—getting maps working in React Native was more work than I expected. But once I understood the why behind each step, it all clicked.
If you’re stuck on a blank gray screen right now, trust me—you’re probably just one small config fix away from getting it working. Double-check your API key, your SHA-1, your manifest. Clean and rebuild. Uninstall and reinstall if you have to.
And when it finally loads? When you see that map render with your markers and your custom styling? Honestly, it’s worth the hassle.
Good luck. You got this. ☕
Questions? Hit me up in the comments. I’ll try to help if I can.