안드로이드 하이브리드 앱을 만들 때 앱과 웹의 구분을 하고 싶어하는 경우가 있다.


언제 앱에서 오고, 언제 웹에서 오는 지 어떻게 구분하는 걸까?


생각해보니 보통은 제품을 사용하니까 제품에서 특정 스크립트를 제공하거나 통신 시에 앱에서만 특정한 정보를 전달하는 경우가 있는데...제품을 사용하지 않고, 그냥 하려면 어떻게 하는 게 좋을까하고 조금 생각해보았다.


그래서 든 생각이 앱에서 http request를 던질 때 header를 커스텀하는 것이 생각나서 해봤는데, 꽤나 괜찮은 방법이었다.


그래서 열심히 검색 -> http://stackoverflow.com/questions/7610790/add-custom-headers-to-webview-resource-requests-android



 WebView  host = (WebView)this.findViewById(R.id.webView);
 String url = "<yoururladdress>";

 Map <String, String> extraHeaders = new HashMap<String, String>();
 extraHeaders.put("Authorization","Bearer"); 
 host.loadUrl(url,extraHeaders);


키밸류를 가지는 해쉬맵을 하나 만들어서 헤더에 추가하는 방법이다. (API Level 8 부터 지원한다)


앱에서만 이 정보가 넘어오므로, 서버에서는 해당 정보를 보내는 녀석만 앱으로 인식하면 된다.



응? 그런데 무엇인가 이상하다...어떤 폰은 잘 되는데, 어떤 폰은 서버에서 그런 키가 없다고 한다.


무엇이 문제란 말인가???


헤더를 읽어보니 크로미움을 적용하는 킷캣부터는 헤더의 키 값이 모두 소문자로 보내진다.


아항...그렇구나.


그럼 소문자로 키와 밸류를 별도로 적용하기로 한다.


안드로이드 젤리빈까지는 헤더에 값을 넣은대로 서버에서 헤더가 인식되는데, 킷캣부터는 내가 커스텀한 헤더의 정보는 모두 소문자로 들어가는 이슈가 있었던 것.


이걸로 잠시 삽질을 했다.


안드로이드 킷캣(4.4 / API 19)부터 애플리케이션 내에서 이미지와 문서를 바로 프린트하는 기능을 제공한다.


프린트하는 기능들은 Android Support Library를 통해서 가능한데, V4 support library의 PrintHelper 클래스를 이용하면 쉽게 앱에서 이미지, html, 커스텀 문서의 프린터 출력을 할 수 있다.


참고 - http://developer.android.com/training/printing/index.html

동영상 - https://www.youtube.com/watch?v=Iub67ic87KI



구글의 가이드를 보니 꽤 쉬워보여서 예제 코드 넣고 바로 실행!


안드로이드 Android Support Library를 Android tools > Add Support Library… 통해서 추가하여 android-support-v4.jar 가 libs 폴더에 추가되었음에도 불구하고 정상적으로 라이브러리를 찾지 못했다.

이에 build path에서 private library에 체크가 안됐나? 하고 열어보니 체크가 되어 있다.
(Android Support Library rev 22 부터 private과 dependencies에 담기는 라이브러리 나눠짐)

이것은 미스터리…우째 이런 일이?

지금 사용하는 이클립스에 안드로이드 안드로이드 SDK 툴과 support library를 계속 업데이트하면서 Android SDK tools rev 21인가 22 업데이트 꼬여서 고생한 적이 있었는데…자꾸 그 생각이 난다.

아무튼, 해결 방법은 좀 당황스럽지만 v4 샘플 코드 프로젝트를 import해서 라이브러리를 직접 카피해서 프로젝트에 넣었더니 모두 잘된다. 헐…뭐야 이게.


어찌됐든 프린트는 잘 된다는 것이고, 다음과 같은 조건에서 프린트할 수 있다.


1) 네트워크 프린터의 경우 동일 네트워크에 프린터가 있을 경우 (일반 네트워크 프린터)

2) WiFi Direct 설정을 통해서 연동시킨 프린터가 있을 경우 (WPS 지원 프린터)

3) NFC 태그 프린팅을 지원하는 프린터가 있을 경우 (자체 프로그램을 사용할 수도 있음)


요즘 시중에 WPS 지원 프린터로 모바일 디바이스와 다이렉트로 연결할 수 있는 장비들이 나오고 있으니 그걸 이용하면 그냥 프린트할 수 있는데, 단말과 계속 붙이고 있으면 배터리가 빨리 줄어드는 것 같다. (배터리...배터리...모바일은 배터리)


프린터 사용할 때에만 연결하여 사용하면 될 것 같다.



