프로젝트에서 하이브리드앱 형태로 해서 모바일웹페이지를 안드로이드의 웹뷰에서 보여주며 동작시키는 앱을 만들었다.

제조사마다 다양한 종류의 디바이스에서 테스트를 해봐야하는 안드로이드 개발은 앞으로도 고역이 될 것 같다.


얼마간 나를 괴롭히던 녀석이 있었다.

로그인을 할때 CookieManager를 이용해서 웹뷰의 쿠키 Sync를 맞춰두고 로그인상태를 유지하도록 만들었다.

이 싱크를 맞추는 작업이 지금까지도 곤혹스럽다. 


갤럭시S는 사용자가 많다. 그런데 가장 이상한 안드로이드폰이 갤럭시S다. 갤럭시S를 제외한 안드로이드폰들에서는

정상적으로 동작하는 앱이 꼭! 갤럭시S에서는 다르게 반응하는 것이다. 후아.

인터넷을 뒤져보다가 이 문제에 대한 해결책을 찾았다.


  
/**
 * Remove all session cookies, which are cookies without expiration date
 */
public void removeSessionCookie() {
    final Runnable clearCache = new Runnable() {
        public void run() {
            synchronized(CookieManager.this) {
                Collection> cookieList = mCookieMap.values();
                Iterator> listIter = cookieList.iterator();
                while (listIter.hasNext()) {
                    ArrayList list = listIter.next();
                    Iterator iter = list.iterator();
                    while (iter.hasNext()) {
                        Cookie cookie = iter.next();
                        if (cookie.expires == -1) {
                            iter.remove();
                        }
                    }
                }
                CookieSyncManager.getInstance().clearSessionCookies();
            }
        }
    };
    new Thread(clearCache).start();
}

위의 소스를 보면 마지막에 new Thread(clearCache).start()가 실행되는 것이 보인다. CookieManager.removeSessionCookie() 가 스레드로 실행되는 것을 확인할 수 있다.

갤럭시S가 다른폰들과 다른 반응을 보인 부분이 이 부분이다.


인터넷에 해결방법이 있을까?


하는 생각으로 인터넷을 뒤적거리다가 해결방법을 찾았다.

jinu's blog : Android webview cookie sync 문제 : http://jinu.info/blog/372

1년 전에 작성된 글인데, 글의 중간에 보면

try { Thread.sleep(500); } catch (Exception e) {}


위의 코드가 핵심이다. 500ms의 강제 대기시간을 주어서 cookieManager가 세션쿠키를 삭제할 수 있는 충분한 시간적인 여유를 부여한 후에 진행되도록 하는 것이다.


<< 위의 내용을 힌트삼아서 수정한 소스 >>

  
public void removeAllCookie() {
        Log.d(LOG_TAG, "webViewHelper removeAllCookie execute.");
        cookieManager.removeAllCookie();
        threadSleep();
        setDefaultCookies();
        CookieSyncManager.getInstance().sync();
    }

    public void removeSessionCookies() {
        Log.d(LOG_TAG, "webViewHelper removeSessionCookies execute.");
        cookieManager.removeSessionCookie();
        threadSleep();
        this.httpClient = null;
        setDefaultCookies();
        CookieSyncManager.getInstance().sync();
    }

    private void threadSleep() {
        try {
            Thread.sleep(500);
        } catch (Exception e) {
            Log.d(LOG_TAG, "thread Exception!");
        }
    }

처럼 처리했다.

참고 사이트 : 

http://struts.apache.org/2.2.3/docs/struts-2-maven-archetypes.html


  메이븐을 이용하면 의존성을 가진 라이브러리들까지 손쉽게 다운로드 받아서 프로젝트를 생성할 수가 있다.

  2줄의 명령어만 넣어주면 된다.


스트럿츠 archetype을 생성하는 방법은 두 종류가 있다. 둘 중 마음에 드는 방법을 선택한다.


1.1. 메이븐의 archetype을 이용하여 스트럿츠 프로젝트를 생성(generate)한다.

  - 스트럿츠 2.2.3.1 버전을 사용했다. 

