
앱개발 종합반 78기 듣고 있습니다. 오래된 강의라서 강의영상 대신 강의안으로 따라가고 있습니다.
강의안에서 아래 부분 실행시켰는데 빨간색 오류가 뜹니다. 5번 넘게 여러가지 살펴봐가면서 시도해 봤는데 오류가 뜹니다. 뭐가 문제일지요?
eas build -p android --profile development
**오류메시지
Android build failed:
Gradle build failed with unknown error. See logs for the "Run gradlew" phase for more information
# 오류화면 캡쳐

# 애드몹 화면캡쳐


App.js 전체코드
import React, {useEffect} from "react";
//이제 모든 페이지 컴포넌트들이 끼워져있는 책갈피를 메인에 둘예정이므로
//컴포넌트를 더이상 불러오지 않아도 됩니다.
// import MainPage from './pages/MainPage';
// import DetailPage from './pages/DetailPage';
import { StatusBar } from 'expo-status-bar';
//메인에 세팅할 네비게이션 도구들을 가져옵니다.
import {NavigationContainer} from '@react-navigation/native';
import StackNavigator from './navigation/StackNavigator'
import mobileAds from 'react-native-google-mobile-ads';
export default function App() {
console.disableLoginBox = true;
useEffect(()=>{
//구글 애드몹은 실제 빌드된 앱에서만 가능하기 때문에! 조건부 처리!
if(!__DEV__){
mobileAds()
.initialize()
.then(adapterStatuses => {
// Initialization complete!
});
}
},[])
return (
<NavigationContainer>
<StatusBar style="dark"/>
<StackNavigator/>
</NavigationContainer>);
}
MainPage.js 전체코드
import React,{useState,useEffect} from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';
const main = 'https://storage.googleapis.com/sparta-image.appspot.com/lecture/main.png'
import data from '../data.json';
import Card from '../components/Card';
import Loading from '../components/Loading';
import { StatusBar } from 'expo-status-bar';
import * as Location from "expo-location";
import axios from "axios"
import {firebase_db} from "../firebaseConfig"
import { BannerAd, BannerAdSize, TestIds } from 'react-native-google-mobile-ads';
import AdCard from '../components/AdCard';
const adUnitId = __DEV__ ? TestIds.BANNER : 'ca-app-pub-1989790761658370/3852325613';
export default function MainPage({navigation,route}) {
//useState 사용법
//[state,setState] 에서 state는 이 컴포넌트에서 관리될 상태 데이터를 담고 있는 변수
//setState는 state를 변경시킬때 사용해야하는 함수
//모두 다 useState가 선물해줌
//useState()안에 전달되는 값은 state 초기값
const [state,setState] = useState([])
const [cateState,setCateState] = useState([])
//날씨 데이터 상태관리 상태 생성!
const [weather, setWeather] = useState({
temp : 0,
condition : ''
})
//하단의 return 문이 실행되어 화면이 그려진다음 실행되는 useEffect 함수
//내부에서 data.json으로 부터 가져온 데이터를 state 상태에 담고 있음
const [ready,setReady] = useState(true)
useEffect(()=>{
navigation.setOptions({
title:'나만의 !!꿀팁'
})
//뒤의 1000 숫자는 1초를 뜻함
//1초 뒤에 실행되는 코드들이 담겨 있는 함수
setTimeout(()=>{
firebase_db.ref('/tip').once('value').then((snapshot) => {
let tip = snapshot.val();
setState(tip)
setCateState(tip)
getLocation()
setReady(false)
});
// getLocation()
// setState(data.tip)
// setCateState(data.tip)
// setReady(false)
},1000)
},[])
const getLocation = async () => {
//수많은 로직중에 에러가 발생하면
//해당 에러를 포착하여 로직을 멈추고,에러를 해결하기 위한 catch 영역 로직이 실행
try {
//자바스크립트 함수의 실행순서를 고정하기 위해 쓰는 async,await
await Location.requestForegroundPermissionsAsync();
const locationData= await Location.getCurrentPositionAsync();
const latitude = locationData['coords']['latitude']
const longitude = locationData['coords']['longitude']
const API_KEY = "cfc258c75e1da2149c33daffd07a911d";
const result = await axios.get(
`http://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&units=metric`
);
const temp = result.data.main.temp;
const condition = result.data.weather[0].main
//오랜만에 복습해보는 객체 리터럴 방식으로 딕셔너리 구성하기!!
//잘 기억이 안난다면 1주차 강의 6-5를 다시 복습해보세요!
setWeather({
temp,condition
})
} catch (error) {
//혹시나 위치를 못가져올 경우를 대비해서, 안내를 준비합니다
Alert.alert("위치를 찾을 수가 없습니다.", "앱을 껏다 켜볼까요?");
}
}
const category = (cate) => {
if(cate == "전체보기"){
//전체보기면 원래 꿀팁 데이터를 담고 있는 상태값으로 다시 초기화
setCateState(state)
}else{
setCateState(state.filter((d)=>{
return d.category == cate
}))
}
}
//data.json 데이터는 state에 담기므로 상태에서 꺼내옴
// let tip = state.tip;
let todayWeather = 10 + 17;
let todayCondition = "흐림"
//return 구문 밖에서는 슬래시 두개 방식으로 주석
return ready ? <Loading/> : (
<View>
{__DEV__ ? null : (<BannerAd
unitId={adUnitId}
size={BannerAdSize.FULL_BANNER}
requestOptions={{
requestNonPersonalizedAdsOnly: true,
}}
/>)}
<ScrollView style={styles.container}>
<StatusBar style="light" />
{/* <Text style={styles.title}>나만의 꿀팁</Text> */}
<Text style={styles.weather}>오늘의 날!씨: {weather.temp + '°C ' + weather.condition} </Text>
<TouchableOpacity style={styles.AboutPage} onPress={()=>{navigation.navigate('AboutPage')}}>
<Text style={styles.middleButtonText}>소개 페이지</Text>
</TouchableOpacity>
<Image style={styles.mainImage} source={{uri:main}}/>
<ScrollView style={styles.middleContainer} horizontal indicatorStyle={"white"}>
<TouchableOpacity style={styles.middleButtonAll} onPress={()=>{category('전체보기')}}><Text style={styles.middleButtonTextAll}>전!!체보기</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton01} onPress={()=>{category('생활')}}><Text style={styles.middleButtonText}>생활</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton02} onPress={()=>{category('재테크')}}><Text style={styles.middleButtonText}>재테크</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton03} onPress={()=>{category('반려견')}}><Text style={styles.middleButtonText}>반려견</Text></TouchableOpacity>
<TouchableOpacity style={styles.middleButton04} onPress={()=>{navigation.navigate('LikePage')}}><Text style={styles.middleButtonText}>꿀팁 찜</Text></TouchableOpacity>
</ScrollView>
<View style={styles.cardContainer}>
{/* 하나의 카드 영역을 나타내는 View */}
{
cateState.map((content1,i3)=>{
return __DEV__ ? (<Card content8={content1} key={i3} navigation2={navigation}/>) : (<AdCard content8={content1} key={i3} navigation2={navigation}/>)
})
}
</View>
</ScrollView>
</View>)
}
const styles = StyleSheet.create({
container: {
//앱의 배경 색
backgroundColor: '#fff',
},
title: {
//폰트 사이즈
fontSize: 20,
//폰트 두께
fontWeight: '700',
//위 공간으로 부터 이격
marginTop:50,
//왼쪽 공간으로 부터 이격
marginLeft:20
},
weather:{
alignSelf:"flex-end",
paddingRight:20
},
mainImage: {
//컨텐츠의 넓이 값
width:'90%',
//컨텐츠의 높이 값
height:200,
//컨텐츠의 모서리 구부리기
borderRadius:10,
marginTop:20,
//컨텐츠 자체가 앱에서 어떤 곳에 위치시킬지 결정(정렬기능)
//각 속성의 값들은 공식문서에 고대로~ 나와 있음
alignSelf:"center"
},
AboutPage: {
width:120,
height:50,
padding:15,
backgroundColor:"#fdc453",
borderColor:"deeppink",
borderRadius:15,
marginTop: 10,
margin: 10,
alignSelf:"flex-end",
},
middleContainer:{
marginTop:20,
marginLeft:10,
height:60
},
middleButtonAll: {
width:100,
height:50,
padding:15,
backgroundColor:"#20b2aa",
borderColor:"deeppink",
borderRadius:15,
margin:7
},
middleButton01: {
width:100,
height:50,
padding:15,
backgroundColor:"#fdc453",
borderColor:"deeppink",
borderRadius:15,
margin:7
},
middleButton02: {
width:100,
height:50,
padding:15,
backgroundColor:"#fe8d6f",
borderRadius:15,
margin:7
},
middleButton03: {
width:100,
height:50,
padding:15,
backgroundColor:"#9adbc5",
borderRadius:15,
margin:7
},
middleButton04: {
width:100,
height:50,
padding:15,
backgroundColor:"#f886a8",
borderRadius:15,
margin:7
},
middleButtonText: {
color:"#fff",
fontWeight:"700",
//텍스트의 현재 위치에서의 정렬
textAlign:"center"
},
middleButtonTextAll: {
color:"#fff",
fontWeight:"700",
//텍스트의 현재 위치에서의 정렬
textAlign:"center"
},
cardContainer: {
marginTop:10,
marginLeft:10
},
});
AdCard.js 전체코드
import React,{useEffect} from 'react';
import {View, Image, Text, StyleSheet,TouchableOpacity} from 'react-native'
import { useInterstitialAd, TestIds } from 'react-native-google-mobile-ads';
//MainPage로 부터 navigation 속성을 전달받아 Card 컴포넌트 안에서 사용
const adUnitId = __DEV__ ? TestIds.INTERSTITIAL : 'ca-app-pub-1989790761658370/7752445123';
export default function AdCard({content8,navigation2}){
const { isLoaded, isClosed, load, show } = useInterstitialAd(adUnitId, {
requestNonPersonalizedAdsOnly: true,
});
useEffect(() => {
// 카드에 광고를 미리 준비해놓습니다
load();
}, [load]);
useEffect(() => {
if (isClosed) {
// 광고가 끝나면, 또는 광고를 끄면, 다음 목적지로 이동시킵니다.
navigation2.navigate('DetailPage',{idx:content8.idx})
}
}, [isClosed, navigation2]);
return(
//카드 자체가 버튼역할로써 누르게되면 상세페이지로 넘어가게끔 TouchableOpacity를 사용
<TouchableOpacity style={styles.card} onPress={() => {
if (isLoaded) {
show();
} else {
// No advert ready to show yet
navigation2.navigate('DetailPage',{idx:content8.idx})
}
}}>
<Image style={styles.cardImage} source={{uri:content8.image}}/>
<View style={styles.cardText}>
<Text style={styles.cardTitle} numberOfLines={1}>{content8.title}</Text>
<Text style={styles.cardDesc} numberOfLines={3}>{content8.desc}</Text>
<Text style={styles.cardDate}>{content8.date}</Text>
</View>
</TouchableOpacity>
)
}
const styles = StyleSheet.create({
card:{
flex:1,
flexDirection:"row",
margin:10,
borderBottomWidth:0.5,
borderBottomColor:"#eee",
paddingBottom:10
},
cardImage: {
flex:1,
width:100,
height:100,
borderRadius:10,
},
cardText: {
flex:2,
flexDirection:"column",
marginLeft:10,
},
cardTitle: {
fontSize:20,
fontWeight:"700"
},
cardDesc: {
fontSize:15
},
cardDate: {
fontSize:10,
color:"#A6A6A6",
}
});
App.json 전체코드
{
"expo": {
"name": "sparta-myhoneytip-lim",
"slug": "sparta-myhoneytip-lim",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.munaso.spartamyhoneytiplim"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
},
"package": "com.munaso.spartamyhoneytiplim"
},
"web": {
"favicon": "./assets/favicon.png"
},
"plugins": [
[
"expo-build-properties",
{
"ios": {
"useFrameworks": "static"
}
}
]
],
"extra": {
"eas": {
"projectId": "ff397b48-1c85-4853-a1a5-17b4d0403331"
}
}
},
"react-native-google-mobile-ads": {
"android_app_id": "ca-app-pub-1989790761658370~7622930108",
}
}
eas.json 전체코드
{
"cli": {
"version": ">= 2.4.1"
},
"build": {
"development": {
"distribution": "internal",
"android": {
"buildType": "apk"
}
},
"preview": {
"distribution": "internal"
},
"production": {}
},
"submit": {
"production": {}
}
}
* 겪고 있는 문제 상황을 최대한 자세하게 작성해주세요.
* 문제 해결을 위해 어떤 시도를 해보았는지 구체적으로 함께 알려주세요.