날짜나 시간을 가져오기 위해서 어떤 방법이 있는 지 검색해봤다.


일단 날짜를 출력하기 위해서는 달력이 어떻게 되어 있는지, 시간이 어떻게 측정(?)되는 지 알아야 할 것 같아서 좀 더 검색을 해봤다.


출처 - http://bomber0.byus.net/index.php/2009/02/05/983


천체관측을 통해서 1년을 365일 5시간 48분 55초라고 하는데, 보니 365일과 약 1/4일이 1년이라는 이야기다.


4년 마다 약 하루씩의 날짜가 더 있기 때문에, 4년마다 윤년을 두고 2월에 하루를 더 추가하지만,  33년 마다 8일이 더 붙어서 100 = 33 * 3 + 1 , 400 = 33 * 3 * 4 + 4 라는 식을 활용한다면, 400년에는 8 * 3* 4 + 1 =97 일 정도가 더 필요해지게 되고, 이 오차를 수정하기 위해서 100년 마다 윤년을 건너뛰고 400년의 배수가 되는 해를 윤년으로 해서 100년간 97번의 윤년을 가지게 된다고 한다.


출처 - http://stackoverflow.com/questions/5369682/get-current-time-and-date-on-android

율리우스력 - http://en.wikipedia.org/wiki/Julian_calendar

그레고리력 - http://en.wikipedia.org/wiki/Gregorian_calendar


4년마다 율리우스력을 사용하던 방식에서 16세기 그레고리 교황 시기에 이 오차를 수정한 그레고리력을 사용을 시작했고, 댓글을 보니 1582년 10월 4일에서 1582년 10월 15일로 10일을 점프(기존 오차를 보정?)해서 적용했다고 한다.


아무튼 그렇다고 하니 그렇다.



안드로이드에서 시간을 얻는 방법을 좀 검색해보니 방법이 꽤 많다.


조 - http://developer.android.com/reference/android/os/SystemClock.html


우선 안드로이드의 시스템 시간을 얻어오는 방법들을 알아봤다.


안드로이드 시스템 시계는 android.os.SystemClock 클래스를 통해서 이용할 수 있는데, 몇 가지 특성이 있다.


1) System.currentTimeMillis()
System.currentTimeMillis()는 표준적인 시계로, 특정 시점(1970년 1월 1일 00:00:00.000)을 기준으로 현재의 시간을 밀리 초로 표시하는 시계로 데이터 타입은 long 이다. 

UTC(협정 세계시) 기준으로 사용자가 직접 시스템 시간을 설정하거나 네트워크 시간 받아오기를 선택함으로써 해당 시간을 시스템의 현재 시간으로 인지한다. (따라서 사용자가 현재와 다른 시간을 수동으로 설정하거나 장시간 네트워크가 끊어짐으로 오차가 발생할 여지는 있을 것 같다.)

이 시계는 캘린더 알람과 같은 앱에서 사용될 때 실제 시간과 일치하여 사용되기도 하고, 타임스탬프와 같은 항목에 적용할 수 있다고 한다. (음, 캘린더나 알람 등 실제 생활과 연결이 되는 앱을 만들때에는 현재의 시간이 네트워크를 통하여 동기화되어 있나를 체크해보는 것이 필요할 것이라는 생각이 든다.)

사실 별 생각없이 사용했는데, 그렇구나 하는 게 있다.


2) uptimeMillis()
uptimeMillis()는 시스템이 부팅된 이후의 시간을 밀리초로 표시하는 시계로, SystemClock.uptimeMillis()와 같이 사용되며 데이터 타입은 long 이다.

요 녀석의 특징은 시스템이 잠들면 시간이 멈춘다는 점이 특징이다. 잠든다고 표현한 항목들은 CPU의 off 상태, 화면이 꺼져서 검게된 상태, 그리고 외부 입력으로 인하여 시스템이 대기중인 상태 등이다. 그 외에 전력을 아끼기 위해서 화면이 어두워지거나 하는 등의 절전 상태에서는 이 시계는 잠들지 않는다.

이런 특징을 가지고 있기 때문에 앱이 실행 중인 상태에서 실행 시간 등을 체크하는 데 사용하면 될 것 같다. 예를 들면 게임에서 플레이 타임을 체크할 때 유용하지 않을까 생각이 든다.


3) elapsedRealtime(), elapsedRealtimeNanos()

이 녀석들은 시스템 부팅 이후 앱이나 시스템의 대기상태 등에 영향을 받지 않고 계속 시간을 체크하며, long 타입을 반환한다.


