MAC OSX에서의 PhoneGap 개발환경 구성에 대해 알아 보겠습니다. 요즘 특정 Hybrid Framework에서는 Windows 환경에서도 iOS Application을 Build하는 방법을 제공하지만, Open Source인 PhoneGap에서는 아직 제공하지 않으므로 MAC OSX 환경에서 개발환경을 구성하는 방법에 대해 알아 보겠습니다.
아래부터는 편의를 위해 경어는 생략하도록 하겠으니 양해 바랍니다.
1. XCode 설치
XCode는 Apple AppStore나 홈페이지에서 다운로드 할 수 있다. Apple AppStore에서 다운로드 할 경우 최신 버전만 다운로드 가능하므로 이전 버전의 XCode를 다운로드하고 싶을 경우 홈페이지에 접속하여 다운로드 받도록 한다. 홈페이지 아래의 경로로 접근하면 다운로드 가능하다.

https://developer.apple.com/downloads

XCode는 현재 OS 버전에 따라 설치할 수 있는 버전이 제한되며, 최신 버전의 iOS 지원을 위해서는 개발에 사용하는 MAC Book, iMac의 OS 버전도 최신으로 업데이트해야 한다.

2. Command Line Tools 설치
혹시나 Command Line Tools가 아직 설치되어 있지 않다면, 1번 과정과 동일한 방법으로 Command Line Tools를 설치한다.
3. Node.js 설치
PhoneGap 3.5 버전부터는 다운로드는 허용하지 않으며, CLI를 통한 설치만 허용한다. 해당 작업이 Node.js 기반으로 구성되었으므로 먼저 아래 URL로 접근하여 Node.js를 설치한다. -. http://nodejs.org

4. PhoneGap 설치
PhoneGap 3.5 부터는 CLI를 통한 다운로드만 허용하고 있으므로 npm install 명령으로 설치한다. Command Window를 실행한 후 아래 화면과 같이 명령어를 입력한다.

명령어를 입력하면 NodeJS 모듈이 PhoneGap을 다운로드하여 자동으로 설치한다. 설치가 종료되면 Command Window에서 cordova –v 라고 입력하여 설치한 PhoneGap version을 확인할 수 있다.

5. PhoneGap 프로젝트 생성
위 과정으로 PhoneGap 프로젝트 생성을 위한 준비가 끝났다. 실제 프로젝트를 생성하여 개발 툴인 XCode로 반입하는 방법은 아래와 같다.

1. 임시 workspace 생성

PhoneGap CLI로 생성한 프로젝트를 보관할 폴더를 하나 만든다. 각자 관리하기 편한 경로에 생성하면 된다. 일단 Sample로는 /Users/계정/Documents/phonegap/workspace/ 로 생성하였다.

2. PhoneGap 프로젝트 생성

PhoneGap 프로젝트는 CLI로 생성할 수 있으므로 Command Window를 열고 /Users/계정/Documents/phonegap/workspace/로 이동한다. 이동한 후 cordova create 명령으로 PhoneGap 프로젝트를 생성할 수 있다. 생성하는 과정은 아래 그림을 참고한다.

실행한 결과를 보면 com.edu.bbs 라는 아이디를 가진 MobileBBS라는 프로젝트를 생성하였는데, 그 경로가 /Users/계정/Documents/phonegap/workspace/mobileBBS 에 생성되었다는 결과가 표시되었다.

3. Platform 추가

프로젝트를 생성했으면 프로젝트에서 사용할 Platform을 추가해야 한다. 당연히 이번에는 iOS를 추가해보자. 먼저 방금 생성한 프로젝트 폴더로 이동하여 cordova platform add 명령을 실행한다. 과정은 아래 그림을 참고한다.

4. XCode 반입

이제 생성한 Project를 XCode로 반입해야 한다. MAC OSX에서 반입은 프로젝트 파일만 실행시키면 쉽게 XCode 프로젝트로 등록 가능하다. 방금 전 단계에서 iOS platform을 추가하였으므로 ./platform/ios/ 경로에 접근해보면 MobileBBS.xcodeproj 파일을 볼 수 있다. 해당 파일을 더블클릭하면 자동으로 XCode Project로 등록된다.




300x250

'모바일 > 개발환경구성' 카테고리의 다른 글

PhoneGap 개발환경구성 (Windows)  (3) 2015.01.05
언젠가부터 Enterprise Mobile Application을 개발하는데 Hybrid 개발 방법이 많이 쓰이고 있습니다. 물론 Native나 Mobile Web과는 일정 부분의 득과 실이 있겠지만, 기업 입장에서 전체적인 개발 비용을 다운시킬 수 있고 하나의 소스로 유지보수 할 수 있는 점은 무시할 수 없는 매력으로 작용했을 듯 합니다.
이런 Hybrid 개발은 사용자가 직접 Android, iOS 등에서 WebView를 생성하여 개발하기도 하지만 공통적인 부분들을 이미 개발해 놓은 Hybrid Framework를 사용해서 많이들 개발합니다. 각 기업들에서 내놓은 솔루션들도 많지만 가장 많이 사용하는 건 아무래도 Open Source인 PhoneGap이 아닐까 합니다. 하여 이미 많이들 사용하고 계시지만 PhoneGap 개발을 위한 개발환경 구성에 대해 알아보도록 하겠습니다.
아래부터는 편의를 위해 경어는 생략하도록 하겠으니 양해 바랍니다.
1. ADT(Android Developer Tools) 설치
프로젝트에서 IDE로 사용할 ADT를 다운로드 받아 압축을 해제한다. 개발자들에게 압축하여 배포할 형태를 고려하여 폴더를 생성한다. ADT는 아래 경로에서 다운로드 받아 압축만 해제하면 된다.

http://developer.android.com/sdk/index.html

프로젝트에서는 Packaging 뿐만 아니라 WEB Resources도 같은 IDE에서 개발할 것이므로 HTML, JavaScript, CSS 개발에 필요한 Eclipse Plug-in을 설치한다. Eclipse에서 [Help] – [Install New Software] 메뉴를 선택하면 아래와 같은 창이 표시된다. 해당 창의 Work with 란에 아래 주소를 입력하면 아래 그림과 같은 미설치 Plug-in 목록이 조회된다.

Eclipse에서 [Help] – [Install New Software] 메뉴를 선택하면 아래와 같은 창이 표시된다. 해당 창의 Work with 란에 아래 주소를 입력하면 아래 그림과 같은 Plug-in 목록이 조회된다. 입력할 주소 : http://download.eclipse.org/releases/kepler

조회된 Plug-in 목록 중 [Web, XML, Java EE and OSGi Enterprise Development] 좌측의 화살표를 클릭하면 해당 Category 하위의 Plug-in목록이 조회된다. 그 중 한 가지에 체크를 하여 설치한다.

-. Eclipse Java Web Developer Tools
2. Node.js 설치
PhoneGap 3.5 버전부터는 다운로드는 허용하지 않으며, CLI를 통한 설치만 허용한다. 해당 작업이 Node.js 기반으로 구성되었으므로 먼저 아래 URL로 접근하여 Node.js를 설치한다. -. http://nodejs.org/ 페이지의 중간에 있는 큼직한 INSTALL 버튼을 클릭하면 *.msi 파일을 다운로드 하며, 해당 파일을 클릭하면 Node.js가 설치된다.

