세가지 언어가 최근에 화두가 되고 있는 언어이며 주요 플랫폼의 개발언어이다.

자바개발자가 ObjectiveC를 배울때 어렵고 힘들어하는 부분이 있으며 역으로 ObjectiveC개발자가 자바를 배울때 어려와 하는 부분들이 있다. C#을 포함하여 모두 객체지향 언어로 일맥상통하는 부분이 있기 때문에 이런 부분들에 대해 정리하여 서로 다른 플랫폼개발자가 다른 언어를 배우는데 있어서 좀더 쉽게 배울수 있는 자료를 작성하려고 한다.


Posted by 삼스
Android/Porting2013. 9. 24. 09:53


안드로이드 오픈소스를 풀빌드하려고 하면 몇시간씩 걸리게 된다. 최초 빌드는 그렇게하겠지만 일부만 수정한 경우는 일부만 빌드하고자할것이다. 

1. 안드로이드 소스 디렉토리로 이동한다.

2. 빌드환경을 셋팅

  #. build/envsetup.sh 

3. 빌드타겟을 설정한다. 환경마다 조금씩 다르겠지만 choosecombo나 lunch로 하게 되어 있다.

4. 부분빌드를 수행한다.

부분빌드는 Android.mk파일을 대상으로 진행한다. 빌드하고자 하는 부분의 Android.mk파일을 mmm으로 실행한다.

#mmm packages/app/Launcher2

mm은 해당 경로로이동 후 빌드하는것으로 mmm과 이 부분만 제외하고 동일한 작업을 한다.

빌드결과는 다음 경로아래에 lib이나 app에 위치하게 된다.

out/target/product/MODELNAME/system


Posted by 삼스
Windows2013. 9. 13. 11:46


http://msdn.microsoft.com/en-us/library/windows/apps/hh913756.aspx

윈도우 스토어앱을 위한 푸시서비스에 대한 MS문서 정리임


윈도우푸시서비스는 3rd party개발자가 자신의 클라우스서비스를 통해 토스트, 타일, 뱃지 또는 데이터를 전송할 수 있는 방안을 제공한다. 

어떻게 동작하나?

다음 그림이 설명하고 있다.

1. 앱이 Notification Client Platform에 푸시채널을 요청한다.

2. Notification Client Platform은 WNS에 새로운 푸시채널을 질의하여 URI형태로 반환한다.

3. 앱은 푸시채널URI를 얻게 된다.

4. 당신의 클라우드서비스에 이 URI를 전달한다. 이 때 보안은 알아서 하길 바란다.

5. 클라우드서비스에서 업데이트내용을 전송하려면 채널URI로 SSL을 통해 HTTP POST request를 수행한다. 이 과정은 인증이 필요하다.

6. WNS는 request를 받아서 해당 디바이스에 전달한다.


이와 같이 안드로이드 GCM이나 애플의 APNS와 동작구조은 대동소이하다.

앱등록 및 클라우드서비스의 credential얻기

WNS로 푸시를 전송하기 전에 앱을 윈도우 스토어 대시보드에 반드시 등록해야 한다. 그러면 클라우드서비스에서 WNS에 인증할때 사용 가능한 credential을 발급해준다. 이 credential은 Package Security Identifier(SID)와 secret Key를 포함한다. https://appdev.microsoft.com/StorePortals/ko-KR/Home/Index?wa=wsignin1.0 <-여기(Windows Store app development)페이지에 가서 Windows Dev Center -> Dashboard에서 이 과정을수행할 수 있다.

앱과 credential은 쌍으로 관리되며 다른 앱에는 사용될 수 없다.
앱 등록에 대한 더 자세한 사항은 http://msdn.microsoft.com/en-us/library/windows/apps/hh465407.aspx <- 여기를 참조.

푸시채널 요청





Posted by 삼스
Windows2013. 9. 12. 17:54


Bouncy Castle은 자바와 C#을 지원하는

암호화관련 거의 모든 API들이 총 망라되어 있는 오픈소스이다.

아래 주소는 그 중에서 WinRT와 WP8의 오피셜사이트이다.

http://w8bouncycastle.codeplex.com/



Posted by 삼스


EPG를 추출하기 위해 필요한 DVB-SI에 대해 분석한다.

주요 섹션은 다음과 같다.

