🎉 개요
프로젝트에서 Kakao MAP API를 사용하기 이전에 지도를 통해 위치 정보를 정확하게 보여주려면 위도와 경도가 필요합니다. 그러기 위해선 오타 등의 이유로 사용자에게 주소를 직접 입력 받는 것 보단 우편번호 API를 사용하는 방식이 더 안전할 것 이라고 생각해 사용하게 되었습니다.
🚨 Warning !
- Node.js는 설치 되었단 가정하에 진행합니다
- Window 환경에서 진행되었습니다.
- 이 API는 JS만으로 제공되기 때문에 안드로이드에서 Retrofit 등을 사용해 직접 연동이 불가능합니다.
- 이를 해결하기 위해 FireBase Host 서비스를 사용해 호스팅한 후 Web View를 통해 보여줄겁니다.
FireBase Hosting이란 ?
정적 파일(HTML, CSS, JavaScript 등)을 호스팅하고 배포하는 서비스를 말합니다.
파이어베이스 호스팅을 사용하면 사용자는 서버 셋업 및 유지 관리에 대해 걱정할 필요 없이 손쉽게 웹 앱을 배포할 수 있습니다.
🎉 API 연동
https://console.firebase.google.com/
✅ 파이어 베이스에 접속해 로그인 후 프로젝트를 생성해 줍니다.
✅ 왼쪽 메뉴에서 Hosting을 선택 해줍니다.
✅ CLI 설치 코드를 복사해줍니다
✅ 원하는 위치에 작업용 폴더를 하나 생성합니다.
✅ cmd창을 열고 해당 폴더 위치로 이동 후 CLI 코드를 입력해 설치합니다.
//폴더 이동 명령어
cd
// CLI 설치
npm install -g firebase-tools
✅ 아래와 같이 설치가 완료 되었다면 아래와 같이 진행해줍니다.
$ firebase login // 새 창이 뜸
// init 을 입력하면 yes > Hosting : Configure files
// for Firebase Hosting and (optionally) set up Github Action deploys 선택
$ firebase init
✅ public 폴더에 있는 index.html을 수정 후 deploy 합니다.
firebase deploy
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<!-- HELLO DAUM! -->
<!-- iOS에서는 position:fixed 버그가 있음, 적용하는 사이트에 맞게 position:absolute 등을 이용하여 top,left값 조정 필요 -->
<div id="layer" style="display:block;position:fixed;overflow:hidden;z-index:1;-webkit-overflow-scrolling:touch;">
</div>
<script src="https://t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
<!-- <script src="http://dmaps.daum.net/map_js_init/postcode.v2.js"></script> -->
<script>
window.addEventListener("message", onReceivedPostMessage, false);
function onReceivedPostMessage(event){
//..ex deconstruct event into action & params
var action = event.data.action;
var params = event.data.params;
console.log("onReceivedPostMessage "+event);
}
function onReceivedActivityMessageViaJavascriptInterface(json){
//..ex deconstruct data into action & params
var data = JSON.parse(json);
var action = data.action;
var params = data.params;
console.log("onReceivedActivityMessageViaJavascriptInterface "+event);
}
// 우편번호 찾기 화면을 넣을 element
var element_layer = document.getElementById('layer');
function sample2_execDaumPostcode() {
new daum.Postcode({
oncomplete: function(data) {
var fullRoadAddr = data.roadAddress ? data.roadAddress : data.autoRoadAddress;
var extraRoadAddr = ''; // 도로명 조합형 주소 변수
// 법정동명이 있을 경우 추가한다. (법정리는 제외)
// 법정동의 경우 마지막 문자가 "동/로/가"로 끝난다.
if(data.bname !== '' && /[동|로|가]$/g.test(data.bname)){
extraRoadAddr += data.bname;
}
// 건물명이 있고, 공동주택일 경우 추가한다.
if(data.buildingName !== '' && data.apartment === 'Y'){
extraRoadAddr += (extraRoadAddr !== '' ? ', ' + data.buildingName : data.buildingName);
}
// 도로명, 지번 조합형 주소가 있을 경우, 괄호까지 추가한 최종 문자열을 만든다.
if(extraRoadAddr !== ''){
fullRoadAddr += ' (' + extraRoadAddr + ')';
}
var jibunAddr = data.jibunAddress ? data.jibunAddress : data.autoJibunAddress;
window.Android.processDATA(fullRoadAddr); // data.zonecode + ", " +
},
width : '100%',
height : '100%'
}).embed(element_layer);
// iframe을 넣은 element를 보이게 한다.
element_layer.style.display = 'block';
// iframe을 넣은 element의 위치를 화면의 가운데로 이동시킨다.
initLayerPosition();
}
// 브라우저의 크기 변경에 따라 레이어를 가운데로 이동시키고자 하실때에는
// resize이벤트나, orientationchange이벤트를 이용하여 값이 변경될때마다 아래 함수를 실행 시켜 주시거나,
// 직접 element_layer의 top,left값을 수정해 주시면 됩니다.
function initLayerPosition(){
var width = (window.innerWidth || document.documentElement.clientWidth); //우편번호서비스가 들어갈 element의 width
var height = (window.innerHeight || document.documentElement.clientHeight); //우편번호서비스가 들어갈 element의 height
var borderWidth = 5; //샘플에서 사용하는 border의 두께
// 위에서 선언한 값들을 실제 element에 넣는다.
element_layer.style.width = width + 'px';
element_layer.style.height = height + 'px';
element_layer.style.border = borderWidth + 'px solid';
// 실행되는 순간의 화면 너비와 높이 값을 가져와서 중앙에 뜰 수 있도록 위치를 계산한다.
element_layer.style.left = (((window.innerWidth || document.documentElement.clientWidth) - width)/2 - borderWidth) + 'px';
element_layer.style.top = (((window.innerHeight || document.documentElement.clientHeight) - height)/2 - borderWidth) + 'px';
}
</script>
</body>
</html>
🎉 Android Setting
✅ Web View를 띄워줄 Activity를 만들어 줍니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
✅ Activity 코드를 작성합니다.
webView.loadUrl( ) 의 파라미터는 개인 FireBase Host Domain을 입력합니다.
class AddressActivity : AppCompatActivity() {
private lateinit var binding: ActivityAddressBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAddressBinding.inflate(layoutInflater)
setContentView(binding.root)
val webView = binding.webView
webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(BridgeInterface(), "Android")
webView.webViewClient = object: WebViewClient(){
//2. 페이지가 로드 되었을 때
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
// android->javascript
webView.loadUrl("javascript:sample2_execDaumPostcode();")
}
}
//1.
// 최초 웹뷰 로드
webView.loadUrl(개인 Host Domain)
}
inner class BridgeInterface{
@JavascriptInterface
fun processDATA(data: String){
// 카카오 주소 검색 API 결과를 브릿지 경로를 통해 전달 받는다(from Javascript)
val intent = Intent()
intent.putExtra("data", data)
setResult(ADDR_RESULT, intent)
finish()
}
}
}
✅ 위 Activity 호출할 Activity나 Fragment를 생성합니다. 저는 Fragment에서 실행했습니다.
btnAddr.setOnClickListener {
val intent = Intent(requireContext(), AddressActivity::class.java)
launcher.launch(intent)
}
val launcher = registerForActivityResult(
// AddrActivity 로부터 결과값을 전달 받음
ActivityResultContracts.StartActivityForResult()){ result ->
if (result.data != null){
when(result.resultCode){
// ADDR_RESULT : 1001
ADDR_RESULT -> {
val data = result.data!!.getStringExtra("data")
binding.addrEdit.setText(data)
}
}
}
'Android' 카테고리의 다른 글
[Android] Jetpack WorkManager (0) | 2024.01.07 |
---|---|
[Android]Android Memory Process (1) | 2024.01.07 |
Android Base64 Decoding (0) | 2024.01.03 |
Anroid Jetpack [ ViewBinding ] (0) | 2024.01.02 |
Android LayoutInflater (1) | 2023.12.26 |