브이월드 배경지도와 개방해의 WFS 오픈API를
이용한 스마트폰 어플 만들기에 대해 설명합니다.
스마트폰 개발환경 세팅이 잘 마무리가 되었다면 이제 브이월드 배경지도와 개방해 오픈API를 호출하여 스마트폰 어플을 개발해보겠습니다. 중요한 부분의 소스코드는 본문에 주석으로 설명될것이고 가이드라인의 최하단엔 직접 프로젝트 소스를 다운로드 받을수있게 제공하겠습니다.
※ 스마트폰 어플 개발하기는 iOS개발환경의 제약성으로인해 안드로이드 개발환경에서 진행됩니다.
- 이클립스 실행상태에서 파일 -> New -> other -> Android -> Android Application Project 선택 -> Next 를 클릭합니다.
- Application Name 란에 'openApiSample' 이라고 적어주고 다음으로 넘어갑니다.
- Create activity 란 체크를 해제하고 다음으로 넘어갑니다.
- Finish 버튼이 나올때까지 다음으로 넘어가고 마지막으로 Finish버튼을 눌러 프로젝트를 생성합니다. 왼쪽 Package Explorer 에 이번에 생성한 프로젝트가 만들어졌습니다.
- 프로젝트 하위구조 src에서 오른쪽마우스클릭 -> New -> Class 선택합니다.
- Name항목에 'OpenApi_Activity' 작성 후 Finish 버튼 클릭합니다.
- OpenApi_Activity.java 파일이 생성된것을 확인합니다. 이제 이파일에서 작업하는 내용은 안드로이드에서 제공하는 Activity 클래스를 상속받아 화면으로 나타나게 될것입니다.
- OpenApi_Activity.java 파일을 아래와 같이 작성합니다. 소스코드에 대한 설명은 주석으로 작성하겠습니다.
package openApiSample; import android.app.Activity; import android.os.Bundle; import android.webkit.WebView; import com.example.openapisample.R; public class OpenApi_Activity extends Activity { // WebView를 통해 opneApi.html 파일을 파싱하여 화면에 뿌려줍니다. WebView mWebView; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // res/layout/openapi_activity.xml의 레이아웃을 사용합니다. setContentView(R.layout.openapi_activity); mWebView = (WebView) findViewById(R.id.webView); // opneApi.html 파일은 assets 디렉토리에 저장하여 사용합니다. mWebView.loadUrl("file:///android_asset/openApi.html"); // WebView에서 javascirpt가 실행될 수 있게 설정 합니다. mWebView.getSettings().setJavaScriptEnabled(true); } }
- 프로젝트 하위구조 res/layout에서 오른쪽마우스클릭 -> New -> Android XML File을 선택합니다.
- File항목에 'openapi_activity.xml' 작성 후 Finish 버튼을 클릭합니다.
- res/layout 디렉토리에 openapi_activity.xml 파일이 생성된것을 확인합니다. 해당 디렉토리에 생성되는 xml파일은 안드로이드 화면 구성의 레이아웃 파일입니다.
OpenApi_Activity.java 소스 14번 라인의 코드로 openapi_activity.xml과 연결되는것을 알 수 있습니다.
- openapi_activity.xml 파일을 아래와 같이 작성합니다.
상단에 TextView를 배치하고 하단의 남는 모든 영역을 WebView영역으로 배치 했습니다.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="선상낚시포인트 WFS" /> <WebView android:id="@+id/webView" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
- 프로젝트 하위구조 assets에서 오른쪽마우스클릭 -> New -> File을 선택합니다.
- File name항목에 'openApi.html' 작성 후 Finish 버튼을 클릭합니다.
- assets 디렉토리에 openApi.html 파일이 생성된것을 확인합니다.
WebView에서 해당 html파일을 파싱하여 스마트폰 화면상에 뿌려줍니다. 이 파일에 우리는 브이월드 배경지도와 개방海의 WFS 오픈API를 호출하여 지도서비스를 제공합니다.
- openApi.html 파일을 아래와 같이 작성합니다.
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>WFS Test</title> <script type="text/javascript" src="js/jquery-3.1.1.min.js"></script> <script type="text/javascript" src="js/OpenLayers.js"></script> <!-- 브이월드 지도 서비스 호출 --> <SCRIPT language="JavaScript" type="text/javascript" src="http://map.vworld.kr/js/apis.do?type=Base&apiKey=브이월드에서받은apiKey값&domain=브이월드에서apiKey신청시등록한도메인값"></SCRIPT> <script type="text/javascript"> var map; // 지도의 영역을 지정 var mapBounds = new OpenLayers.Bounds(123 , 32, 132 , 43); // avoid pink tiles OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3; OpenLayers.Util.onImageLoadErrorColor = "transparent"; function init(){ var options = { projection: new OpenLayers.Projection("EPSG:900913"), displayProjection: new OpenLayers.Projection("EPSG:4326"), controls : [], // 사용자 이벤트 등록 eventListeners: { featureover: function(e) { // feature에 마우스오버시 e.feature.renderIntent = "select"; e.feature.layer.drawFeature(e.feature); console.log("featureover"); }, featureout: function(e) { // feature에 마우스아웃시 e.feature.renderIntent = "default"; e.feature.layer.drawFeature(e.feature); console.log("featureout"); }, featureclick: function(e) { // feature에 마우스클릭시 console.log("featureclick e.feature.id = " + e.feature.id); } } }; map = new OpenLayers.Map('map', options); // html의 'map'div 태그에 지도를 그려주도록 세팅 // 배경지도 추가하기 vBase = new vworld.Layers.Base('VBASE'); if (vBase != null){map.addLayer(vBase);} // 지정된 바운드로 줌 map.zoomToExtent( mapBounds.transform(map.displayProjection, map.projection ) ); // 지도 센터 설정 map.setCenter(127.1141382, 37.3599968); // 지도 초기 레벨 설정 map.zoomTo(7); // 지도컨트롤등록 map.addControl(new OpenLayers.Control.MousePosition()); map.addControl(new OpenLayers.Control.Navigation()); // 개방海 WFS 오픈API 호출 getWFS(); } function getWFS() { var layerName = "TB_YACHT_SPOINT"; // 개방海 선상낚시포인트 레이어 지정 var url = "http://www.khoa.go.kr/oceanmap/otmsWfsApi.do"; url += "?ServiceKey=개방해에서부여받은 ServiceKey값"; url += "&Layer=" + layerName; $.ajax({ async:true, cache:false, type:"GET", url:encodeURI(url), data:{ }, dataType:"text", success:function(response) { // 정상적으로 데이터를 받아오면 받은 데이터를 파싱하여 지도상에 feature배열을 그려준다. parseGML(response, layerName); }, error:function(response) { // 데이터를 받아오지 못했을때 에러처리 alert("처리오류로 인해 WFS정보를 가져오지 못했습니다."); } }); } function parseGML(response, layerName) { // WFS GML의 값을 파싱하여 features 배열에 저장 var features; var g = new OpenLayers.Format.GML(); features = g.read(response); // features를 그려줄 랜더러 설정 var renderer = OpenLayers.Util.getParameters(window.location.href).renderer; renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers; // features가 그려질 레이어 세팅 var layer = new OpenLayers.Layer.Vector(layerName, { styleMap: "", renderers: renderer }); // 레이어에 features add layer.addFeatures(features); // 지도에 레이어 add map.addLayer(layer); // 지도 이벤트 등록 selectControl = new OpenLayers.Control.SelectFeature(layer); map.addControl(selectControl); selectControl.activate(); layer.events.on({ 'featureselected': onFeatureSelect, 'featureunselected': onFeatureUnselect }); // 속성정보 팝업 X버튼 클릭시 호출 function onPopupClose(evt) { var feature = this.feature; if (feature.layer) { selectControl.unselect(feature); } else { this.destroy(); } } // 마우스로 선택된 feature가 받는 이벤트 function onFeatureSelect(evt) { feature = evt.feature; popup = new OpenLayers.Popup.FramedCloud("featurePopup", feature.geometry.getBounds().getCenterLonLat(), new OpenLayers.Size(100,100), "<h2>"+feature.data.POINT_NM + "</h2>" + feature.data.ADR_KNM, null, true, onPopupClose); feature.popup = popup; popup.feature = feature; map.addPopup(popup, true); } // 마우스로 선택되지 않은 feature들이 받는 이벤트 function onFeatureUnselect(evt) { feature = evt.feature; if (feature.popup) { popup.feature = null; map.removePopup(feature.popup); feature.popup.destroy(); feature.popup = null; } } } </script> </head> <body onload="init()"> <div id="map" style="height:600px;"></div> </body> </html>
- AndroidManifest.xml 파일을 엽니다. 해당파일은 안드로이드 어플의 설정에 관한 내용을 정의한 파일입니다. 우리는 이곳에서 앱이 실행될때 최초로 출력될 화면에 대한 설정, 브이월드 지도 서비스와 오픈API를 네트워크를 통해 가져오기 위한 '인터넷사용'에 대한 퍼미션 허용 세팅법을 알아보겠습니다.
- AndroidManifest.xml 파일을 아래와 같이 작성합니다.
- 7~12 라인은 안드로이드 어플이 실행될때 처음으로 보여질 Activity 화면을 설정하는 코드입니다. 해당 설정은 OpenApi_Activity.java 화면이 최초의 화면으로 설정되었습니다.
- 16 라인은 안드로이드 어플에게 인터넷사용 허가권을 부여하는 퍼미션 제어라인 입니다. 'android.permission.INTERNET' 퍼미션 외에 GPS사용허용, 주소록접근권한허용, 카메라제어허용 등 여러가지 옵션이 있습니다.
- 마지막으로 이제 assets 디렉토리에 jquery파일, Openlayers파일을 복사하여 넣어줍니다. 해당파일들은 '오픈API를 이용한 웹서비스 개발하기'란에서 설명되어 있습니다.
- jquery-3.1.1.min.js : jQuery파일
- OpenLayers.js, img디렉토리, theme디렉토리 : openlayers파일
※ 해당파일들을 복사한후 이클립스상의 assets 디렉토리에는 해당파일 목록이 갱신되지 않을수 있습니다. 이때 assets 디렉토리를 선택한후 F5키를 눌러주면 목록이 갱신됩니다.
- 이제 안드로이드 어플 개발은 마무리가 되었습니다. 앞으로 남은일은 어플을 올릴 스마트폰을 준비하고 PC와 USB로 연결하여 어플을 실행하면 됩니다. 하지만 그 중간에 거쳐야할 사항이 있습니다. 스마트폰의 설정을 변경해야하는 작업이 남았습니다.
- 어플을 올릴 스마폰에서 설정 -> 보안 -> 출처를 알 수 없는 앱 -> 허용체크 를 해줍니다.
- 스마트폰을 PC와 연결한후 프로젝트 오론쪽 마우스클릭 -> Run AS -> Android Application 선택합니다.
- 개발한 어플을 올릴 스마트폰을 선택해줍니다.
- 잠시후 스마트폰에 우리가 만든 어플이 올라가고 실행됩니다. 최종적으로 아래와 같은 화면이 나온다면 정상적으로 마무리가 된것입니다.
이제 스마트폰 어플 개발이 완료되었습니다. 이번 가이드라인에서 안내한 내용을 반복하고 이해하면서 자신의 것으로 만들고 응용하면 다른형태의 훌륭한 스마트폰 어플 개발을 할 수 있습니다. 일반 사용자들에게 공개된 여러가지 오픈API들을 이용하여 좋은 서비스를 제공할 수 있는 기회가 되면 좋겠습니다.
※ 해당 프로젝트 파일은 '여기'를 클릭하면 다운로드 받을 수 있습니다.