uptimeMillis()가 상태에 따른 시간의 흐름이 단절되는데 반해서 시스템 부팅 이후의 시간을 계속 체크하므로, 일반적인 목적의 시간 간격을 체크하는 기반으로 사용되면 좋다고 한다.



그 외에도 좀 읽을 거리가 많이 있기 때문에 위의 구글 주소에 들어가서 한 번 읽어보면 좋을 것 같다.





안드로이드 단말이 대개 하드웨어 키가 있는 것하고, 소프트 키가 있는데...레이아웃이 맞지 않는 경우가 종종 있다.

그래서, RelativeLayout으로 위젯들을 배치하는 것도 괜찮지만 아무래도 전체 화면을 모두 동일하게 사용하고 싶은 경우가 발생한다.


안드로이드 4.0 이후(API Level 14)부터 하단 네비게이션 바(Navigation bar)와 상단의 상태바(Status bar)를 감추는 옵션을 제공했다. 

킷캣(API Level 19)부터는 Immersive mode를 제공한다.


관련 URL - https://developer.android.com/training/system-ui/immersive.html


네비바와 상태바를 사용자의 화면 상단을 끌어서 표시하고, 터치로 감추려면 다음과 같이 하면 된다.



public void onWindowFocusChanged(boolean hasFocus) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {  

if (hasFocus) {

getWindow().getDecorView().setSystemUiVisibility(

View.SYSTEM_UI_FLAG_LAYOUT_STABLE

| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION

| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION

| View.SYSTEM_UI_FLAG_FULLSCREEN

| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

}

}

}

 



국내에서는 이클립스를 주로 사용하지만 구글이 Android Studio 기반에 Gradle 사용을 통한 플러그인 관리 등을 권장하고 있다.


지난 달에 아마존에서 구입한 파이어폰을 이클립스에 물려보니 DDMS에서는 폰 자체는 인식하는데, 빌드할 때 폰이 보이지 않아서 좀 찾아보니 얘네도 이클립스보다는 이런 환경을 설정해서 사용하길 권한다. 


https://developer.amazon.com/public/resources/development-tools/ide-tools/tech-docs/01-setting-up-your-development-environment#Using%20the%20Eclipse%20IDE


아마존 XML 리소스를 읽지 못하는 거라고 하는데, 일단 가이드에 따라서 ADB를 실행 후에 User Define Site에 해당 주소를 추가하여 파이어폰 SDK와 EXTRA에서 필요한 파일들을 모두 설치했다.


https://developer.amazon.com/public/solutions/devices/fire-phone/docs/connecting-your-device


흠...아무튼...

하아~ 안드로이드는 적응이 잘 안된다.

안되는 것 없이 다 되기는 하는데...이러나 저러나 적응이 안돼. -_-;;


아이폰에서는 뭐...탭 메뉴나 테이블 등과 같이 데이터를 순차적으로 나열하여 보여주고 네비게이션하기 쉽게 되어 있는데...안드로이드를 처음 접하는 입장에서 이것 참 쉽지 않다.


데모 형태의 앱을 만들면서 첫 목표는 DB(SQlite)의 활용, 탭 메뉴 생성, 메뉴 내에서의 네비게이션 등을 익히는 일이다. 


아무튼, 탭 메뉴를 만드는 방법은 몇 가지가 있다.



1. TabActivity를 사용하는 방법

deprecated 됐다고 한다. 하지만 아직 사용은 가능하다. 또 하지만 대부분의 사람들이 이걸 사용하는 것보다 다른 것을 권장한다. 그 이유는 꽤나 많다.


예제 - http://www.androidhive.info/2011/08/android-tab-layout-tutorial/


하나의 탭 내에서 액티비티간 이동(세부 내용 보기 등)을 위해서는 ActivityGroup을 이용한다.

하지만 이것도 deprecated 되어 있는 상태. ㅋㅋㅋ


예제 - http://richipal.com/post/2624844577


요거는 한 번 해봤는데...이전 액티비티로 안돌아오고 그냥 종료되네...ㅋㅋㅋ 뭔가 실수한 듯.

다시 한 번 확인해봐야할 지...FragmentActivity를 사용할 지...더 나은 무료 공개 소스를 이용할 지 생각 좀 해봐야 할 듯.


2. FragmentActivity 사용하는 방법

3.0 이후로 TabActivity 사용이 deprecated 되어 있어서 권장하는 방식이다.

코드가 좀 늘어 났다.


예제 - http://android.codeandmagic.org/2011/07/android-tabs-with-fragments/



3. Custom Tab Menu 만들기

실무 작업자들이 권하는 방식은 이미지뷰나 버튼을 활용해서 커스텀 탭 메뉴를 만드는 방식이다.