mvn archetype:generate -B
-DgroupId=tutorial
-DartifactId=tutorial
-DarchetypeGroupId=org.apache.struts
-DarchetypeArtifactId=struts2-archetype-blank

-DarchetypeVersion=<version>


1.2. 스트럿츠 archetype 을 생성한다. 
mvn archetype:generate -DarchetypeCatalog=http://struts.apache.org/

2. 메이븐으로 생성한 프로젝트를 이클립스에서 사용할 수 있는 프로젝트로 변경한다.

mvn eclipse:eclipse -Dwtpversion=1.5
이렇게 하면 된다. 
그럼 이클립스에서 사용할 수 있는 프로젝트가 간단하게 생성된다. 

1.2번과 2번을 같이하는 게... 편한 것 같기도 하다.


생성 과정 기록 : 


HoneyBook:dreaminfra ihoneymon$ mvn archetype:generate -DarchetypeCatalog=http://struts.apache.org/

[INFO] Scanning for projects...

[INFO]                                                                         

[INFO] ------------------------------------------------------------------------

[INFO] Building Maven Stub Project (No POM) 1

[INFO] ------------------------------------------------------------------------

[INFO] 

[INFO] >>> maven-archetype-plugin:2.1:generate (default-cli) @ standalone-pom >>>

[INFO] 

[INFO] <<< maven-archetype-plugin:2.1:generate (default-cli) @ standalone-pom <<<

[INFO] 

[INFO] --- maven-archetype-plugin:2.1:generate (default-cli) @ standalone-pom ---

[INFO] Generating project in Interactive mode

[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)

//원하는 유형을 선택하고 groupId, articleId 를 임의에 따라 지정한다.

Choose archetype:

1: http://struts.apache.org/ -> org.apache.struts:struts2-archetype-blank (Struts 2 Archetypes - Blank)

2: http://struts.apache.org/ -> org.apache.struts:struts2-archetype-convention (Struts 2 Archetypes - Blank Convention)

3: http://struts.apache.org/ -> org.apache.struts:struts2-archetype-dbportlet (Struts 2 Archetypes - Database Portlet)

4: http://struts.apache.org/ -> org.apache.struts:struts2-archetype-plugin (Struts 2 Archetypes - Plugin)

5: http://struts.apache.org/ -> org.apache.struts:struts2-archetype-portlet (Struts 2 Archetypes - Portlet)

6: http://struts.apache.org/ -> org.apache.struts:struts2-archetype-starter (Struts 2 Archetypes - Starter)

Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 1

Define value for property 'groupId': : StudyStruts

Define value for property 'artifactId': : StudyStruts

Define value for property 'version':  1.0-SNAPSHOT: : 

Define value for property 'package':  StudyStruts: : 

Confirm properties configuration:

groupId: StudyStruts

artifactId: StudyStruts

version: 1.0-SNAPSHOT

package: StudyStruts

 Y: : y

[INFO] ----------------------------------------------------------------------------

[INFO] Using following parameters for creating project from Archetype: struts2-archetype-blank:2.2.1

[INFO] ----------------------------------------------------------------------------

[INFO] Parameter: groupId, Value: StudyStruts

[INFO] Parameter: artifactId, Value: StudyStruts

[INFO] Parameter: version, Value: 1.0-SNAPSHOT

[INFO] Parameter: package, Value: StudyStruts

[INFO] Parameter: packageInPathFormat, Value: StudyStruts

[INFO] Parameter: package, Value: StudyStruts

[INFO] Parameter: version, Value: 1.0-SNAPSHOT

[INFO] Parameter: groupId, Value: StudyStruts

[INFO] Parameter: artifactId, Value: StudyStruts

[INFO] project created from Archetype in dir: /Users/ihoneymon/Documents/workspaces/dreaminfra/StudyStruts

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 15.347s

[INFO] Finished at: Wed Oct 12 10:45:18 KST 2011

[INFO] Final Memory: 7M/81M

[INFO] ------------------------------------------------------------------------