3. Git 설치
PhoneGap 3.x 대 버전부터는 Project를 생성할 때 사용하고자 하는 js API를 Git에서 선택적으로 추가해서 사용하는 구조이므로 Git도 설치 및 PATH에 잡혀 있어야 한다. Git는 아래 URL에서 다운로드하여 설치한다. -. http://msysgit.github.io/

4. PhoneGap 설치
PhoneGap 3.5 부터는 CLI를 통한 다운로드만 허용하고 있으므로 npm install 명령으로 설치한다. Command Window를 실행한 후 아래 화면과 같이 명령어를 입력한다.

명령어를 입력하는 NodeJS 모듈이 PhoneGap을 다운로드하여 자동으로 설치한다. 설치가 종료되면 Command Window에서 cordova –v 라고 입력하여 설치한 PhoneGap version을 확인할 수 있다.

5. Ant 설치
PhoneGap 3.x 에서는 Project 생성 시 CLI를 지원하며, Android Project 추가 시 내부적으로 Ant를 사용하여 Build 한다. 따라서 Android Project를 추가하기 위해서는 Ant 역시 설치되어 있어야 한다. Ant는 아래 URL에서 다운로드 할 수 있으며, 원하는 경로에 압축을 해제하면 된다. -. http://ant.apache.org/

Ant 는 설치 후 %ANT_HOME%을 등록하고 \bin 경로를 Path에 등록해 두어야 PhoneGap이 필요한 경로에서 Build 할 수 있다. 압축을 해제한 경로를 Path에 등록하자.

1. 시스템 변수 등록

[내 컴퓨터] – [속성]의 [고급 시스템 설정] 메뉴에서 [고급] 탭으로 이동한 후 [환경 변수] 버튼을 클릭하면 아래와 같은 창이 표시된다.

시스템 변수에 [새로 만들기] 버튼을 클릭하여 변수 이름에 ANT_HOME, 변수 값에 ANT 압축을 해제한 경로를 설정하도록 하자. 예를 들어 C:\Ant에 압축을 해제하였다고 하면 위와 같이 ANT_HOME 이라는 변수에 C:\Ant라는 값이 저장된다.

2. Path 추가

시스템 변수를 추가했으면 사용자 변수 중 Path 부분을 Edit 하여 해당 경로를 Path에 포함시켜야 한다. 사용자 변수 중 Path를 선택하고 [편집] 버튼을 누른 후 변수 값 가장 마지막 부분에 %ANT_HOME%\bin; 을 추가한다.
6. PhoneGap 프로젝트 생성
위 과정으로 PhoneGap 프로젝트 생성을 위한 준비가 끝났다. 실제 프로젝트를 생성하여 개발 툴인 ADT로 반입하는 방법은 아래와 같다.

1. 임시 workspace 생성

PhoneGap CLI로 생성한 프로젝트를 보관할 폴더를 하나 만든다. 각자 편한 이름으로 생성하면 된다. 일단 Sample로는 d:\phonegap_workspace 로 하나 생성했다.

2. PhoneGap 프로젝트 생성

PhoneGap 프로젝트는 CLI로 생성할 수 있으므로 Command Window를 열고 d:\phonegap_workspace로 이동한다. 이동한 후 cordova create 명령으로 PhoneGap 프로젝트를 생성할 수 있다. 생성하는 과정은 아래 그림을 참고한다.

실행한 결과를 보면 com.edu.bbs 라는 아이디를 가진 MobileBBS라는 프로젝트를 생성하였는데, 그 경로가 d:\phonegap_workspace\mobileBBS 에 생성되었다는 결과가 표시되었다.

3. Platform 추가

프로젝트를 생성했으면 프로젝트에서 사용할 Platform을 추가해야 한다. 일단은 Android 이번 범위에서는 Android 만 진행할 예정이므로 Android 만 추가해보자. 먼저 방금 생성한 프로젝트 폴더로 이동하여 cordova platform add 명령을 실행한다. 과정은 아래 그림을 참고한다.

4. ADT 반입

생성한 Project를 ADT로 반입해야 한다. Application 개발 시 ADT를 사용할 것이므로 CLI에서 생성한 Project를 ADT로 반입하여야 개발환경 설정이 완료된다. Package Explorer 의 바로가기 메뉴에서 [New] – [Other..]를 선택한다.

[Android] – [Android Project from Existing Code]를 선택하고 [Next] 버튼을 클릭한다.

Root Directory에 방금 전 생성한 PhoneGap Project 경로를 선택하고 아래 쪽에 있는 [Copy projects into workspace] 옵션에 체크한 후 [Finish] 버튼을 클릭한다. 여기까지 하면 PhoneGap Project 를 ADT 환경으로 반입할 수 있다. 현재 Bug 비슷하게 발생하는 문제가 있어서 Project 반입 시 오류가 발생하면 지우고 재 반입하면 정상적으로 반입할 수 있다. 반입한 후 Package Explorer 는 아래 그림과 같다.

Native 개발은 [프로젝트 명-CordovaLib] 프로젝트에서 진행하며, 화면 등의 주 개발 영역인 Web 개발은 위 프로젝트에서 진행한다. Web Resources는 /assets/www/ 폴더 경로에 위치한다.


300x250

'모바일 > 개발환경구성' 카테고리의 다른 글

PhoneGap 개발환경구성 (iOS)  (0) 2015.01.10

제목: 글쓰기 페이지 구성 (Client)

최초작성일: 2015-01-05

최종수정일: 2015-01-05

2015년 새해가 밝았습니다. 다들 2015년에는 하시는 일 원하시는대로 이루어지길 빌겠습니다. 물론 저도, 우리 꼬맹이도 건강하고 많이 이루어나가는 한 해가 되었으면 좋겠네요. 정말 한 해가 지나고 새해가 밝으면 문자 그대로 많은 일들을 후회하고, 새해에 대한 다짐과 기대에 차오르는 것 같습니다. 2015년에는 많은 핑계들로 다짐을 지워가는 한 해는 되지 않도록 열심히 살아봐야겠네요. 지난 시간에 목록 페이지에 이어 상세 페이지까지 개발해 보았습니다. 이제 신규로 글을 등록하는 기능을 구현해보도록 하겠습니다. 글 등록 역시 일단은 서버가 없으니 UI만 만들어보도록 하겠습니다. Local Storage에 저장할 수도 있고, WEB Database에 저장할 수도 있겠지만, 일단 저장은 하지 않고 UI 개발만 하고 멈추도록 하겠습니다. 입력에 사용할 항목은 아래와 같이 정의합니다.

-. 입력자 성명
-. 게시물 제목
-. 게시물 내용
-. 비밀번호
그럼 UI를 구성해보겠습니다.
1. 기본 HTML 구조 작성
글쓰기 페이지 역시 [헤더] - [본문] - [푸터]로 영역을 분할하여 구성하겠습니다. 아래 소스 코드를 참고하셔서 ./bbs_write.html 파일로 저장합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta http-equiv="content-type" content="text/html;charset=UTF-8">
        <meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, width=device-width">
        <title>Mobile BBS</title>
        <link rel="stylesheet" type="text/css" href="./css/common.css" />
    </head>
    <body>
        <header>
            <h1>Mobile BBS</h1>
        </header>
         
        <div class="wrap">
            <div class="content_line">
                <span class="header">작성자</span>
                <span><input type="text" class="input" id="inputUserName"><span>
                    </span></span></div>
            <div class="content_line">
                <span class="header">비밀번호</span>
                <span><input type="text" class="input" id="password"></span>
            </div>
            <div class="content_line">
                <span class="header">글제목</span>
                <span><input type="text" class="input" id="subject"></span>
            </div>
            <div class="content_line">
                <span class="header">글내용</span>
                <span><textarea id="content" class="text"></textarea></span>
            </div>
        </div>
         
        <footer>
            <button id="btnWrite">글쓰기</button>
        </footer>
    </body>
    <script type="text/javascript" charset="utf-8" src="./scripts/jquery-1.10.2.min.js"></script>
    <script type="text/javascript" charset="utf-8" src="./scripts/common.js"></script>