이미지는 나인 패치를 이용해서 만들면 괜찮을 것 같다.


http://www.androidside.com/bbs/board.php?bo_table=B49&wr_id=81870

http://darphin.tistory.com/22


이미지 리소스를 조금이라도 줄여볼까 하는 생각으로 배경 이미지를 패턴으로 깔아주는 것에 대해서 좀 알아 보았다.


아이폰에서는 쉽게 아래와 같이 하면 패턴이 적용된다.


1:    [self.view setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"bg_pattern.png"]]];  


안드로이드에서는 어떻게 하는 지 좀 알아봤다.


1. xml을 이용한 배경 이미지 패턴 설정

xml을 이용하는 방법은 일반 레이아웃 사용할 때 활용하면 될 듯하다.

적용한는 방법은 간단하다.


1) Drawable 폴더에 비트맵 xml  파일을 만든다. (background_pattern.xml로 만든다)

타일 이미지 리소스를 지정하고 tileMode를 "repeat"로 하면 된다. (titleMode에는 clamp, micro, repeat 가 있다)

1:  <?xml version="1.0" encoding="utf-8"?>  
2:  <bitmap xmlns:android="http://schemas.android.com/apk/res/android"  
3:    android:src="@drawable/bg_pattern"   
4:    android:tileMode="repeat" />  


2) 해당 xml을 패턴을 설정할 레이아웃의 background로 지정하면 된다.

1:  <?xml version="1.0" encoding="utf-8"?>  
2:  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
3:    android:id="@+id/MainLayout"  
4:    android:layout_width="fill_parent"  
5:    android:layout_height="fill_parent"  
6:    android:orientation="vertical"  
7:    android:background="@drawable/background_pattern">  
8:  </LinearLayout>  




2. 코드로 배경 이미지 패턴 설정

1:  BitmapDrawable bg;  
2:  bg = new BitmapDrawable(BitmapFactory.decodeResource(getResources(),R.drawable.bg_pattern));  
3:  bg.setBounds(0, 0, getWidth(), getHeight());  
4:  bg.setTileModeX(Shader.TileMode.REPEAT);  
5:  bg.draw(canvas);  

코드로도 간단하게 배경을 채울 수 있다.

드로우하는 코드 안에서 BitmapDrawable을 하나 생성해서 리소스를 읽고, 해당 리소스를 전체 화면의 영역을 얻어와서 해당 영역에 타일 반복으로 캔버스에 그려주면 된다.


안드로이드나 자바나 거의 하나도 모르는 상태에서 하나 하나 찾아보고 있다.


SQLite  파일을 미리 생성해서 앱 패키지에 추가하고 싶은데, 책을 찾아보니 그런 내용들은 나와 있는 것이 별로 없다. 대부분 앱 실행 시 생성하고 추가, 검색, 삭제 등에 대한 부분을 다루고 있다.


그래서 일반적인 sqlite 사용법을 다룬 글들을 모두 제외하고, 

검색을 통해서 관련된 괜찮은 글들을 몇 개 추려 봤다.



1. apk에 sqlite 파일을 넣어서 사용하기

http://stackoverflow.com/questions/513084/how-to-ship-an-android-application-with-a-database

http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/



2. 대용량 sqlite 파일을 잘라서 사용하기

http://www.chriskopec.com/blog/2010/mar/13/deploying-android-apps-with-large-databases/


작성자 글을 보면 1메가 이상의 raw 파일의 경우 안드로이드에서 제한을 걸고 있는 것 같다. 그래서 1메가 이상의 파일은 잘라서 사용해보니 잘 되더라라는 글이다.


2012.08.13 추가

좀 더 검색을 해보니...asset 폴더에 확장자를 일반 리소스처럼해서 집어 넣고, 데이터베이스를 읽어서 data/data 폴더에 저장할 때 .sqlite 확장자를 붙이면 된다고 한다.


http://dhna.tistory.com/185


자세한 것은 위의 블로그로...


일단 데이터베이스를 담고 서비스를 하는 것과 사용자가 데이터베이스를 생성해서 사용하게 하는 것 가운데 후자가 바람직하고 그 권한이 사용자에게 있으므로 좋을 것 같기는 하지만, 그렇지 않은 서비스도 있으니 이것이 문제.


아무튼, 그러하다...이제 테스트해봐야겠당.


웹에서 데이터베이스를 다운로드 받아서 SD카드에 저장하게 할 수도 있을 것 같지만 일단은 별도의 네트워크 연결 없이도 사용할 수 있도록 하려면 위의 방법을 사용해야 할 듯.



+ Recent posts