HoneyBook:dreaminfra ihoneymon$ cd StudyStruts/

HoneyBook:StudyStruts ihoneymon$ mvn eclipse:eclipse -Dwtpversion=1.5

[INFO] Scanning for projects...

[INFO]                                                                         

[INFO] ------------------------------------------------------------------------

[INFO] Building Struts 2 Blank Webapp 1.0-SNAPSHOT

[INFO] ------------------------------------------------------------------------

[INFO] 

[INFO] >>> maven-eclipse-plugin:2.8:eclipse (default-cli) @ StudyStruts >>>

[INFO] 

[INFO] <<< maven-eclipse-plugin:2.8:eclipse (default-cli) @ StudyStruts <<<

[INFO] 

[INFO] --- maven-eclipse-plugin:2.8:eclipse (default-cli) @ StudyStruts ---

[INFO] Adding support for WTP version 1.5.

[INFO] Using Eclipse Workspace: /Users/ihoneymon/Documents/workspaces/dreaminfra

[WARNING] Workspace defines a VM that does not contain a valid jre/lib/rt.jar: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home

[INFO] no substring wtp server match.

[INFO] Using as WTP server : VMware vFabric tc Server Developer Edition (Runtime) v2.5

[INFO] Adding default classpath container: org.eclipse.jdt.launching.JRE_CONTAINER

[INFO] Not writing settings - defaults suffice

[INFO] Wrote Eclipse project for "StudyStruts" to /Users/ihoneymon/Documents/workspaces/dreaminfra/StudyStruts.

[INFO] 

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 2.254s

[INFO] Finished at: Wed Oct 12 10:45:34 KST 2011

[INFO] Final Memory: 6M/81M

[INFO] ------------------------------------------------------------------------

HoneyBook:StudyStruts ihoneymon$ 

이클립스를 열고, 이 StudyStruts라는 폴더를 import하면 스트럿츠 라이브러리가 설치된 프로젝트를 바로 이용해볼 수 있다. 여기에는 간단한 예제 코드가 포함되어 있다. 이 프로젝트를 서버에 추가하고 실행해보면 다음처럼 나온다.

자! 스트럿츠를 시작해보자.

관련 사이트 : 

  - Joda Time : http://joda-time.sourceforge.net/quickstart.html

  - ICU4j calendar : http://userguide.icu-project.org/datetime/calendar#TOC-Calendar


쪼다타임(Joda time)은 자바의  Date, Time class를 대신할 수 있는 DateTime 클래스를 제공한다.   날짜, 시간 정보를 손쉽게 접근하고 가공할 수 있는 오픈소스다. 퀵스타트만 봐도 손쉽게 사용할 수 있다. ^^;

쪼다타임이 편리하기는 한데, 음력 처리를 해주지 못하는 걸 알고는 인터넷을 뒤져보다가 IBM에서 ICU(International Componenets for Unicode)라는 이름으로 제공하는 컴포넌트다. 그 중에 달력처리 부분에서 ChineseCalendar를 이용해서 음력처리가 가능한 것을 발견하고는 간단하게 테스트 코드를 작성해본다.

  
/**
 * Create Date : 2011. 10. 11.
 */
package honeymon.study.test;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;

import com.ibm.icu.util.ChineseCalendar;

/**
 * @author 허니몬
 */
public class LunarCalendarTest {
    
    private ChineseCalendar chineseCal;
    private DateTime dateTime;
    
    @Before
    public void setUp() {
        chineseCal = new ChineseCalendar();
        dateTime = new DateTime();
    }

    /**
     *  왜 중국음력에서 달에 +1을 하는 걸까?
     *  +1은 회합주기?
     *  2011/10/11 음력은 2011/09/15일
     */
    @Test
    public void 음력테스트() {
        chineseCal.setTimeInMillis(dateTime.getMillis());
        assertThat(chineseCal.get(ChineseCalendar.MONTH) + 1, is(9));
        assertThat(chineseCal.get(ChineseCalendar.DAY_OF_MONTH), is(15));
    }
}

+ Recent posts