</html>
HTML 페이지는 구조만 선언하므로 큰 내용이 없습니다. 글쓰기 페이지에서 표시할 정보에 대한 구조를 선언했습니다. 사용자가 입력해야 하는 값인 작성자, 비밀번호, 글제목, 글내용 컬럼을 입력할 수 있는 inputbox가 화면의 전부입니다. 글내용은 긴 내용도 입력할 수 있어야 하기 때문에 textarea로 구성합니다.
그럼 이제 글쓰기 페이지의 모양을 위해 간단하게 StyleSheet를 추가해보겠습니다.
2. StyleSheet 작성

StyleSheet는 모든 페이지에서 common.css를 사용하도록 하겠습니다. common.css에 글쓰기 페이지와 관련된 부분을 추가해보겠습니다.

1
2
3
.wrap .content_line .header{display:inline-block;width:100px;text-align:center;vertical-align:top;padding-top:5px;}
.wrap .content_line .input{width:250px;border:1px solid #ccc;background-color:#f4f4f4;border-radius:3px;height:22px;line-height:22px;}
.wrap .content_line .text{width:250px;border:1px solid #ccc;background-color:#f4f4f4;border-radius:3px;height:200px;line-height:200px;}
일단 inputbox 및 textarea의 크기는 고정으로 사용합니다. 입력할 내용이나 프로젝트의 UI 표준에 맞게 화면의 크기에 반응하여 늘어나게 해도 되고, 현재처럼 고정으로 사용하기도 합니다. CSS 까지 적용하시면 아래 그림과 같은 화면이 완성됩니다.


3. JavaScript 작성
글쓰기 페이지는 아직 서버와 인터페이스하지 않는 부분까지만 개발할 예정이므로, 개발할 수 있는 부분이 많지 않습니다.
-. Validation
-. 서버 인터페이스
-. 목록 화면으로 Re-Direction
작업 중 이번 과정에서는 Validation 부분과 인터페이스를 할 수 있는 모듈까지만 작성해보도록 하겠습니다. 그럼 먼저 Validation 부분을 살펴보도록 하겠습니다. 일반적으로는 4개의 컬럼이 필수라면 아래의 코드와 같이 작성합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if ($('#inputUserName').val() == '') {
    alert('작성자는 필수 입력입니다.');
    return;
}
 
if ($('#password').val() == '') {
    alert('비밀번호는 필수 입력입니다.');
    return;
}
 
if ($('#subject').val() == '') {
    alert('글제목은 필수 입력입니다.');
    return;
}
 
if ($('#content').val() == '') {
    alert('글내용은 필수 입력입니다.');
    return;
}
jQuery Selector로 필수로 입력해야 하는 값들을 체크하여 값이 없을 경우 alert을 return하는 내용입니다. 하지만 필수 입력값이 많다면 저런 방식의 코드는 비효율적일 수 있으니 간단하게 현재 사용하는 inputbox와 textarea 만을 고려하여 Validation 후 미입력된 필수값을 alert으로 알려주는 코드를 구현해 보겠습니다. 먼저 HTML 파일을 아래와 같이 수정합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class="wrap">
    <div class="content_line">
        <span class="header">작성자</span>
        <span><input type="text" class="input mandatory" id="inputUserName" data="작성자"><span>
    </span></span></div>
    <div class="content_line">
        <span class="header">비밀번호</span>
        <span><input type="password" class="input mandatory" id="password" data="비밀번호"></span>
    </div>
    <div class="content_line">
        <span class="header">글제목</span>
        <span><input type="text" class="input mandatory" id="subject" data="글제목"></span>
    </div>
    <div class="content_line">
        <span class="header">글내용</span>
        <span><textarea id="content" class="text mandatory" data="글내용"></textarea></span>
    </div>
</div>
사용자가 필수로 입력해야 하는 값들에 mandatory 라는 class를 하나 추가했습니다. 그리고 data 속성을 추가하여 해당 입력값이 무엇을 의미하는지 표시하였습니다. 그럼 이어서 ./scripts/common.js 파일에 function을 하나 추가하도록 하겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
COMM.validate = function() {
    var items = $('.mandatory');
    var messages = '', isValid = true;
    for (var inx=0; inx<items.length; inx++) {
        if ($(items[inx]).val() == '') {
            isValid = false;
            messages += $(items[inx]).attr('data') + '은(는) 필수 입력값입니다.\n';
            break;
        }
    }
     
    return {valid: isValid, messages: messages};
};
위 코드의 의미는 간단합니다. mandatory라는 class를 가진 element들을 Loop 돌면서 값이 입력되지 않았으면 해당 element에 값을 출력하라는 메시지를 return하는 함수입니다. 간단하게 구성해봤지만 이런 식으로 매번 반복적으로 사용했던 코드들을 공통화하는 방법을 생각하는 것은 매우 중요합니다. 그럼 위 코드를 호출하여 유효성 검사를 하는 부분을 구현해 보겠습니다. ./scripts/bbs_write.js 파일을 하나 생성하여 아래와 같이 작성합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var WRITER = {};
 
var WRITER.write = function() {
    var validator = COMM.validate();
    if (!validator.valid) {
        alert(validator.messages);
        return;
    }
};
 
$(document).ready(function() {
    $('#btnWrite').on('click', function() {
        WRITER.write();
    });
});
이제 아무것도 입력하지 않은 상태에서 [저장하기] 버튼을 터치해보면 "작성자은(는) 필수 입력값입니다." 라는 경고 메시지가 출력됩니다. 물론 입력값을 모두 입력한 후에 [저장하기] 버튼을 터치해도 값이 입력되었을 경우에 대한 로직은 구현하지 않았으므로 아무 반응도 없습니다. 그럼 이제 서버와의 인터페이스를 위한 함수를 구현해 보겠습니다. 서버와의 인터페이스는 Form Submit 방식을 사용하지 않고 AJAX 방식으로 인터페이스하며, jQuery에서 제공하는 $.ajax 함수를 사용하여 인터페이스 하겠습니다. 일단 ./scripts/common.js 파일에 아래 코드와 같이 function을 추가합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
COMM.doPost = function(url, input, success, fail) {
    var option = {};
    option.url = url + '?__jsonParams=' + JSON.stringify(input);
    option.type = 'POST';
    option.headers = {'Content-Type': 'application/json'};
    option.success = function(data) {
        try {
            if (typeof data == 'string') data = JSON.parse(data);
            success(data);
        } catch (e) {
            if (fail && typeof fail == 'function') {
                fail(e);
            } else {
                alert(e.stack);
            }
        }
    };
    option.error = function(jqXHR, status, error) {
        if (fail && typeof fail == 'function') {
            fail(error);
        } else {
            alert(error);
        }
    };
    $.ajax(option);
};
$.ajax를 간단하게 한 번 wrapping 한 형태입니다. 공통 성공, 실패 및 설정 부분에 대한 부분만 코딩되어 있습니다. 실제 프로젝트에서는 해당 프로젝트에서 사용하는 인터페이스 전문 및 파일 전송 여부 등에 따라 좀 더 꾸며져 있는 형태로 코딩하셔서 사용하시면 됩니다. 데이터를 전달하는 방법은 각자 프로젝트 성격에 맞게 Payload로 전달하셔도 되고, 아니면 샘플에서처럼 쿼리스트링 파라미터로 전달하셔도 됩니다. Payload에 전달하고 싶을 경우 아래 코드와 같이 써주시면 됩니다.
1
option.data = input;
자, 이번 시간은 네트워크 공통 모듈을 만드는 여기까지만 진행하겠습니다. 나머지는 Local 환경에 서버를 구성한 후 실제 인터페이스를 해보며 진행하겠습니다.
아직 이래저래 바쁘다보니 올해 달력은 자세히 못봤습니다. 하지만 달력이 꽤 좋다는 얘기는 좀 들리네요. 다들 일 때문에 늘 바쁘시겠지만 쉴 때는 좀 쉬어가며 Working & Life Balance를 잘 유지하는 한 해 되시기 바랍니다. 오늘도 수고하셨어요!


300x250

제목: 상세 페이지 구성 (Client)

최초작성일: 2014-12-30

최종수정일: 2014-12-30

연말연시는 언제나 아쉬움이 많이 남는 것 같습니다. 그래도 이번 연말은 좋네요. 회사란 곳에 입사를 하고서부터는 정말 바쁘게 시간이 흘러가서 따로 한 해를 정리할 시간이 없었는데 좋은건지 안좋은건지 올해는 지나온 시간들 중 가장 한가한 연말이 아닌가 합니다. 지나온 바쁜 시간들에 물론 감사하는 마음도 있지만 올해처럼 이런 여유를 가질 수 있는 연말도 퍽이나 좋네요. 모두에게 다사다난했을 2014년도 잘 정리하시기 바랄게요. 지난 시간에는 목록 페이지를 개발해 보았습니다. 비록 아직 서버가 없는 관계로 인터페이스는 없지만 단말에서 데이터를 생성하여 UI에 Binding 하고, Binding 하는 부분의 모듈을 Templates을 사용하여 개선하는 부분도 진행해 보았습니다. 이번에는 상세 페이지를 만들어 보겠습니다. 상세 페이지는 목록에서 볼 수 없는 해당 게시물에 대한 전체 정보를 조회하는 기능을 제공하는 페이지입니다. 우리가 만들 게시판은 정보가 많지 않기 때문에 목록 페이지에 보이는 데이터가 거의 다지만, 실제 프로젝트에서는 정말 많은 데이터를 모바일 화면에서도 조회하게 됩니다. 자 그럼 상세 페이지 개발을 시작해보겠습니다.
1. 기본 HTML 구조 작성
상세 페이지 역시 [헤더] - [본문] - [푸터]로 영역을 분할하여 구성하겠습니다. 아래 소스 코드를 참고하셔서 ./bbs_detail.html 파일로 저장합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta http-equiv="content-type" content="text/html;charset=UTF-8">
        <meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, width=device-width">
        <title>Mobile BBS</title>
        <link rel="stylesheet" type="text/css" href="./css/common.css" />
    </head>
    <body>
        <header>
            <h1>Mobile BBS</h1>
        </header>
         
        <div class="wrap">
            <div class="content_line">
                <span id="subject"></span>
            </div>
            <div class="content_line">
                <span id="additionalInfo"></span>
            </div>
            <div class="content_line">
                <span id="content"></span>
            </div>
        </div>
         
        <footer>
            <button id="btnWrite">글쓰기</button>
        </footer>
    </body>
    <script type="text/javascript" charset="utf-8" src="./scripts/jquery-1.10.2.min.js"></script>
    <script type="text/javascript" charset="utf-8" src="./scripts/common.js"></script>
</html>
HTML 페이지는 구조만 선언하므로 큰 내용이 없습니다. 상세 페이지에서 표시할 정보에 대한 구조를 선언했습니다. 먼저 subject로 표시한 부분은 제목을 표시할 영역이고, additionalInfo 영역에는 작성자 + 작성일자 + 조회 수를 한 행으로 정리하여 표시하도록 하겠습니다. content 영역에는 글의 본문 내용을 표시해보겠습니다.
그럼 이제 상세 페이지의 모양을 위해 간단하게 StyleSheet를 추가해보겠습니다.
2. StyleSheet 작성
StyleSheet는 모든 페이지에서 common.css를 사용하도록 하겠습니다. common.css에 상세 페이지와 관련된 부분을 추가해보겠습니다.
1
.wrap .content_line{padding:7px 5px 7px 5px;border-bottom:1px solid #ccc;}
3. JavaScript 작성
이제 목록 페이지에서 받아온 데이터를 상세 페이지에 Bind하는 부분을 구현해야 합니다. 여기서 우리가 잊고 온 부분이 있네요. 목록 페이지에서 값을 보내는 부분을 구현해보지 않았습니다. 목록 페이지에서 상세를 조회할 게시물의 행을 터치하면 선택한 게시물의 정보를 어딘가에 담아서 상세 페이지로 전달해야 합니다.

여기서 정보를 전달하는 방법에 크게 두 가지 방법이 있습니다. 먼저 일반적인 방법으로 게시물의 식별자(Key) 정보만 전달하고 상세 페이지에서 식별자로 해당 게시물 정보를 조회해오는 방법이 있습니다. 하지만 우리가 개발하는 게시판처럼 목록에서 보여지는 내용과 상세에서 보여지는 컬럼 수가 많이 차이나지 않는다면 목록을 조회할 때 모든 정보를 조회한 후 상세 페이지에서는 별도의 서버 인터페이스를 하지 않는 방법이 있습니다. 우리는 후자의 방법을 선택하여 목록 페이지에서 모든 데이터를 받아서 상세 페이지로 전달하기로 하겠습니다.
3-1. 데이터 전달 방법
데이터를 전달하는 방법에 대한 고민도 필요합니다. 만약 어플리케이션이 하나의 HTML로 이루어진 구조라면 전역 변수를 사용할 수도 있습니다. 하지만 업무 별로 페이지를 분할하여 개발하는 경우에는 전역 변수를 공유할 수 없으므로, 어떤 방식으로던 데이터의 전달이 필요합니다. 전달하는 방법은 크게 두 가지로 나눌 수 있을 것 같습니다.
먼저 쿼리스트링으로 전달하는 방법입니다. 이동할 페이지 정보 뒤에 쿼리스트링으로 값을 연결하여 보내는 경우 받는 페이지에서 location.href 정보에서 쿼리스트링 정보를 잘라서 사용할 수 있습니다. 쿼리스트링으로 데이터를 전달할 경우 아래와 같은 코드로 손쉽게 잘라올 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var REQUEST = {};
 
REQUEST.getParameter = function(parm) {
    var parmVal = null;
    var pageUrl = location.href;
 
    var parms = (pageUrl.slice(pageUrl.indexOf("?") + 1, pageUrl.length)).split("&");
 
    for (var inx=0; inx<parms.length; inx++) {
        if (parms[inx].split("=")[0].toUpperCase() == parm.toUpperCase()) {
            parmVal = decodeURIComponent(parms[inx].split("=")[1]);
            break;
        }
    }
    return parmVal;
};
두 번째 방법은 Local Storage를 사용하는 방법입니다. Local Storage는 key-value pair로 브라우저의 메모리에 저장할 수 있으며, 저장 형태는 string만 가능합니다. 따라서 사용하기 위해서는 JSON Object를 Serialize하여 저장해야 합니다. 우리는 이 두 번째 방법인 Local Storage를 사용하여 개발해보도록 하겠습니다.
두 번째 방법을 선택한 이유는 Android의 4.0.x 대 일부 단말의 OS에서 쿼리스트링까지 페이지 파일명으로 인식하는 버그가 있고, 글 본문 내용 같은 큰 데이터 전달을 위함입니다. 쿼리스트링은 1024 바이트까지만 전달 가능합니다.
3-2. 페이지 이동 function 개발
그럼 이전 시간에 개발했던 ./scripts/common.js 파일을 열어 Local Storage 저장 및 페이지 이동에 대한 기능을 개발하겠습니다. common.js 파일에 아래 내용을 추가합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
COMM.setItem = function(key, value) {
    var saveValue = (typeof value == 'string') ? new String(value) : JSON.stringify(value);
    localStorage.setItem(key, saveValue);
};
 
COMM.getItem = function(key) {
    var value = localStorage.getItem(key);
    try {
        value = JSON.parse(value);
    } catch (e) {
     
    }
    return value;
};
 
COMM.removeItem = function(key) {
    localStorage.removeItem(key);
};
 
COMM.movePage = function(page, pageData) {
    if (pageData) COMM.setItem('__pageData', pageData);
    location.href = page;
};
 
COMM.getPageData = function() {
    var data = COMM.getItem('__pageData');
    COMM.removeItem('__pageData');
    return data;
};
먼저 위의 3개의 function은 브라우저의 LocalStorage를 사용하기 위한 공통 함수입니다. Parameter가 Object로 들어올 경우 자동으로 Serialize하여 저장합니다. 그 다음 COMM.movePage function은 페이지를 이동하기 전에 전달할 데이터를 저장하고 이동하는 기능을 합니다. COMM.getPageData function은 이동한 페이지에서 전달받은 데이터를 꺼내어 오는 기능을 합니다. 그럼 이제 작성한 공통 함수를 가지고 실제 데이터를 전달하여 페이지 이동을 구현해보도록 하겠습니다.
3-3. 목록 페이지 수정

이제 목록 페이지를 수정하여 게시물을 터치하면 상세 페이지로 이동하도록 수정하겠습니다. 목록 데이터를 Bind하는 function인 BBS.display function을 아래와 같이 수정합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BBS.display = function(rows) {
    var listArea = $('#bbsListArea');
    var html = null;
 
    COMM.loadTemplate('bbs_list_line', function() {
        for (var inx=0; inx<rows.length; inx++) {
            html = COMM.getHTMLObj('bbs_list_line', rows[inx]);
            html.find('.bbs_list_txt').attr('data', rows[inx]);
            html.find('.bbs_list_txt').on('click', function(event) {
                COMM.movePage('./bbs_detail.html', $(this).attr('data'));
            });
            listArea.append(html);
        }
    });
}
여기까지 개발을 마쳤다면, 잠시 한 번 쉬어가도록 하겠습니다. 청산유수로 개발을 끝내면 좋겠지만 세상에는 그렇게 만만한 일들은 잘 일어나지 않더군요. 그래서 여기까지 작성한 코드가 정상적으로 동작하는지 확인해보고 지나가도록 하겠습니다. 확인할 사항은 아래와 같이 크게 없습니다.
1. ./bbs_detail.html 페이지로 이동하는지(물론 헤더와 푸터만 있는 빈 페이지입니다.)
2. Chrome 브라우저의 localStorage에 __pageData 값이 잘 저장되어 있는지
위 두 가지 사항을 확인해 보겠습니다. Google Chrome에서 마우스 우클릭 후 나타나는 바로가기 메뉴에서 [요소 검사]를 선택하거나 [F12] Key를 누르면 구글 개발자 도구가 열립니다. 먼저 페이지 이동에 대한 부분은 상세 보기 페이지로 이동하고 Console에 JavaScript 오류가 표시되는 내용이 없다면 정상으로 구현된 것입니다. localStorage 값 확인은 Google 개발자 도구의 Resources 탭에서 확인할 수 있습니다. 아래 그림과 같이 Resources 탭을 확인해보면 데이터 저장 여부를 확인할 수 있습니다.

다른 방법으로 개발자 도구의 Console에서 직접 COMM.getItem function을 호출하여 확인해볼 수 있습니다.

위 내용이 모두 정상적으로 확인되었다면 다음 Step으로 넘어가볼까요?

3-4. 상세 페이지 개발

이제 목록 페이지에서 전달한 데이터를 받아서 상세 페이지에 Bind하는 부분을 구현해보겠습니다. 상세 페이지에서 사용할 JavaScript 파일은 ./scripts/bbs_detail.js 로 생성하여 아래 코드를 반영합니다.

1
2
3
4
5
6
7
8
9
10
11
var DETAIL = {};
 
DETAIL.display = function(data) {
    $('#subject').text(data.subject);
    $('#additionalInfo').text(data.updateDate + ' | ' + data.inputUserName + ' (' + data.readCount + ')');
    $('#content').text(data.content);
};
 
$(document).ready(function() {
    DETAIL.display(COMM.getPageData());
});
./bbs_detail.html 파일에도 작성한 ./scripts/bbs_detail.js 파일을 추가합니다.
1
<script type="text/javascript" charset="utf-8" src="./scripts/bbs_detail.js"></script>
잘 따라하셨나요? 위의 내용까지 따라하시면 목록을 터치하면 상세 페이지로 이동하고 아래 그림과 같이 상세 내용이 표시되는 것을 보실 수 있습니다.

여기까지 모두 잘 되실거라 믿겠습니다. 그런데 지금은 값을 표시할 부분이 3군데 밖에 없어서 코딩이 짧게 끝났지만 값을 20개, 30개 세팅해야 한다고 하면 Selector로 Element를 찾아서 값을 세팅하는 코딩이 20 라인이 들어가게 됩니다. 그럼 이제 위에서 만든 Template을 이용해서 코딩을 좀 짧게 할 수 있는 방법으로 다시 개발해 보겠습니다.

먼저 기본 HTML 페이지를 아래와 같이 수정합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, width=device-width">
<title>Mobile BBS</title>
<link rel="stylesheet" type="text/css" href="./css/common.css" />
</head>
<body>
<header>
    <h1>Mobile BBS</h1>
</header>
 
<!-- 수정 시작 -->
<div class="wrap" style="display:none;">
    <div class="content_line">
        <span>{subject}</span>
    </div>
    <div class="content_line">
        <span>{additionalInfo}</span>
    </div>
    <div class="content_line">
        <span>{content}</span>
    </div>
</div>
<!-- 수정 종료 -->
 
<footer>
    <button id="btnWrite">글쓰기</button>
</footer>
</body>
<script type="text/javascript" charset="utf-8" src="./scripts/jquery-1.10.2.min.js"></script>
<script type="text/javascript" charset="utf-8" src="./scripts/common.js"></script>
<script type="text/javascript" charset="utf-8" src="./scripts/bbs_detail.js"></script>
</html>
위와 같이 실제 Contents를 표시하는 부분인 .wrap 부분을 hidden 처리해줍니다. 치환하기 전에 화면이 먼저 Rendering 될 것이므로 치환을 완료하기 전까지는 화면에 표시하지 않기 위함입니다. 그리고 실제로 값을 표시할 부분을 {}로 감싸서 식별할 수 있도록 해둡니다. 여기까지 마쳤으면 상세 화면을 출력하는 함수인 DETAIL.display 함수를 수정해 보겠습니다.
1
2
3
4
5
6
7
DETAIL.display = function(data) {
    var area = $('.wrap');
    var html = COMM.dynamicExpression(area.html(), data);
    area.empty();
    area.html(html);
    area.show();
}
코드를 살펴보면 의도는 간단합니다. $('.wrap') 안에 있는 내용을 모두 String 형태의 HTML로 받아서 {} Parameter 처리한 부분을 데이터에서 찾아서 자동으로 세팅하겠다는 의미입니다. 하지만 위 내용까지 따라해보시면 {additionalInfo}가 Bind되지 않는 것을 보실 수 있습니다. 이유는 간단합니다. 목록에서 전달하는 데이터에 additionalInfo라는 컬럼이 없기 때문입니다. 우리가 만든 template은 기본적으로 컬럼끼리의 Mapping에 대한 선언은 하지 않으므로 동일한 데이터는 동일한 이름으로 선언해주어야 합니다.

그럼 목록에서 데이터를 전달할 때 additionalInfo 컬럼을 세팅해서 보내보도록 하겠습니다. bbs_list.js 파일을 열어 BBS.display 함수에 컬럼을 추가해 보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
BBS.display = function(rows) {
    var listArea = $('#bbsListArea');
    var html = null;
     
    COMM.loadTemplate('bbs_list_line', function() {
        for (var inx=0; inx<rows.length; inx++) {
            rows[inx].additionalInfo = rows[inx].updateDate + ' | ' +   rows[inx].inputUserName + ' (' + rows[inx].readCount + ')'
            html = COMM.getHTMLObj('bbs_list_line', rows[inx]);
            html.find('.bbs_list_txt').attr('data', JSON.stringify(rows[inx]));
            html.find('.bbs_list_txt').on('click', function(event) {
                COMM.movePage('./bbs_detail.html', $(this).attr('data'));
            });
            listArea.append(html);
        }
    });
}
여기까지 수정한 후 다시 목록을 조회해서 상세 페이지로 이동하면 데이터가 모두 표시되는 것을 확인할 수 있습니다. 어떠신가요? 다들 잘 따라하셨나요? 이젠 생각보다 날이 많이 풀려서 사무실에 앉아있지만 솔솔 잠도 오네요. 연말연시라 싱숭생숭하고 변화가 많은 시기지만 모두 2014년 한 해 잘 정리해서 보내주고 다가오는 신년을 잘 맞이했으면 합니다. 다음 시간은 2015년에 만나도록 하겠습니다.


300x250

제목: 목록 페이지 구성 (Client)

최초작성일: 2014-12-26

최종수정일: 2014-12-26

자 이제 목록 페이지를 개발해 보겠습니다. 목록 페이지는 서버에서 데이터를 조회해와서 List 형태로 화면에 출력하는 역할을 담당합니다. 하지만 우리는 서버는 나중에 개발해보기로 하였으니 먼저 단말에서 강제로 데이터를 생성해서 List에 올바르게 Bind 하는지까지만 확인해보도록 하겠습니다. 그럼 이제부터 목록 페이지 만들기를 시작해 보겠습니다.
1. 기본 HTML 구조 작성
목록 페이지 뿐만 아니라, 모든 페이지를 위해서는 기본 구조가 필요합니다. 우리는 간단하게 모바일에서 늘 보던 방식인 [헤더] - [본문] - [푸터]로 구분하여 [본문] 영역만 Scroll 되는 구조로 개발해 보겠습니다. Scroll은 별도의 Open Source Library를 사용하지 않고 브라우저에서 지원하는 DIV Scroll을 사용할 예정이므로 Android 4.0 이하의 버전에서는 사용할 수 없습니다. 하지만 Android Developer 사이트에서 제공하는 현재 OS 점유율을 보면 4.0 이하의 OS는 점유율이 낮고 차차 없어질 부분이므로 일반적으로 크게 문제가 되지 않습니다. OS 버전 별 점유율은 아래 Link를 참고하시면 됩니다. http://developer.android.com/about/dashboards/index.html 그럼 위 방법대로 HTML을 간단히 구성해보도록 하겠습니다. 아래 소스 코드를 참고하여 bbs_list.html을 작성합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta http-equiv="content-type" content="text/html;charset=UTF-8">
        <meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, width=device-width">
        <title>Mobile BBS</title>
        <link rel="stylesheet" type="text/css" href="./css/common.css" />
    </head>
    <body>
        <header>
            <h1>Mobile BBS</h1>
        </header>
         
        <div class="wrap">
            <ul id="bbsListArea"></ul>
        </div>
         
        <footer>
            <button id="btnWrite">글쓰기</button>
        </footer>
    </body>
    <script type="text/javascript" charset="utf-8" src="./scripts/jquery-1.10.2.min.js"></script>
</html>
큰 내용은 없습니다. 페이지 구조를 크게 [헤더] - [본문] - [푸터]로 분리하였고, 공통 StyleSheet 파일을 하나 포함하도록 설정하였고, Open Source Library인 jQuery 사용을 위해 Script를 load 하였습니다.
2. StyleSheet 작성
모든 페이지에 공통으로 사용할 StyleSheet를 작성해 보겠습니다. 일단은 목록 페이지에서 사용할 부분만 작성하고 나머지 부분은 차차 페이지를 개발하는대로 추가해보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
@charset "utf-8";
/* default */
html, body{height:100%;}
body{position:relative;margin:0;padding:0;}
ul, ol{list-style:none;padding:0;margin:0;}
a{text-decoration:none;}
button{height:30px;background-color:#FFF;border:1px solid #CCC;border-radius:3px;}
header{position:absolute;left:0;top:0;width:100%;z-index:2;height:45px;background-color:#333;border-bottom:2px solid #cc0000;}
header h1{left:0;top:0;width:100%;height:45px;color:#FFF;font-weight:bold;text-align:center;box-shadow:inset 0px 7px 20px rgba(0, 0, 0, 0.2);margin:0;line-height:45px;font-size:1.1em;}
footer{position:absolute;left:0;bottom:0;width:100%;z-index:2;height:45px;line-height:45px;text-align:center;background-color:#EEE;border-top:1px solid #CCC;}
 
.wrap{position:absolute;top:45px;bottom:45px;width:100%;overflow-y:scroll;}
CSS는 별도로 설명하지 않도록 하겠습니다. 그저 현재까지는 화면에서 영역을 나누고 [헤더], [푸터]를 고정한 후 남는 영역을 [본문] 영역으로 할당한 것이 전체 내용입니다.
3. JavaScript 작성
그럼 이제 JavaScript를 작성해 볼까요? 서버가 없으니 필요한 데이터를 단말에서 JSON 형태로 하드코딩하여 만들어 보도록 하겠습니다. JavaScript는 bbs 라는 Namespace 안에 별도의 Object 생성이 필요없도록 Static Function으로 구현하도록 하겠습니다.
일단 게시판 목록에 필요한 데이터의 Layout은 아래와 같이 정의하겠습니다. 추후 서버 개발할 때, 아래 Layout 대로 데이터를 단말로 return 하면 됩니다.
1
2
3
4
5
6
7
8
9
[{
    idx: 1,
    subject: '',
    readCount: 0,
    content: '',
    inputUserName: '',
    inputDate: 'YYYY-MM-DD',
    updateDate: 'YYYY-MM-DD'
}]
그럼 이제 위 Layout 대로 테스트데이터를 생성하여 목록에 Bind하는 부분을 개발해보도록 하겠습니다. function은 데이터를 생성하는 function과 목록에 Bind하는 부분을 구분하여 작성합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var BBS = {};
 
BBS.getTestData = function() {
    var rows = [], row = {};
    row.idx = 1;
    row.subject = '테스트 게시물 입니다.';
    row.readCount = 1;
    row.content = '테스트 게시물 본문 입니다.';
    row.inputUserName = '홍길동';
    row.inputDate = '2015-01-01';
    row.updateDate = '2015-01-01';
     
    rows.push(row);
    rows.push(row);
     
    return rows;
}
 
BBS.display = function(rows) {
    var li = null, a = null, row1 = null, row2 = null;
    var listArea = $('#bbsListArea');
     
    for (var inx=0; inx<rows.length; inx++) {
        li = $('<li>');
        a = $('<a>');
        row1 = $('<div>');
        row1.text(rows[inx].subject + ' (' + rows[inx].updateDate + ')');
        row2 = $('<div>');
        row2.text(rows[inx].inputUserName + ' (' + rows[inx].readCount + ')');
        a.append(row1);
        a.append(row2);
        li.append(a);
         
        listArea.append(li);
    }
}
 
$(document).ready(function() {
    BBS.display(BBS.getTestData());
});
위 코드를 작성하여 ./scripts/bbs_list.js 파일로 저장합니다. 저장한 후 html 파일에 js를 아래와 같이 추가합니다.
1
<script type="text/javascript" charset="utf-8" src="./scripts/bbs_list.js"></script>
위 과정까지 마친 후 Google Chrome에서 bbs_list.html 파일을 열면 아래와 같은 모습으로 실행됩니다. 목록에는 별도의 디자인을 입히지 않았기 때문에 좀 많이 추리(?)하게 나옵니다. 비속어 양해 바랍니다.


4. Templates 만들기
이제 디자인을 입혀보려고 하니, 코드가 좀 마음에 들지 않습니다. 이것저것 추가하려면 목록을 만드는 BBS.display function 부분이 많이 복잡해질 것 같습니다. 그럼 목록에서 반복되는 부분의 Layout을 JavaScript에서 생성하지 말고 별도의 HTML Template을 만들어 읽어오는 방법으로 만들어 보겠습니다.
그럼 ./templates/ 라는 폴더를 하나 생성하고 bbs_list_line.html 파일을 하나 생성하여 아래 코드처럼 작성합니다.
1
2
3
4
5
6
7
8
9
10
<li>
    <a href="#" class="bbs_list_txt">
        <div>
            <span>{subject}</span>
        </div>
        <div>
            <span>{inputUserName} | {updateDate} | 조회 ({readCount})</span>
        </div>
    </a>
</li>
위 코드는 목록의 한 줄의 Layout을 의미하며, 위 코드를 읽어서 목록의 개수만큼 Bind 하는 방식으로 화면을 구성합니다. 코드 상에 있는 {}로 표시한 부분은 변수로 사용하여, 실제 목록에 Bind 할 때는 해당 변수를 실제 값으로 치환하게 됩니다. 그럼 실제로 이 부분을 코드로 작성해보도록 하겠습니다. 이 기능은 이 화면 뿐 아니라 다른 화면에서도 많이 사용하게 될 기능인 것 같으니 별도의 공통 JavaScript 파일을 하나 만들어서 저장하도록 하겠습니다.
아래 코드를 작성한 후 ./scripts/common.js 파일로 저장합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var COMM = {
    templates: []
};
 
COMM.loadTemplate = function(templateId, callback) {
    $.get('./templates/' + templateId + '.html', function(data) {
        COMM.templates[templateId] = data;
        if (callback) callback();
    });
}
 
COMM.getHTMLObj = function(templateId, input) {
    var html = COMM.templates[templateId];
    html = COMM.dynamicExpression(html, input);
    return $(html);
}
 
COMM.dynamicExpression = function(str, params) {
    var retStr = str;
    for (var key in params) {
        var regex = new RegExp('{' + key + '}', 'g');
        var value = params[key];
        if (value == null || value == 'null' || value == undefined || value == 'undefined') {
            value = '';
        }
        retStr = retStr.replace(regex, value);
    }
    return retStr;
}
자. 공통으로 작성한 function은 3가지 입니다. COMM.loadTemplate function은 사용할 template HTML 파일을 COMM Namespace의 변수에 저장합니다. 두 번째로 COMM.getHTMLObj function은 template HTML과 치환할 데이터를 Parameter로 받아서 실제 화면에 Rendering할 HTML을 생성합니다. 이 HTML 생성에 필요한 function이 COMM.dynamicExpression 입니다.
COMM.dynamicExpression function은 text 형태의 HTML와 치환할 데이터를 Parameter로 입력받아 정규 표현식을 사용하여 실제 화면에 Rendering할 형태의 HTML을 생성합니다.
5. Templates 사용하기

그럼 이제 template을 사용하여 BBS.display function을 수정해보도록 하겠습니다. 기존에 JavaScript로 DOM을 생성하는 방식이 아닌 template을 통해 바로 HTML Object를 생성하여 target에 append하는 형태로 수정해 보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
BBS.display = function(rows) {
    var listArea = $('#bbsListArea');
    var html = null;
     
    COMM.loadTemplate('bbs_list_line', function() {
        for (var inx=0; inx<rows.length; inx++) {
            html = COMM.getHTMLObj('bbs_list_line', rows[inx]);
            listArea.append(html);
        }
    });
}
더 복잡해 졌나요?. 물론 목록에 표시해야 하는 HTML Element가 단순하다면 굳이 이런 방법을 쓰지 않고 function 안에서 HTML Code를 생성해도 봐줄만 하겠지만, 실제로 프로젝트에서 사용하는 Layout은 그렇게 단순한 경우가 거의 없습니다. 더하여 코딩 표준을 잡고 프로젝트를 진행한다는 점에서도 이런 방식이 더 효율적으로 작용할 수 있으니 지금 당장은 좀 복잡해 보인다고 해도, 이해하고 넘어가는 편이 좋습니다.
위 코드까지 작성하여 저장하였으면, HTML 파일에 위 js 파일을 적용합니다.
1
<script type="text/javascript" charset="utf-8" src="./scripts/common.js"></script>
그 다음은 목록의 각 행에 적용할 StyleSheet를 common.css 에 추가합니다. 아래 코드를 참고합니다.
1
2
3
4
.wrap ul li{padding:14px 10px;border-bottom:1px solid #d7d7d7;background:-webkit-gradient(linear,left top,left bottom,color-stop(0.00,#fefefe),color-stop(1.00,#f1f1f1));}
.wrap ul li a{display:inline-block;width:100%;}
.wrap ul li span {color:#999;font-size:0.9em;}
.wrap ul li span strong{color:#000;font-size:1.1em;}
위 코드까지 적용하면 아래와 같은 모습의 목록화면이 완성됩니다.

다들 잘 나오나요? 파일 하나에 개발하던 방법에 비해서 파일을 분할해 놓은 탓에 처음보는 오류들이 발생할 수도 있습니다. 하지만 우리가 사용하는 Google Chrome에서는 쉽게 Debugging 할 수 있어 어렵지 않게 따라오셨을거라 믿을게요. 다음에는 "상세보기" 페이지를 같이 진행해보도록 하겠습니다.

300x250
제목: Concept
최초작성일: 2014-12-23
최종수정일: 2014-12-23
이제 이틀만 지나면 크리스마스네요. 매년 이맘때쯤 "이번 일 년은 정말 빨리 지나갔어" 라고 생각하지만 올해는 더더욱 빠른 속도로 휩쓸고 지나가버린 느낌입니다. 예전에는 어른(?, 저도 지금은 어른입니다.)들께서 나이가 먹으면 시간이 빨리 간다고 말씀하셔도 무슨 말인지 공감할 수 없었지만, 결혼하고 육아하며 살아보니 그 말씀에 정말 백배공감 하게 되네요. 이제부터 간단하게 모바일 앱으로 게시판을 하나 만들어볼까 합니다. 앱이라고 해도 사용하는 언어는 Android Java도 아니고, iOS Objective-C 도 아닌 WEB으로 해보겠습니다. 하지만 이렇게 비즈니스를 구성하는 건 WEB 기술인 JavaScript 이지만 모양새는 Packaging한 앱의 형태여야 합니다. 그래서 Open Source인 PhoneGap을 사용해볼까 합니다. 그냥 Native에서 WebView를 하나 만들고 Web Page를 Load 해도 유사한 결과를 만들어낼 수 있지만, 그런 방법으로 개발할 경우 Native 개발을 많이 포함할 수 밖에 없는 형태가 됩니다. 우리는 일단 WEB Resource의 구성에 집중할 예정이므로 Open Source로 널리 사용하는 PhoneGap을 사용하겠습니다. 게시판을 구성하는 기본적인 로직은 일반 게시판과 동일합니다. 하지만 모바일에 맞는 UI를 구성해보는 부분과, Form Submit 형태가 아닌 Ajax 통신 기반으로 만들어보도록 하겠습니다. 어차피 Hybrid 라는게 내부에 있는 Contents 자체는 Web 이다보니 HTML로 게시판을 개발해보신 분들이라면 그다지 어렵지 않게 만드실 수 있습니다. 하지만 실제 프로젝트를 하게 되면 단말 별로 예상하지도, 기대하지도 않았던 이슈들이 프로젝트에 많이 참여하게 되므로 의외로 기초가 중요한 것 같습니다.

일단 전체 구성을 표현한 그림을 한 장 보고 가도록 하겠습니다.
1. Application 구성

일단 그림의 오른쪽과 같이 Local PC에 APM(Apache + PHP + MySQL)으로 간단한 웹 서버를 하나 구성합니다. APM은 아래 경로에 가시면 다운로드할 수 있습니다. http://www.apmsetup.com Hybrid Application은 WEB 기술로 구현하므로 WEB Resource의 위치에 따라 자연스럽게 두 가지 방법으로 나눌 수 있습니다. WEB Resource를 단말에 넣어서 Packaging하는 방법과 서버에 두어서 Package와 분리하는 방법입니다. 두 가지 방법에는 생각해보면 당연할 차이점 및 장단점이 존재합니다. 전부 나열하기는 힘드나 간략하게 표로 한 번 정리해 보겠습니다.
구분 서버 페이지 (1안) 단말 페이지 (2안)
장점 -. JSP / ASPX / PHP 등 화면을 서버 사이드 스크립트 방식으로 개발 가능함
-. 화면 수정 시 어플리케이션 재배포가 필요 없음
-. 어플리케이션이 모두 서버에 있으므로 상대적으로 보안성이 좋음
-. Package 용량이 가벼움
-. WEB Resouce가 단말에 있으므로 다운로드가 필요없어 빠름
-. 실제 업무 데이터만 다운로드 하므로, 데이터 사용량이 적음
단점 -. 페이지 실행 시 필요한 WEB Resource를 모두 다운로드 하므로 로딩이 느림
-. 모든 데이터를 서버에서 다운로드 하므로, 데이터 사용량이 많음
-. 화면은 HTML로만 구성 가능함
-. 화면이 수정되면 어플리케이션 전체를 재배포해야 함 (부분 배포를 위한 기능개발 필요)
-. 어플리케이션 소스가 모두 단말에 있으므로 Reverse Engineering에 취약함
-. WEB Resource가 많을 경우 Package 용량이 커짐
장단점을 정리해보면 위의 표와 같습니다. 다시 시선을 위의 어플리케이션 구성으로 옮겨보면 우리는 Client 어플리케이션을 모두 단말에 두고, 필요한 데이터만 서버에서 AJAX 통신을 통해 가져오는 2안으로 개발하도록 하겠습니다. 일반적인 Native 어플리케이션의 경우 당연히 UI는 단말에 있으므로 우리도 일반적인 어플리케이션 개발 방식을 따른다는 의미로 2안으로 해보겠습니다. 1안의 경우는 페이지에 대한 업데이트가 잦거나 보안 솔루션 등이 많이 도입되어 Package 사이즈가 배포에 부담스러운 경우에 주로 사용하며, 일반적으로는 페이지 로딩 및 전환 속도가 빠른 2안을 선호합니다.
2. 프로젝트 구성
프로젝트 구성에 대한 부분은 [개발환경 구성] > [PhoneGap (Windows)], [PhoneGap (iOS)] 부분에 자세히 정리해 놓았습니다. 해당 메뉴를 참고하셔서 개발환경을 설치하고 프로젝트를 생성해서 IDE로 반입하면 됩니다. IDE로 반입하면 Windows / MAC OSX 모두 www라는 경로가 있습니다. 해당 경로가 우리가 개발하는 WEB Resource의 루트 경로이며 앞으로 개발하는 모든 파일은 www 기준으로 경로를 잡으시면 됩니다. 사실 프로젝트를 구성하는 목적은 PhoneGap 이라는 Platform을 이용해서 어플리케이션을 Packaging 하기 위함입니다. 우리는 일단 Packaging 은 제외하고 WEB Resource에 대한 부분만 Google Chrome을 이용해서 할 예정이므로 현재는 큰 의미는 없지만 개발하는 소스는 모두 www 경로 아래 두도록 하겠습니다.
3. Google Chrome 개발환경 구성
로컬에서 개발하는 JavaScript 기반의 어플리케이션을 Google Chrome으로 테스트하기 위해서는 옵션이 두 가지 필요합니다.
-. --disable-web-security
-. --allow-file-access-from-files
위 두 가지 옵션입니다. 먼저 --disable-web-security의 경우 Google chrome에서 제한하고 있는 Cross Domain에 대한 Scripting을 허용합니다. 우리는 Local에 있는 파일(Local 서버가 아닌 Local 파일입니다)에서 서버의 데이터를 요청할 것이므로 Google Chrome에서 제한하게 됩니다. (JavaScript의 Same Origin Policy와 별개로 Chrome에서 제한합니다.) 따라서 해당 옵션을 적용하여 Cross Domain에 대한 보안사항을 해제하여야 테스트 가능합니다.

두 번째 --allow-file-access-from-files 옵션입니다. Local에서 파일을 읽어오고자 할 경우 적용하여 해제해주어야 하나 우리는 사용하지 않을 예정이므로 적용하지 않아도 됩니다.

보안 옵션은 Windows에서는 바로가기에 적용하면 되며, MAC OSX는 터미널에서 실행 시 --args 옵션 뒤에 적용하면 됩니다. 정상적으로 해제되었을 경우 Chrome 브라우저의 상단에 아래 그림과 같은 경고가 표시됩니다.



300x250

+ Recent posts