NIT 현재 네트워크(방송국)에서 송출되는 모든 네트워크정보를 표현 BAT 1개이상의 채널을 하나의 그룹으로 지정함 SDT 서비스(채널)의 정보를 포함 EIT 특정서비스에 해당하는 프로그램(이벤트)의 정보를 송출함. TDT, TOT는 시간값을 송출하며 수신기는 자신의 시간을 이 값을 사용하며 맞출 수 있다.


NIT나 BAT는 부가적인 정보로 간주하고 SDT와 EIT로 프로그램가이드를 구성하는 방법에 대해 정리하겠다.


SDT 구조

service_description_section(){ 

    table_id

    section_syntax_indicator
    reserved_future_use
    reserved
    section_length
    transport_stream_id
    reserved
    version_number
    current_next_indicator
    section_number
    last_section_number
    original_network_id
    reserved_future_use
    for (i=0;i<N;i++){

        service_id 

        reserved_future_use 

        EIT_schedule_flag 

        EIT_present_following_flag 

        running_status 

        free_CA_mode 

        descriptors_loop_length 

        for (j=0;j<N;j++){

            descriptor()
        }

    }

    CRC_32 


PID는 0x011이며 table_id는 0x42(actual), 0x46(other)가 있다.

EIT_schedule_flag : 1이면 서비스의 EIT schedule 정보가 현재 TS에 포함됨을 의미한다. TR101 211에 더 자세한 정보가 기술되어 있다. 0이면 현재 TS에 EIT schedule정보가 없음을 의미한다.

EIT_present_following_flag : 1이면 서비스의 EIT present following정보가 현재 TS에 포함됨을 의미한다. TR101 211에 더 자세한 정보가 기술되어 있다. 0이면 현재 TS에 EIT present following 정보가 없음을 의미한다.

running_status : 서비스의 현재 상태를 나타낸다.

 0

undefined 

 1

not running 

 2

starts in a few seconds(e.g. for video recording) 

 3

pausing 

 4

running 

 5

reserved for future use 

free_CA_mode : 켄텐츠가 스크램블되었는지를 나타냄.


EIT

PID는 0x0012이고 table_id다음과 같다.

  1. 1)  actual TS, present/following event information = table_id = "0x4E";

  2. 2)  other TS, present/following event information = table_id = "0x4F";

  3. 3)  actual TS, event schedule information = table_id = "0x50" ~ "0x5F";

  4. 4)  other TS, event schedule information = table_id = "0x60" ~ "0x6F". 


