본문 바로가기
안드로이드 자바

[Java][Android] 주소검색 API(kakao) 이용하기

by teamnova 2021. 4. 5.

이번시간에는 카카오에서 제공하는 주소검색 API를 이용하여 주소를 입력해보도록하겠습니다.

 

스틱코드 (stickode.com/mainlogin.html)

스틱코드 플러그인을 사용해서  빠르게 구현해보도록 하겠습니다.

 

스틱코드는 자주쓰는 코드를 저장해서 쉽고 빠르게 사용할 수 있고,

다른사람들의 코드도 즐겨찾기를 통해 쉽게 내코드로 등록하여 사용할 수 있어 사용하는 사람이 늘어나고, 

좋은 코드가 쌓일수록 강력해지는 플러그인 입니다.

 

자그럼 시작하겠습니다.

 

프로젝트 생성

빈 프로젝트를 생성해줍니다. 

 

 

권한설정

WebView를 사용해서 주소검색창을 띄울거기 때문에

AndroidManifest.xml 파일 안에 Internet 권한을 추가해주어야 합니다.

<!-- 인터넷 권한 설정   -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 인터넷 연결 확인-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

 

주소 액티비티 생성

 

다음과 같이 주소 액티비티를 생성해줍니다.

 

XML 파일 설정

이제 메인액티비티와 주소검색창을 띄워줄 액티비티의 레이아웃을 설정해주도록 하겠습니다. 

 

main XML

<?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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:text="주소입력"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <EditText
        android:id="@+id/edit_addr"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:ems="10"
        android:hint="주소를 입력해주세요."
        android:inputType="textPersonName"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView2" />


</androidx.constraintlayout.widget.ConstraintLayout>

주소API XML

<?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"
    tools:context=".AddressApiActivity">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

PHP서버

WebView로 주소 검색창을 띄울 거라서 띄워줄 html 파일이 필요합니다.

 

사실상 html 파일에서 javascript를 통해 주소검색api를 사용하신다고 생각하시면 됩니다.

 

저는 개인적으로 사용하는 서버로 테스트를 진행하였습니다.

로컬에 서버를 구축하시거나, aws를 빌려 서버를 구축하시거나, 

무로 호스팅 서버를 빌려 테스트 해보시기 바랍니다. 

 

서버에 html 파일을 생성해 주겠습니다. 

daum.html 

<!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 fullAddr = data.address; // 최종 주소 변수
                var extraAddr = ''; // 조합형 주소 변수

                // 기본 주소가 도로명 타입일때 조합한다.
                if(data.addressType === 'R'){
                    //법정동명이 있을 경우 추가한다.
                    if(data.bname !== ''){
                        extraAddr += data.bname;
                    }
                    // 건물명이 있을 경우 추가한다.
                    if(data.buildingName !== ''){
                        extraAddr += (extraAddr !== '' ? ', ' + data.buildingName : data.buildingName);
                    }
                    // 조합형주소의 유무에 따라 양쪽에 괄호를 추가하여 최종 주소를 만든다.
                    fullAddr += (extraAddr !== '' ? ' ('+ extraAddr +')' : '');
                }
				
				
				var fullRoadAddr = data.roadAddress; // 도로명 주소 변수
                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 !== ''){
                    extraRoadAddr = ' (' + extraRoadAddr + ')';
                }
                // 도로명, 지번 주소의 유무에 따라 해당 조합형 주소를 추가한다.
                if(fullRoadAddr !== ''){
                    fullRoadAddr += extraRoadAddr;
                }				

				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>
	

이제 안드로이드에서 준비를 해보도록 하겠습니다. 

 

MainActivity 부터 셋팅해보도록 하겠습니다.

인터넷이 연결 예외처리

webView로 띄워 주기때문에 인터넷 연결이 되어있을때만 실행될 수 있게 예외처리를 해주려고합니다.

 

스틱코드에 등록해두면 손쉽게 코드작성을 할 수 있습니다.

 

먼저 인터넷을 체크할 수 있는 클래스 파일을 만들어주겠습니다.

이렇게 생긴 클래스 파일에서 스틱코드를 사용해 클래스 파일을 셋팅해보겠습니다.
출처 : stickode.com/detail.html?no=1923

package com.example.httpurlconnectionexample;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

public class NetworkStatus {
    public static final int TYPE_WIFI = 1;
    public static final int TYPE_MOBILE = 2;
    public static final int TYPE_NOT_CONNECTED = 3;

    public static int getConnectivityStatus(Context context){ //해당 context의 서비스를 사용하기위해서 context객체를 받는다.
        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE);

        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
        if(networkInfo != null){
            int type = networkInfo.getType();
            if(type == ConnectivityManager.TYPE_MOBILE){//쓰리지나 LTE로 연결된것(모바일을 뜻한다.)
                return TYPE_MOBILE;
            }else if(type == ConnectivityManager.TYPE_WIFI){//와이파이 연결된것
                return TYPE_WIFI;
            }
        }
        return TYPE_NOT_CONNECTED;  //연결이 되지않은 상태
    }
}

