DUI (Deajeon University Introduction app)
프로젝트 : DUI (Deajeon University Introduction app)
포트폴리오 주소: https://github.com/nohhyeon/Fidecosemi.git
수행 기간: 2023.03 ~ 2023.11
수행 인원: 3명
프로젝트 목표/소개
신입생과 처음 학교를 방문한 사람들을 위해 학교의 편의시설을 쉽게 찾을 수 있도록 카테고리별로 장소를 나누고, 해당 카테고리를 누르면 마커핀을 통해 장소의 명칭과 위치를 확인할 수 있게 합니다. 또한, 마커핀을 길게 누르면 상세 정보 표시, 익명성을 보장하는 게시판 기능 제공.
개발 환경 (사용 도구/언어)
Firebase,
Swift,
CocoaPods,
Firebase Realtime Database,
Google Maps,
Xcode,
macOS

담당 역할
- 프로젝트 팀장으로서 iOS 앱의 전체적인 개발 구성과 기획
- Firebase Database를 사용하여 게시판과 Google Maps에서 마커핀 정보 출력 기능 구현
블록 다이어그램

시연 영상
[영상 1] - 위치정보의 표시와 상단 카테고리에 따라 마커핀이 표시가 다르게 되고 마커핀 클릭시 상세 정보가 나오는 작동 화면을 보여줍니다.
[영상 2] - UUID로 게시판에 고유의 정보로 글 작성과 삭제 권환이 있는 것을 보여줍니다.
실행화면 및 상세설명, 주요 코드

import UIKit
class Define: Any {
// "~~~~~~" 개인정보라 가려둠
// KEY
static let GOOGLE_API_KEY = "~~~~~~"
static let MAP_ID = "~~~~~~"
// OpenWeatherMap API 엔드포인트 및 API 키
static let apiKey = "~~~~~~"
static let endpoint = "~~~~~~"
static let city = "Daejeon, KR" // 날씨 정보를 얻고자 하는 도시
// 구글지도 좌표계 -> WGS 84 (교내 편의시설 기본 좌표)
static let LAT_001 = 36.336059
static let LONG_001 = 127.459963
// 구글지도 좌표계 -> WGS 84 (주변 음식점 기본 좌표)
static let LAT_002 = 36.335088
static let LONG_002 = 127.457517
static let BOARD_REG_DATE_TYPE = "yyyyMMddHHmmss"
}

import UIKit
import Firebase
import FirebaseDatabase
class ResMapdetailViewController: UIViewController {
@IBOutlet weak var contentTextView: UITextView!
@IBOutlet weak var contentTextFied: UITextField!
var ref: DatabaseReference!
var categoryName: String = "" // 카테고리 정보
var Atitle: String = "" //
var cam: String = ""
override func viewDidLoad() {
super.viewDidLoad()
// Firebase Database Reference 가져오기
ref = Database.database().reference()
// 제목 필드의 테두리 스타일 설정
contentTextFied.layer.borderWidth = 1.0 // 테두리 두께
contentTextFied.layer.borderColor = UIColor.gray.cgColor // 테두리 색상
contentTextFied.layer.cornerRadius = 5.0 // 테두리 모서리 반경
contentTextFied.isEnabled = false // 읽기 전용
// 내용 필드의 테두리 스타일 설정
contentTextView.layer.borderWidth = 1.0 // 테두리 두께
contentTextView.layer.borderColor = UIColor.gray.cgColor // 테두리 색상
contentTextView.layer.cornerRadius = 5.0 // 테두리 모서리 반경
contentTextView.isEditable = false // 읽기 전용
// placeID가 존재하면 데이터를 가져와서 표시
self.fetchPlaceDetails()
}
// Firebase에서 장소 정보 가져와 텍스트 뷰에 출력하는 함수
func fetchPlaceDetails() {
// Firebase 데이터베이스에서 placeID에 해당하는 장소의 정보를 가져옵니다.
ref.child(cam).child(categoryName).child(Atitle).observe(.value) { (snapshot) in
if let placeData = snapshot.value as? [String: Any],
let title = placeData["title"] as? String,
let content = placeData["content"] as? String {
// 가져온 정보를 텍스트 뷰에 설정
let Info = "\(content)"
self.contentTextView.text = Info
let PlaceName = "\(title)"
self.contentTextFied.text = PlaceName
}
else { print("error")
self.contentTextView.text = "Info가 포함되어 있지 않습니다."
self.contentTextFied.text = "PlaceName이 포함되어 있지 않습니다."
}
}
}
}