event_information_section(){ 

    table_id

    section_syntax_indicator
    reserved_future_use
    reserved
    section_length
    service_id

    reserved
    version_number 

    current_next_indicator 

    section_number 

    last_section_number 

    transport_stream_id 

    original_network_id 

    segment_last_section_number 

    last_table_id 

    for(i=0;i<N;i++){

        event_id
        start_time
        duration
        running_status
        free_CA_mode
        descriptors_loop_length
        for(i=0;i<N;i++){
            descriptor()
        }

    }

    CRC_32 


service_id : 이벤트가 소속되는 서비스(채널)아이디

segment_last_section_number : sub_table을 가지는 경우 마지막섹션의 개수. 아닌경우 last_section_number와 동일하다.

last_table_id : table이 하나로만 구성되면 이 table과 동일 table_id이며 여러개로 구성된 경우 마지막 table_id를 나타낸다.

event_id : 이벤트를 구별하는 아이디

start_time : 프로그램 시작시간, UTC시간이며 시작시간이 정해지지 않은 경우 모든 비트가 1이다. 앞에서부터 16비트가 년월일이고 MJD포맷이다. 이어서 24비트가 4비트씩 시분초를 의미한다.

EXAMPLE 1: 93/10/13 12:45:00 is coded as "0xC079124500".

duration : 프로그램 방영시간.  24비트로 4비트씩 시분초를 의미한다.

running_status : 현재 상태를 의미한다.

free_CA_mode : 스크램블 여부를 의미한다.

 

Descriptors

각 섹션별로 추가적인 정보들이 디스크립터로 기술이 된다. 상당히 많은 디스크립터들이 정의되어 있으며 이 중에 필요한 디스크립터들만 추출해도 EPG정보구성에는 문제가 없다.

디스크립터 목록에 대한 정보는 tr101211에 기술되어 있고, 디스크립터에 대한 상세한 구조는 en_300468에 기술되어 있다.

SDT와 EIT의 디스크립터 목록은 다음과 같다.


SDT descriptors

- Announcement support descriptor

- Bouquet name descriptor

- CA identifier descriptor

- Country availability descriptor

- Data broadcast descriptor

- Linkage descriptor

- Mosaic descriptor

- Multilingual service name descriptor

- NVOD reference descriptor

- Service descriptor

- Service availability descritor

- Telephone descriptor

- Timeshifted service descriptor


EIT descriptor

- CA identifier descriptor

- Component descriptor

- Content descriptor

- Data broadcast descriptor

- Extended event descriptor

- Linkage descriptor

- Multilingual component descriptor

- Parental rating descriptor

- PDC decriptor

- Short event descriptor

- Telephone descriptor

- Time shifted event descriptor



Posted by 삼스
iOS2013. 8. 29. 02:10


아이폰 코드공유의 문제점

모두다 알다시피 애플은 개발자에세 아이폰용 프레임웍을 만들 수 있는 기회를 제공하지 않는다. 하지만 많은 경우 서로 다른 프로젝트나 개발자들에게 코드를 배포해야 하는 경우가 있다.

대안

몇가지 코드공유나 배포를 위한 방안이 있다. 

첫번째는 코드자체를 공유 및 배포 가능하게 하는것이다. 이 방법은 XCode가 관련 매커니즘을 제공하지만 개발자가 디펜던시나 헤더파일 경로등을 추가로 해주어야 하는 불편함이 있다.

두번째는 코드가 아니라 static library로 배포하는것이다. 잘 알려진 방법이고 리눅스/유닉스 개발자를 비롯해서 아주 많은 개발자들에게 익숙한 방법이다. 하지만 몇가지 불편함이 있는데.  static library는 C/C++코드로 작성이 되어지고 Objective-C의 property나 category를 사용할 수 없다. category를 static library에 추가하려면 명시적으로 링커옵션을 주어야 한다.

-ObjC

-all_load

개발자가 위 옵션을 깜박하면 런타임에러가 발생하게 된다."unrecognized selector sent to instance"


Static Framework

가장 좋은 방법은 'static framework'라고 생각한다. 이 방법은 컴파일러에게 이 라이브러리가 일반적인 아이폰 프레임웍인것처럼 인식하도록 하는 것이다. 공유하고 싶은 static library가 있다면 아주 쉽게 framework으로 만들 수 있다. 그리고 이런 프레임웍은 개발자에게 프로젝트에 추가하는것 말고 추가로 아무것도 시키지 않는다.


어떻게 만들지??

XCode에서 프레임웍으로 빌드하는 방법을 제공하지 않으므로 XCode MacOS framework template로 빌드해야 한다. 일반적인 프레임웍과 동일한 구조를 가지며 몇가지 추가적인 절차가 있다.

1. simulator와 device용을 하나로 만듦

2. framework bundle에 이전 단계에서 프레임웍 번들로 추가한다.

쉽게 작업하기 위해 쉘스크립트를 사용할것이다. lipo유틸을 사용할것인데 이 유틸은 라이브러리 여러개를 하나로 묶어주는 유틸리티이다. 마지막에 이 파일은 프레임웍번들에 복사되고 전용 링크가 생성될것이다.

FRAMEWORK=”${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework”
lipo \”${BUILD_DIR}/${CONFIGURATION}-iphoneos/libDev.a” “${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/lib Sim.a” -create -output “${FRAMEWORK}/Versions/Current/${PRODUCT_NAME}”cd “${FRAMEWORK}” && ln -sf “Versions/Current/${PRODUCT_NAME}” ./

위 스크립트는 프로젝트의 빌드페이즈에 스크립트로 추가된다.
위 과정을 거치면 이젠 코드를 포함하는 프레임웤을 쉽게 공유할 수 있다.


Posted by 삼스
iOS2013. 8. 28. 23:01


3rd party library를 사용하다보면 서로 같은 심볼을 사용하게 되어서 아래와 같은 링크에러가 나는 경우가 종종 있다.

ld: duplicate symbol .objc_class_name_CJSONScanner in /Users/myappOne/TapjoyConnect/Frameworks/libTapjoyConnectSimulatorRewardInstall_Ads_Pinch.a(CJSONScanner.o) and /Developer/Projects/BuildOutput/Debug-iphonesimulator/OtherLibrary_d.a(CJSONScanner.o)
이 경우 해결 방법을 정리하겠다.

2개의 3rd party library가 있고 소스가 없는 상황을 가정한다.
libtool, lipo, ar명령으로 라이브러리를 extract하고 recombine한다.

먼저 라이브러리가 어떤 아키텍쳐를 지원하는지 확인한다.

$ lipo -info libTapjoy.a
Architectures in the fat file: libTapjoy.a are: armv6 i386

armv6와 i386를 지원하는것을 알 수 있다. 여기서 armv6를 extract한다.

$ lipo -extract_family armv6 -output libTapjoy-armv6.a libTapjoy.a
$ mkdir armv6
$ cd armv6
$ ar -x ../libTapjoy-armv6.a

같은 방법으로 다른 라이브러리의 동일아키텍쳐를 extract하는데 같은 디렉토리에 한다. 그리고 다음과 같이 다시 recombine한다.

$ libtool -static -o ../lib-armv6.a *.o

아키텍쳐별로 이 과정을 마친 후 다시 lipo로 합친다.

$ cd ..
$ lipo -create -output lib.a lib-armv6.a lib-i386.a




Posted by 삼스
iOS2013. 7. 15. 17:57


#import <Cocoa/Cocoa.h>

@interface NSMutableArray (variadicMethodExample)

- (void) appendObjects:(id) firstObject, ...; // This method takes a nil-terminated list of objects.

@end

@implementation NSMutableArray (variadicMethodExample)

- (void) appendObjects:(id) firstObject, ...
{
id eachObject;
va_list argumentList;
if (firstObject) // The first argument isn't part of the varargs list,
  {                                   // so we'll handle it separately.
  [self addObject: firstObject];
  va_start(argumentList, firstObject); // Start scanning for arguments after firstObject.
  while (eachObject = va_arg(argumentList, id)) // As many times as we can get an argument of type "id"
      [self addObject: eachObject]; // that isn't nil, add it to self's contents.
  va_end(argumentList);
  }
}

@end


Posted by 삼스
iOS2013. 7. 15. 14:40


출처 : http://nickeys.tistory.com/archive/201108


SQL DB 엔진의 주 목적은 SQL문장을 평가 하는 것이다. 그걸 위해서, 개발자는 두 개의 객체에 대해 알 필요가 있다:

1) The database connection object: sqlite3
2) The prepared statement object: sqlite3_stmt

엄격히 따지자면, prepared_statement 객체는 꼭 필요한건 아니긴 하지만 편의를 위해서 wrapper 인터페이스들(sqlite3_exec 또는 sqlite3_get_table등)이 사용될 수 있다. 그래도, prepared statements에 대한 이해는 SQLite를 잘 사용하기 위해선 필수적이다.

The database connection과 prepared statement 객체들은 아래에 나열된 C/C++ 인터페이스 루틴의 소 집합에 의해 조작된다.

● sqlite3_open()
● sqlite3_prepare()
● sqlite3_step()
● sqlite3_column()
● sqlite3_finalize()
● sqlite3_close()

위의 루틴들의 리스트는 실재 존재하는 것이 아닌(actual) 개념적이라는 것을 알아 두자. 이 루틴들은 다양한 버전이 존재한다. 예를 들면, 사실 약간 다르긴 하지만 같은 용도의, 세 개의 분리된 루틴들(sqlite3_open(), sqlite3_open16(), sqlite3_open_v2())이 있고 위의 리스트 에서는 sqlite3_open()이라는 싱글 루틴을 보여준다. 위의 리스트에서 보여지는 "sqlite_column()"은 다양한 타입의 열 데이터를 추출하는데 사용되는 루틴들의 전체 군에 대한 place holder이다.

각각의 코어 인터페이스들의 요약이 있다:

sqlite3_open()   이 루틴은 SQLite DB파일을 열고 DB 연결 객체를 반환 한다. 이 루틴은 응용프로그램이 빈번하게 제일 먼저 호출 하는데, 대부분의 SQLite API들의 선행 조건이기 때문이다. 많은 SQLite 인터페이스들은 첫 번째 인자로 DB 연결에 대한 포인터를 요구한다. 이 루틴은 DB 객체의 생성자 역할을 한다고 할 수 있겠다.

sqlite3_prepare()  이 루틴은 SQL 문장을 prepared statement 객체로 전환하고 그 객체에 대한 포인터를 반환한다. 이 인터페이스는 앞에서 sqlite3_open()을 호출해서 만들어진 DB 연결 객체의 포인터와 SQL 문장을 포함한 문자열을 인자로 받는다. 이 API는 실재로 SQL 문장을 평가하는 것이 아니고 단지, SQL 문장에 대한 평가를 준비하는 단계이다.
새로운 응용 프로그램에서 sqlite3_prepare()의 사용은 추천되지 않는다는 것을 알아두라. 대신 sqlite3_prepare_v2()를 사용하는 게 낫다.

sqlite3_step()  이 루틴은 sqlite3_prepare() 인터페이스에서 생성된 prepared statement를 평가한다. 해당 문장은 결과의 첫 번째 행에 대한 포인터에 대해 평가 된다. 다음 열에 대해 계속해서 진행하려면, sqlite3_step()을 다시 호출하라. 해당 문장이 끝날 때까지sqlite3_step()을 계속 수행하라. 결과를 반환하지 않는 문장들(INSERT, UPDATE, DELETE)은 sqlite3_step()을 한번 호출해도 완료 된다.

sqlite3_column()  이 루틴은 sqlite3_step()에 의해 평가되고 있는 prepared statement에 대한 결과 집합의 현재 튜플로 부터 한 열을 반환한다. sqlite3_step()은 매번 새로운 결과 집합 튜플에서 멈추는데, 이 루틴은 해당 튜플에서 모든 열들의 값을 찾기 위해 여러번 호출 될 수 있다(한 튜플은 여러 열로 이뤄 지므로). 위에서 명시 된 것 처럼, SQLite API에는 "sqlite3_column()" 함수와 같은 것은 정말로 없다. 대신, 여기서 sqlite3_column()을 호출하는 것은 다양한 타입의 결과 집합으로 부터 한 값을 반환하는 함수들의 전체 집합에 대한 place holder라는 것이다. 그 결과(문자열이나 BLOB데이터일 경우)의 사이즈와 결과 집합에 있어 열의 수를 반환하는 함수 군에는 여러 루틴들이 있다.


● sqlite3_column_blob()
● sqlite3_column_bytes()
● sqlite3_column_bytes16()
● sqlite3_column_count()
● sqlite3_column_double()
● sqlite3_column_int()
● sqlite3_column_int64()
● sqlite3_column_text()
● sqlite3_column_text16()
● sqlite3_column_type()
● sqlite3_column_value()

sqlite3_finalize()  이 루틴은 sqlite3_prepare()의 호출로 부터 만들어진 prepared statement를 파괴한다. 모든 prepared statement는 메모리 누수를 막기 위해서 이 루틴을 호출해서 파괴되어야 한다.

sqlite3_close()  이 루틴은 이전에 sqlite3_open()을 호출함으로써 만들어진 DB연결을 닫는다. 모든 해당 연결에 관련된 prepared statement들은 해당 연결이 닫히기 전에 종결 되어야 한다.


Posted by 삼스
Android/App개발2013. 7. 11. 19:13



private void getMusicMetaInfo(String fileStr) {

Uri fileUri = Uri.parse(fileStr);

String filePath = fileUri.getPath();

Cursor c = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null,"_data ='" + filePath + "'",null,null);

c.moveToNext();

if(c.getCount()>0) {

int id = c.getInt(0);

Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,id);

Log.d(LOG_TAG, fileStr + "'s uri : " + uri.toString());

Cursor cur = managedQuery(uri, null, null, null, null);

if(cur.moveToFirst()) {

Log.d(LOG_TAG, "==============================");


// int artistColumn = cur.getColumnIndex(MediaStore.Audio.AlbumColumns.ARTIST);

Log.d(LOG_TAG, "타이틀 : " + cur.getString(cur.getColumnIndex(MediaStore.Audio.AudioColumns.TITLE)));

Log.d(LOG_TAG, "아티스트 : " + cur.getString(cur.getColumnIndex(MediaStore.Audio.AlbumColumns.ARTIST)));

Log.d(LOG_TAG, "앨범 : " + cur.getString(cur.getColumnIndex(MediaStore.Audio.AlbumColumns.ALBUM)));

Log.d(LOG_TAG, "재생시간 : " + cur.getString(cur.getColumnIndex(MediaStore.Audio.AudioColumns.DURATION)));


Log.d(LOG_TAG, "==============================");

}

}

c.close();

Log.d(LOG_TAG, "");

}

Posted by 삼스