嗨,我正在学习 React Native 并使用 expo go。
我想通过 MapView 和 Google Maps API 显示地图。 并且用模拟器测试也没有出现错误。 但是转换成apk文件后出现错误。 每当我尝试打开地图页面时它就会停止。
我正在搜索所有文档,但找不到解决我的问题的方法。
下面是我的页面的完整代码,其中有mapView。
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, Pressable } from 'react-native';
import { PROVIDER_GOOGLE, Marker } from 'react-native-maps';
import MapView from 'react-native-maps';
import Header from '../components/fixed/Header';
import Colors from "../constants/Colors";
import { getSafeContentHeight } from '../constants/DeviceSize';
import deviceSize from "../constants/DeviceSize";
const deviceWidth = deviceSize.deviceWidth;
const deviceHeight = deviceSize.deviceHeight;
export default function MapPush({ navigation, route }) {
const { myLocation } = route.params;
const [safeContentHeight, safeContentHeightWithoutNav] = getSafeContentHeight();
const [pressedMarkerInfo, setPressedMarkerInfo] = useState(null);
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<View style={{ width: deviceWidth, height: safeContentHeightWithoutNav, paddingTop: 50 }}>
<Header title="홍대입구역 9번출구" isPush={true} navigation={navigation} />
<MapView
style={{ width: '100%', height: '100%' }}
region={{
latitude: 37.55604312175928,
longitude: 126.92299623955266,
latitudeDelta: 0.01827,
longitudeDelta: 0.01198
}}
initialRegion={{
latitude: 37.55604312175928,
longitude: 126.92299623955266,
latitudeDelta: 0.01827,
longitudeDelta: 0.01198
}}
minZoomLevel={12}
maxZoomLevel={20}
showsUserLocation={true}
showsMyLocationButton={true}
provider={PROVIDER_GOOGLE}
>
<Marker
coordinate={{
latitude: 37.55604312175928,
longitude: 126.92299623955266,
}}
pinColor="red"
onPress={() => {
setIsModalOpen(true)
}}
>
<View style={[
styles.markerContainer,
]}>
<Text
style={[
styles.markerText,
]}
>
홍대입구역 9번출구
</Text>
</View>
<View
style={[
styles.markerTriangle,
]}
/>
</Marker>
</MapView>
</View>
)
};
const styles = StyleSheet.create({
container: {},
markerContainer: {
position: 'relative',
backgroundColor: Colors.white,
paddingHorizontal: 10,
paddingVertical: 7,
borderRadius: 30,
borderWidth: 1,
borderColor: Colors.cool_gray2
},
markerText: {
fontFamily: 'GothicA1-Bold',
fontSize: deviceWidth / 400 * 16.5,
lineHeight: deviceWidth / 400 * 17.5,
color: Colors.cool_gray5
},
markerTriangle: {
alignSelf: 'center',
width: 0,
height: 0,
// borderWidth: 8,
borderColor: 'transparent',
borderTopColor: Colors.cool_gray2,
borderWidth: 13,
marginTop: -1
},
})
我还会将 App.js 和其他导入的组件放入 MapPush 中
import React, { useEffect, useRef, useState } from "react";
import { View } from 'react-native';
import { useFonts } from 'expo-font';
// import LottieView from "lottie-react-native";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Tab = createBottomTabNavigator();
const Stack = createNativeStackNavigator();
import PinUp from "./src/components/animations/PinUp";
// import LogIn from "./src/screens/LogIn";
import NavBar from './src/components/fixed/NavBar';
import Home from './src/screens/Home';
import PinDetail from './src/screens/PinDetail';
import MapPush from "./src/screens/MapView";
import Records from './src/screens/Records';
import FindPin from './src/screens/FindPin';
import MakePin from "./src/screens/MakePin";
import Search from './src/screens/Search';
import SearchMap from "./src/screens/SearchMap";
import MakePinSearch from "./src/screens/makePinSearch";
import Map from "./src/screens/Map";
import Invites from './src/screens/Invites';
import FriendRequest from './src/screens/FriendRequest';
import MyBoard from './src/screens/MyBoard';
import OthersBoard from './src/screens/OthersBoard';
import Settings from './src/screens/Settings';
import ProfileSetting from "./src/screens/ProfileSetting";
import Notice from './src/screens/Notice';
import KaKaoLogin from "./src/screens/KakaoLogin";
import { getLocationPermissionHandler } from "./src/expoSDK/expoLocation";
import Colors from './src/constants/Colors';
import deviceSize from "./src/constants/DeviceSize";
import LogIn from "./src/screens/LogIn";
const deviceWidth = deviceSize.deviceWidth;
const deviceHeight = deviceSize.deviceHeight;
export default function App() {
let [fontsLoaded] = useFonts({
'GothicA1-Thin': require('./assets/fonts/GothicA1-Thin.ttf'),
'GothicA1-ExtraLight': require('./assets/fonts/GothicA1-ExtraLight.ttf'),
'GothicA1-Light': require('./assets/fonts/GothicA1-Light.ttf'),
'GothicA1-Regular': require('./assets/fonts/GothicA1-Regular.ttf'),
'GothicA1-Medium': require('./assets/fonts/GothicA1-Medium.ttf'),
'GothicA1-SemiBold': require('./assets/fonts/GothicA1-SemiBold.ttf'),
'GothicA1-Bold': require('./assets/fonts/GothicA1-Bold.ttf'),
'GothicA1-ExtraBold': require('./assets/fonts/GothicA1-ExtraBold.ttf'),
'GothicA1-Black': require('./assets/fonts/GothicA1-Black.ttf'),
});
// const animationRef = useRef<LottieView>(null);
const [login, setLogin] = useState(false);
const [locationPermissionStatus, setLocationPermissionStatus] = useState();
const [isSplash, setIsSplash] = useState(true)
useEffect(() => {
// animationRef.current?.play(30, 120);
getLocationPermissionHandler()
.then(status => setLocationPermissionStatus(status))
setTimeout(() => {
setIsSplash(false)
setLogin(true);
}, 3 * 1000)
}, []);
if (fontsLoaded && locationPermissionStatus === 'granted') {
function TabNav() {
return (
<Tab.Navigator
screenOptions={() => ({ headerShown: false })}
tabBar={props => <NavBar {...props} />}
>
<Tab.Screen name="참여중" component={Home} />
<Tab.Screen name="참여내역" component={Records} />
<Tab.Screen name="방찾기" component={FindPin}
options={{ headerShown: false }}
initialParams={{ locationPermissionStatus: locationPermissionStatus }}
/>
<Tab.Screen name="알림" component={Invites} />
<Tab.Screen name="내 보드" component={MyBoard}
initialParams={{ smoke: '비흡연', drink: '금주중', img: null }}
/>
</Tab.Navigator>
)
}
return (
<>
<View style={{ flex: 1, backgroundColor: Colors.cool_gray_minus_1 }}>
<SafeAreaProvider>
<SafeAreaView style={{ flex: 1 }}>
{isSplash && <PinUp />}
{login && <LogIn setLogin={setLogin} />}
<NavigationContainer>
{/* {login && <LogIn setLogin={setLogin} />} */}
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="TabNav" component={TabNav} />
<Stack.Screen name="공지" component={Notice} options={{ headerShown: false }} />
<Stack.Screen name="검색" component={Search} options={{ headerShown: false }} />
<Stack.Screen name="상대 보드" component={OthersBoard} options={{ headerShown: false }}
initialParams={{ isHost: null }}
/>
<Stack.Screen name="설정" component={Settings} options={{ headerShown: false }} />
<Stack.Screen name="핀 상세" component={PinDetail} options={{ headerShown: false }}
initialParams={{ displayLeftDate: null, isIn: null, isOver: null }}
/>
<Stack.Screen name="친구 요청" component={FriendRequest} options={{ headerShown: false }}
initialParams={{ isList: null, isBlock: null }}
/>
<Stack.Screen name="핀 생성" component={MakePin} options={{ headerShown: false }}
initialParams={{ myLocation: null, selectedLocationInfo: null, selectedSchools: null, selectedFriends: null }}
/>
<Stack.Screen name="장소 검색" component={SearchMap} options={{ headerShown: false }}
initialParams={{ myLocation: null }}
/>
<Stack.Screen name="핀 생성 검색" component={MakePinSearch} options={{ headerShown: false }}
initialParams={{ isFriend: null, myLocation: null, selectedLocationInfo: null }}
/>
<Stack.Screen name="지도보기" component={MapPush} options={{ headerShown: false }}
initialParams={{ myLocation: null }}
/>
<Stack.Screen name="카카오로그인" component={KaKaoLogin} options={{ headerShown: false }} />
<Stack.Screen name="프로필 설정" component={ProfileSetting} options={{ headerShown: false }}
initialParams={{ smoking: null, drinking: null, img: null }}
/>
<Stack.Screen name="방찾기 지도" component={Map}
initialParams={{ myLocation: null }}
/>
</Stack.Navigator>
</NavigationContainer>
</SafeAreaView>
</SafeAreaProvider>
</View>
</>
);
}
}
import { Dimensions, Platform } from "react-native";
import { useSafeAreaInsets } from 'react-native-safe-area-context';
const deviceWidth = Dimensions.get('window').width;
const deviceHeight = Dimensions.get('window').height;
const deviceSize = { deviceWidth, deviceHeight };
export default deviceSize;
export function getSafeContentHeight() {
const insets = useSafeAreaInsets();
const safeContentHeight = deviceHeight - (insets.top + insets.bottom + (Platform.OS === 'ios' ? 58 : 68));
const safeContentHeightWithoutNav = deviceHeight - (insets.top + insets.bottom);
return [safeContentHeight, safeContentHeightWithoutNav];
};
import React from "react";
import { View, Text, Pressable, StyleSheet, TextInput, Platform } from "react-native";
import { LinearGradient } from 'expo-linear-gradient';
import { MaterialIcons } from '@expo/vector-icons';
import Colors from "../../constants/Colors";
import deviceSize from "../../constants/DeviceSize"
const deviceWidth = deviceSize.deviceWidth;
const deviceHeight = deviceSize.deviceHeight;
export default function Header({
title,
toggleMenu, selected, setSelected,
isSearch, inputText, setInputText, keywordSearchHttpHandler,
isPush, navigation, ContaienrStyle,
isModalOpen, setIsModalOpen,
pressedMarkerInfo, setPressedMarkerInfo,
searchRes, setSearchRes,
isSchoolPage, selectedSchools,
myLocation,
selectedLocationInfo
}) {
if (title && !toggleMenu) {
return (
<View style={[styles.container, ContaienrStyle]}>
{
isPush ?
<Pressable
style={styles.titleBox}
onPress={() => navigation.goBack()}
>
<MaterialIcons name="arrow-back-ios" size={19} color={Colors.black} />
<Text style={[styles.title]}>
{title}
</Text>
</Pressable>
:
<Text style={styles.title}>
{title}
</Text>
}
</View>
)
} else if (!title && toggleMenu) {
return (
<View style={[styles.container, ContaienrStyle]}>
{
isPush &&
<Pressable onPress={() => navigation.goBack()}>
<MaterialIcons name="arrow-back-ios" size={19} color={Colors.black} />
</Pressable>
}
{
toggleMenu.map((a, i) => {
return (
<Pressable
style={styles.toggleMenuBox}
onPress={() => setSelected(a)}
key={i}
>
<Text style={[styles.toggleMenu, selected === a && { color: Colors.black }]}>{a}</Text>
</Pressable>
)
})
}
</View>
)
} else if (isSearch) {
return (
<LinearGradient
style={[styles.container, ContaienrStyle]}
colors={[Colors.cool_gray02, Colors.cool_gray02_trans]}
>
{
isPush &&
<Pressable onPress={() => {
if(isModalOpen) {
if(pressedMarkerInfo) {
setPressedMarkerInfo(null);
} else if (searchRes){
setSearchRes(null);
setIsModalOpen(false)
}
} else {
if (isSchoolPage) {
console.log(selectedLocationInfo)
navigation.navigate('핀 생성', {
myLocation: myLocation,
selectedSchools: null,
selectedLocationInfo: selectedLocationInfo
})
} else {
navigation.goBack()
}
}
}}>
<MaterialIcons name="arrow-back-ios" size={19} color={Colors.cool_gray4} />
</Pressable>
}
<View style={styles.textInputContainer}>
<TextInput
value={inputText}
onChangeText={(text) => setInputText(text)}
onSubmitEditing={() => keywordSearchHttpHandler()}
placeholder="검색어를 입력하세요"
style={styles.textInput}
/>
</View>
</LinearGradient>
)
}
};
const styles = StyleSheet.create({
container: {
width: deviceWidth,
height: 50,
position: 'absolute',
top: 0,
flexDirection: 'row',
alignItems: 'flex-end',
backgroundColor: Colors.cool_gray_minus_1,
paddingHorizontal: 20,
paddingBottom: 13,
shadowColor: "black",
shadowOffset: {
width: 1,
height: 2
},
shadowOpacity: 0.05,
elevation: 1
},
titleBox: {
flexDirection: 'row',
alignItems: 'center'
// justifyContent:
},
title: {
fontSize: 16.5,
// lineHeight: 17.5,
// fontFamily: 'GothicA1-Bold',
fontWeight: 700,
marginTop: Platform.OS === 'ios' ? null : - deviceWidth / 400 * 3
},
toggleMenuBox: {
marginRight: 13
},
toggleMenu: {
fontSize: 16.5,
// lineHeight: 17,
// fontFamily: 'GothicA1-Bold',
fontWeight: 700,
color: Colors.cool_gray3,
marginTop: Platform.OS === 'ios' ? null : - deviceWidth / 400 * 3
},
textInputContainer: {
width: deviceWidth * 0.85,
height: 30,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: Colors.white_semiTrans,
marginLeft: deviceWidth / 400 * 5,
marginBottom: -5,
borderRadius: 10
},
textInput: {
width: deviceWidth * 0.8,
height: 27,
// backgroundColor: 'red',
// fontFamily: 'GothicA1-SemiBold',
fontSize: 15.5,
// lineHeight: 16,
// fontWeight: 600,
paddingTop: 2,
color: Colors.cool_gray5
},
})
还有我的 package.json 文件
{
"name": "pinup",
"version": "1.0.0",
"scripts": {
"start": "expo start --dev-client",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web"
},
"dependencies": {
"@jiggag/react-native-kakao-maps": "^0.0.10",
"@react-native-async-storage/async-storage": "1.17.11",
"@react-native-community/datetimepicker": "6.7.3",
"@react-native-community/masked-view": "^0.1.11",
"@react-native-community/slider": "4.4.2",
"@react-native-seoul/kakao-login": "^5.3.0",
"@react-navigation/bottom-tabs": "^6.5.8",
"@react-navigation/native": "^6.1.7",
"@react-navigation/native-stack": "^6.9.13",
"@react-navigation/stack": "^6.3.17",
"axios": "^1.4.0",
"expo": "~48.0.18",
"expo-build-properties": "~0.6.0",
"expo-camera": "~13.2.1",
"expo-font": "~11.1.1",
"expo-image-picker": "~14.1.1",
"expo-linear-gradient": "~12.1.2",
"expo-linking": "~4.0.1",
"expo-location": "~15.1.1",
"expo-splash-screen": "~0.18.2",
"expo-status-bar": "~1.4.4",
"lottie-react-native": "5.1.4",
"react": "18.2.0",
"react-kakao-maps-sdk": "^1.1.11",
"react-native": "0.71.8",
"react-native-asset": "^2.1.1",
"react-native-gesture-handler": "~2.9.0",
"react-native-image-picker": "^5.6.0",
"react-native-maps": "1.3.2",
"react-native-paper": "^5.9.1",
"react-native-reanimated": "~2.14.4",
"react-native-safe-area-context": "4.5.0",
"react-native-screens": "~3.20.0",
"react-native-status-bar-height": "^2.6.0",
"react-native-vector-icons": "^9.2.0",
"react-native-webview": "11.26.0",
"react-navigation": "^4.4.4",
"react-navigation-stack": "^2.10.4"
},
"devDependencies": {
"@babel/core": "^7.20.0"
},
"private": true,
"rnpm": {
"assets": [
"./assets/fonts/"
]
}
}
我应该怎样做才能让我的应用程序不崩溃并停止?
我通过在 android.config.googleMaps.apiKey 下的 app.json 中正确添加我的 api 密钥解决了这个问题
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.your.app",
"NSAppTransportSecurity": {
"NSAllowsArbitraryLoads": true,
"NSAllowsArbitraryLoadsInWebContent": true
},
"config": {
"googleMapsApiKey": "YOUR API KEY"
}
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "com.your.app",
"config": {
"googleMaps": {
"apiKey" : "YOUR API KEY"
}
}
},