그럼 다음과 같이 코드가 단번에 완성됩니다.

 

이제 인터넷 연결을 체크할 곳에 코드를 추가해보겠습니다.

마찬가지로 스틱코드로 셋팅을 해보겠습니다.

int status = NetworkStatus.getConnectivityStatus(getApplicationContext());
if(status == NetworkStatus.TYPE_MOBILE || status == NetworkStatus.TYPE_WIFI) {

}else {
Toast.makeText(getApplicationContext(), "인터넷 연결을 확인해주세요.", Toast.LENGTH_SHORT).show();
}

이렇게 만들어진 예외처리 안에 통신을 넣으면  

인터넷 연결 예외처리가 완료되었습니다.

출처 : stickode.com/detail.html?no=1923

 

이제 WebView 가있는 페이지로 넘어갈 Intent를 설정해주겠습니다. 

 

마찬가지로 스틱코드로 설정해보겠습니다.

이렇게 선택하면 

다음과 같이 완성됩니다. 

(SEARCH_ADDRESS_ACTIVITY 상수 선언은 코드 상단으로 올려주었습니다.)

 

이제 응답받는 부분도 셋팅해보겠습니다.

코드 하단으로 이동하셔서 

 

스틱코드를 사용하면

다음과 같이 응답부분도 셋팅이 되었습니다.

 

MainActivity 설정이 끝났습니다. 

이제 Intent를 받을 AddressApiActivity 에 설정을 해주겠습니다.

 

인터페이스 클래스를 생성해주고,

 

onCreate 에서  webView가 실행될 수 있도록 설정해주겠습니다. 

 

출처 : stickode.com/detail.html?no=1998

 

스틱코드

 

stickode.com

 

이제 셋팅은 완료되었고, 

문제가 없다면 data로 webView에서 선택한 주소 값이 넘어올 겁니다.

 

data를 주소 검색 EditText 에 넣어주도록 하겠습니다.

 

다음은 MainActivity.class 전문입니다.

package com.example.addressapiexample;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;


public class MainActivity extends AppCompatActivity {

    // 초기변수설정
    EditText edit_addr;
    // 주소 요청코드 상수 requestCode
    private static final int SEARCH_ADDRESS_ACTIVITY = 10000;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // UI 요소 연결
        edit_addr = findViewById(R.id.edit_addr);

        // 터치 안되게 막기
        edit_addr.setFocusable(false);
        // 주소입력창 클릭
        edit_addr.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.i("주소설정페이지", "주소입력창 클릭");
                int status = NetworkStatus.getConnectivityStatus(getApplicationContext());
                if(status == NetworkStatus.TYPE_MOBILE || status == NetworkStatus.TYPE_WIFI) {

                    Log.i("주소설정페이지", "주소입력창 클릭");
                    Intent i = new Intent(getApplicationContext(), AddressApiActivity.class);
                    // 화면전환 애니메이션 없애기
                    overridePendingTransition(0, 0);
                    // 주소결과
                    startActivityForResult(i, SEARCH_ADDRESS_ACTIVITY);

                }else {
                    Toast.makeText(getApplicationContext(), "인터넷 연결을 확인해주세요.", Toast.LENGTH_SHORT).show();
                }


            }
        });

    }

    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
            super.onActivityResult(requestCode, resultCode, intent);
            Log.i("test", "onActivityResult");

            switch (requestCode) {
                case SEARCH_ADDRESS_ACTIVITY:
                    if (resultCode == RESULT_OK) {
                        String data = intent.getExtras().getString("data");
                        if (data != null) {
                            Log.i("test", "data:" + data);
                            edit_addr.setText(data);
                        }
                    }
                    break;
            }
    }


}

AddressApiActivity.class 전문입니다.

package com.example.addressapiexample;


import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class AddressApiActivity extends AppCompatActivity {

    private WebView webView;

    class MyJavaScriptInterface
        {
            @JavascriptInterface
            @SuppressWarnings("unused")
            public void processDATA(String data) {
                Bundle extra = new Bundle();
                Intent intent = new Intent();
                extra.putString("data", data);
                intent.putExtras(extra);
                setResult(RESULT_OK, intent);
                finish();
            }
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_address_api);

        webView = (WebView) findViewById(R.id.webView);
                webView.getSettings().setJavaScriptEnabled(true);
                webView.addJavascriptInterface(new MyJavaScriptInterface(), "Android");

                webView.setWebViewClient(new WebViewClient() {
                    @Override
                    public void onPageFinished(WebView view, String url) {
                        webView.loadUrl("javascript:sample2_execDaumPostcode();");
                    }
                });

        webView.loadUrl("your server url");


    }
}



 

마지막으로 테스트를 진행해보도록 하겠습니다. 

주소검색 API(kakao) 를 간단하게 사용해보았습니다. 

이 예제에서 사용된 스틱코드

출처 : stickode.com/detail.html?no=1998 - 안드로이드 카카오 주소검색 api

출처 : stickode.com/detail.html?no=1923 - 인터넷 연결확인, 네트워크 상태 체크