import UIKit
import Foundation
import Firebase
import FirebaseDatabase
struct ShowBoard {
var sUID: String = ""
var sTitle: String = ""
var sContext: String = ""
var sRegDate: String = ""
}
class ShowViewController: UIViewController {
@IBOutlet weak var txViewTitle: UITextField!
@IBOutlet weak var txViewMessage: UITextView!
var ref: DatabaseReference!
var boardID: String = ""
var UUID: String = ""
var aUID: String = ""
var uuid = AppStorage.sharedInstance.getUUID()
override func viewDidLoad() {
super.viewDidLoad()
// Firebase Database Reference 가져오기
self.ref = Database.database().reference()
// 제목 필드의 테두리 스타일 설정
txViewTitle.layer.borderWidth = 1.0 // 테두리 두께
txViewTitle.layer.borderColor = UIColor.gray.cgColor // 테두리 색상
txViewTitle.layer.cornerRadius = 5.0 // 테두리 모서리 반경
txViewTitle.isEnabled = false // 읽기 전용
// 내용 필드의 테두리 스타일 설정
txViewMessage.layer.borderWidth = 1.0 // 테두리 두께
txViewMessage.layer.borderColor = UIColor.gray.cgColor // 테두리 색상
txViewMessage.layer.cornerRadius = 5.0 // 테두리 모서리 반경
txViewMessage.isEditable = false // 읽기 전용
// Firebase 데이터 가져오기
self.ShowFirebaseBoard(ID: boardID)
// 삭제 버튼 생성
let DeleteBarButtonItem = UIBarButtonItem(
title: "삭제",
style: .plain,
target: self,
action: #selector(DeleteBarButtonTapped)
)
// 네비게이션 바 오른쪽에 버튼 추가
navigationItem.rightBarButtonItem = DeleteBarButtonItem
}
// Firebase에서 데이터를 가져오는 메소드
func ShowFirebaseBoard(ID: String) {
self.ref.child("게시판").child(ID).observe(.value) { (snapshot) in
print("---------")
print("id : \(ID)")
print("ref : \(String(describing: self.ref.child("게시판")))")
if let data = snapshot.value as? [String: Any],
let UID = data["UID"] as? String,
let title = data["title"] as? String,
let context = data["context"] as? String,
let regDate = data["regDate"] as? String {
var abc = ShowBoard.init()
abc.sUID = UID
abc.sTitle = title
abc.sContext = context
abc.sRegDate = regDate
print("UID : \(abc.sUID)")
print("Title : \(abc.sTitle)")
print("Context : \(abc.sContext)")
print("regDate : \(abc.sRegDate)")
self.UUID = abc.sUID
// UI 업데이트
self.txViewTitle.text = abc.sTitle
self.txViewMessage.text = abc.sContext
}
}
}


// 최단경로
func directionTest() {
// 일본(한국은 휴전국가로 구글에서 경로 정보를 불러올 수 없어서 일본으로 테스트)
let originLatitude = 34.03887901056528 // 시작 위도
let originLongitude = 131.8512689120819 // 시작 경도
let destinationLatitude = 43.1368075169225 // 도착 위도
let destinationLongitude = 141.42493501345194 // 도착 경도
let origin = "\(originLatitude),\(originLongitude)"
let destination = "\(destinationLatitude),\(destinationLongitude)"
// 구글 API로 경로 정보 불러오는기
let directionsURL = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&key=\(Define.GOOGLE_API_KEY)"
print("DirectionsURL : \(directionsURL)")
if let url = URL(string: directionsURL) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let data = data {
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
if let routes = json["routes"] as? [[String: Any]] {
if let route = routes.first,
let overviewPolyline = route["overview_polyline"] as? [String: String],
let points = overviewPolyline["points"] {
// Decode the polyline points and create a GMSPolyline
if let path = GMSPath(fromEncodedPath: points) {
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 3.0
polyline.map = self.mapView
}
}
}
}
} catch {
print("Error parsing JSON: \(error)")
}
}
}.resume()
}
}
댓글남기기