이 글은 안드로이드 레퍼런스 폰의 팩토리 이미지를 빌드하는 방법에 관하여 간단히 설명해 놓은것입니다.


솔직히 설명할 필요도 없이 아래 세 개의 링크만 클릭하면 모든 설명들이 자세하게 되어 있지만, 약간의 예외 및 기타 잡다한 참견들을 추가하도록 하겠습니다. ^^;


https://source.android.com/setup/build/initializing

https://source.android.com/setup/build/downloading

https://source.android.com/setup/build/building



참고로 위 세 개의 링크만 잘 읽어보면, 쉽게 빌드할 수 있지만, 알고보면, 그렇게 쉽지 않은 이유는 조그마한 환경변수나 버전이 하나만 틀어져버려도 에러가 발생할 수 있기 때문입니다.

그래서, 필자도 처음에는 Mac OS 에서 빌드를 시작해서 결국, Mac OS 위 VmWare Fusion 30일용 + Ubuntu 14.04  에서 몇 번 실패한 끝에 겨우 빌드에 성공했습니다.


일단, Ubuntu 14.04 를 설치한 황을 가정하고 설명을 시작하겠습니다. 이유는 제가 빌드에 성공한 버전이기도 하지만, 그나마 예외적인 사항들이 적은 편이기 때문입니다.


https://source.android.com/setup/build/requirements 를 보면 먼저 간단한 요구사항들이 있습니다.


JDK

See Installing the JDK for the prebuilt path and installation instructions for older versions.



그 중 가장 중요한 것은 어떤 버전을 빌드할 것인가 입니다. 이를 테면, Lollipop 을 빌드한다고 하면,  Java 1.7 이 필요합니다. 최신의 Nougat 이상을 빌드하고 싶다면, 현재 보통 사용하고 있는 1.8 을 그냥 사용 하면 되겠지만, 그 이전 버전일 경우에는 위 표를 반드시 알고 미리 준비해두어야 합니다. 만약, JAVA 버전이 다를 경우, 빌드시 에러가 발생합니다.



이후에는 https://source.android.com/setup/build/initializing 에 따라 14.04 에 해당하는 명령을 실행해주면 됩니다. 위 그림에서 '클릭하여 복사' 하여 실행하셔도 됩니다. 



이젠 소스를 다운로드 받아야 합니다. https://source.android.com/setup/build/downloading 에 따라 소스를 받으면 되는데, repo 설정과 그외 부분은 위 그림에서와 같이 '클릭하여 복사'를 잘 이용하시면 편리합니다. 가장 중요한 것은 어떤 브랜치를 가져올것인가 입니다. 

아래 그림에서 'repo init - u https://android.googesource.com/platform/manifest -b android-4.0.1_r1' 에서 android-4.0.1_r1 에 해당하는 부분인데요.

푸른 색 글씨의 Source Code Tags and Builds 링크를 따라가서 무엇을 받을지를 결정하셔야 합니다.




저는 Nexus6P 를 빌드해야 했기 때문에 Nexus6P 를 검색해서 실제 Factory Image 가 올라와있는 버전(MDB08K)을 선택했습니다.




https://developers.google.com/android/images 에서 미리 자신이 가지고 있는 단말의 Factory Image 를 미리 받아서 언제든 원복 시킬수 있거나 소스코드를 수정했을 때, 본래 이미지와 비교할 수 있는 버전을 받아 놓는게 좋습니다. 팩토리 이미지를 설치하는 방법은 다음 글에서 설명해드릴게요.



그래서 저는 'repo init - u https://android.googesource.com/platform/manifest -b android-6.0.0_r24' 로 다운로드를 받았습니다.

그리고, 페이지의 설명대로 'repo sync' 를 시작하면 다운로드를 시작합니다.

주의하실 점은 소스 자체의 크기는 그렇게 크다고 볼 수 없지만, 요즘은 git 정보가 너무 많아서 다운로드에만 50G 이상이 사용됩니다. 빌드할 때 여유공간까지 생각하면 150G 정도의 충분한 여유공간을 만들어 놓는 것이 좋습니다. 

물론, 정보를 적게 가져오는 방법이 있기는 하지만, 여기서는 일단 스킵하고 최대한 많은 여유공간을 확보해두시는 걸 권장해드리고 싶습니다.

그리고, 다운로드 받는데도 꽤 오랜 시간이 걸립니다. 족히 한시간은 걸렸던 걸로 기억이되네요.


다운로드를 받고나서 빌드를 하는 과정은 오히려 어렵지 않습니다. https://source.android.com/setup/build/building 에 나온 대로 'make clobber' -> 'source build/envsetup.sh' -> 'lunch' -> 'make -j4' 순서로 실행해 주시면 됩니다.



사이트에서는 'lunch aosp_arm-eng' 를 예로 들었는데, 'lunch' 만 실행해 보시면 아래와 같이 옵션이 많이 있다는걸 알게됩니다.



저는 Nexus6P 의 코드네임 angler 를 따라 17번  aosp_angler-userdebug 를 선택해서 빌드했습니다.



BUILD_ID=MDB08K 를 보내 뭔가 제대로 된 느낌입니다. ^^; 

'make -j4' 로 빌드를 시작하면 됩니다. 빌드 환경에 따라 -j2 혹은 -j8 로 시작하셔도 됩니다. 숫자가 클수록 빨리 끝나기는 합니다. 그래도 최소 한시간정도는 기다려야 합니다.

빌드가 성공적으로 끝나면 /WORKING_DIRECTORY/out/target/product/[target_code_name] 에 이미지가 생성됩니다.

저는 Nexus6P 이기 때문에 angler 디렉토리에 생성되어 있습니다.



이렇게 빌드된 이미지 파일들을 단말에 설치하면 됩니다. 설치 방법은 다음글에서 안내해 드릴게요.

Compile 은 안드로이드 상위 버전(예: sdkVersion=19)으로 한 뒤, 하위 버전(예: sdkVersion=8)에서 실행할 때 아래와 같은 에러를 만나게 되는 경우에는 Library Project 혹은 Library 의 문제가 아니라, 프로젝트에서 사용하고 있는 
"?android:attr/" 의 문제이다. 
상위 버전의 attr 을 resource id 를 사용하는 것이기 때문에 하위버전에서는 엉뚱한 리소스를 찾다가 실패하는 것이다. 

 Caused by: android.content.res.Resources$NotFoundException: Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x10102fd a=-1} 
혹은 
 java.io.FileNotFoundException: res/drawable-hdpi/divider_horizontal_bright_opaque.9.png

와 같은 에러를 만나게 된다.


프로젝트 xml 파일에서 "?android:attr/" 로 검색하여 최신 속성을 사용하고 있는 것인지 확인해야 한다.


p.s. 본디, 이런 포스팅은 하지 않는데,.. 너무 어이없이 삽질을 하다보니 일단 기록을 남겨둔다.

  1. Denial 2014.08.09 07:01 신고

    저두 정말 어처구니 없는 삽질을 했었네요 ㅠ 눈치챌 즈음에 여기를 발견했습니다. ㅎㅎ

시작하기에 앞서 아래 사이트를 참조하면 좋다.

http://android-developers.blogspot.kr/2013/10/getting-your-sms-apps-ready-for-kitkat.html (영문) 

http://android-developers-kr.blogspot.kr/2013/10/blog-post_15.html (국문 번역)


위 사이트를 참조하면 기본 SMS 앱으로 설정되려면, 아래와 같이 두 개의 BroadcastReciever(SMS_DELIVER 와 WAP_PUSH_DELIVER action 을 받을 수 있는)와 sms, smsto, mms, mmsto scheme 을 받아줄 수 있는 Activity, 그리고, RESPOND_VIA_MESSAGE action 을 받을 수 있는 Service 가 구현되어 있어야 한다.


<manifest>
    ...
    <application>
        <!-- BroadcastReceiver that listens for incoming SMS messages -->
        <receiver android:name=".SmsReceiver"
                android:permission="android.permission.BROADCAST_SMS">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_DELIVER" />
            </intent-filter>
        </receiver>

        <!-- BroadcastReceiver that listens for incoming MMS messages -->
        <receiver android:name=".MmsReceiver"
            android:permission="android.permission.BROADCAST_WAP_PUSH">
            <intent-filter>
                <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
                <data android:mimeType="application/vnd.wap.mms-message" />
            </intent-filter>
        </receiver>

        <!-- Activity that allows the user to send new SMS/MMS messages -->
        <activity android:name=".ComposeSmsActivity" >
            <intent-filter>
                <action android:name="android.intent.action.SEND" />                
                <action android:name="android.intent.action.SENDTO" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="sms" />
                <data android:scheme="smsto" />
                <data android:scheme="mms" />
                <data android:scheme="mmsto" />
            </intent-filter>
        </activity>

        <!-- Service that delivers messages from the phone "quick response" -->
        <service android:name=".HeadlessSmsSendService"
                 android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
                 android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="sms" />
                <data android:scheme="smsto" />
                <data android:scheme="mms" />
                <data android:scheme="mmsto" />
            </intent-filter>
        </service>
    </application>
</manifest>


Uri.Builder 사용하시는 분들이 별로 없으신 것 같아서 간단히 설명드립니다.


Uri = scheme://authority/path?query=value 


와 같은 형태입니다.


Uri.Builder 를 사용하시면 Uri 를 쉽게 만들어서 사용하실 수 있습니다.


예를 들어, 


https://gdata.youtube.com/feeds/api/users/abc/playlists?v=2&alt=jsonc


와 같은 URL 이 있다면 아래 코드와 같이 코딩하신 뒤, toString() 을 사용하시면 됩니다.


https://gdata.youtube.com/feeds/api/users/abc/playlists?v=2&alt=jsonc 


Uri.Builder ub=new Uri.Builder();

ub.scheme("https")

.authority("gdata.youtube.com")

.appendPath("feeds").appendPath("api").appendPath("users")

.appendPath("abc").appendPath("playlists")

.appendQueryParameter("v", "2").appendQueryParameter("alt""jsonc");


String url=ub.build().toString();


특히, QueryParameter 의 경우에는 자주 바뀌거나 추가될 수 있기 때문에 코드의 재사용성이 꽤 괜찮을 것 같습니다. 


Google Support Library v7 appcompat 사용 방법

1. Eclipse> File> Import> Existing Android Code Into Workspace


2. [Android SDK Directory]/extras/android/support/ 선택 

- 이렇게 선택할 경우 support 되는 프로젝트가 모두 표시된다. 이 중 하나를 선택한다.




3. 이렇게 추가된 프로젝트는 라이브러리 프로젝트로 설정되어 있다.

- Project> Properties> isLibrary 가 체크되어 있다.


4. 그러므로, v4 와 같이 jar 파일만 lib 디렉토리에 추가해주는 것이 아니라, Project> Properties> Library > Add> 를 통해 라이브러리 프로젝트를 추가해 주어야 한다.


이렇게 jar 파일로만 해결이 되지 않는 이유는 리소스를 포함하고 있기 때문이다.

startActivityForResult() 로 호출한 결과를 어디에서 처리해야 할까? 개인적인 생각으로는 Fragment 에서 시작한 Activity 라면 Fragment 에서 처리하는 것이 맞다고 생각한다.

어쨋건 Fragment 가 생긴 뒤, Activity 에서 시작한 startActivityForResult 의 결과물에 대하여, 시스템에서 Fragment 에서 생성한 경우, 16bit - 2byte shift 해서 처리하고 있다.

즉, 안드로이드 시스템에서 Activity 와 Fragment 에서 시작한 Activity 를 구분하고 있다고 보면 된다. 그래서, 만약, Fragment 에서 생성한 ActivityResult 를 상위 Activity 에서 처리하고 싶다고 한다면, >>16 을 사용해야 한다.


FragmentA.java

----------------------------------- 

.... 

requestCode=1; 

startActivityForResult(intent, requestCode) 

.... 

----------------------------------- 


 ActivityA.java 

----------------------------------- 

.... 

@Override 

protected void onActivityResult ( int requestCode, int resultCode, Intent data) { 

int fragmentRequestCode = requestCode >> 16 ; 

// fragmentRequestCode=1 } 

.... 

----------------------------------- 


여기서 알수 있는 것은 Fragment 에서 생성한 requestCode 는 0xffff 보다 작아야 한다는 것이다. 그래야 본래의 값을 잃어버리지 않을 수 있다.


1. 아침에 95.9 손석희의 시선집중을 들으며 출근했다. 왜 국판은 DMB 를 버리고 FM Radio 를 넣은 모델을 출시를 안하는건가...
2. Page Buddy> Earphone pages 기능은 꽤 유용한 것 같다.

P.S. 근데, 스크린 캡쳐 기능은 없는건가?





아래 글 YouTube DATA API (1) 을 토대로 Android ContentProvider 를 만들어 봤습니다.


Android 용 Library 와 Source 는 아래에서 확인하실 수 있습니다.

http://code.google.com/p/android-provider-for-google-api/


Sample Project 에서는 이를 이용한 예제를 보여 줍니다.

http://code.google.com/p/android-provider-for-google-api/source/browse/#svn%2Ftrunk%2FAndroidProviderSample


사용방법은 간단합니다.

1. jar 파일 다운로드

http://code.google.com/p/android-provider-for-google-api/downloads/detail?ame=androidprovider4googleopenapi.jar&can=2&q=#makechanges


2. AndroidManifest.xml 파일에 아래 코드 추가

<provider
android:name="com.iuchannel.android.provider.YouTubeProvider"
android:authorities="(PackageName).YouTubeProvider" android:grantUriPermissions="true" />


3. 아래와 같은 Uri 로 query 를 하면 결과값을 Cursor 로 받을 수 있다.

public class MainActivity extends ListActivity {
        private final static String USER_NAME="MBCClassic";
        ListView mListView;
       
SimpleCursorAdapter mAdapter;
       
AsyncQueryHandler mHandler;     
       
Uri mUri;
       
       
@Override
       
protected void onCreate(Bundle savedInstanceState) {
               
super.onCreate(savedInstanceState);
                setContentView
(R.layout.activity_main);
                mUri
=Uri.parse("content://"+getPackageName()+".YouTubeProvider/user/"+USER_NAME);
                mListView
=getListView();
               
                mAdapter
=new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, null,
                               
new String[]{"title"},
                               
new int[]{android.R.id.text1},
                               
SimpleCursorAdapter.NO_SELECTION){
                       
               
};
               
                mListView
.setAdapter(mAdapter);
                mHandler
=new AsyncQueryHandler(getContentResolver()){
                       
@Override
                       
protected void
                        onQueryComplete
(int token, Object cookie, Cursor cursor){
                               
Log.d("Test", "onQueryComplete");
                               
if(cursor==null){
                                       
Log.d("Test", "Cursor=null");
                               
}
                               
                               
if(cursor!=null && cursor.getCount()>0){
                                       
Log.d("Test", "Cursor>0");
                                        mAdapter
.swapCursor(cursor);
                                        mListView
.invalidateViews();
                               
}
                       
};
               
};               
                mHandler
.startQuery(0, null, mUri, null, null, null, null);
       
}

}


Cursor 에 넘겨주는 값들은 Const.java 에 정의 되어 있으며 아래와 같습니다.

                public final static String PRJ_ID="_id";
                public final static String PRJ_TITLE="title";
                public final static String PRJ_PLAYLIST_ID="id";
                public final static String PRJ_DESCRIPTION="description";
                public final static String PRJ_SIZE="size";
                public final static String PRJ_SQDEFAULT="sqDefault";
                public final static String PRJ_HQDEFAULT="hqDefault";
                public final static String PRJ_AUTHOR="author";
                public final static String PRJ_CREATED="created";
                public final static String PRJ_UPDATED="updated";

             

                public final static String[] USER_PLAYLIST={
                                PRJ_ID,
                                PRJ_PLAYLIST_ID,
                                PRJ_CREATED,
                                PRJ_UPDATED,
                                PRJ_AUTHOR,
                                PRJ_TITLE,
                                PRJ_DESCRIPTION,
                                PRJ_SIZE,
                                PRJ_SQDEFAULT,
                                PRJ_HQDEFAULT,
                };



아래 그림은 위의 간단한 코드로 나온 결과값입니다. 오른쪽그림은 YouTube 사이트에서 보이는 화면이구요.

위 코드에서는 Adapter 에서 title 만을 UI 에 뿌려주었기 때문에, 이와 같이 보이는 것이구요.

PRJ_SIZE, PRJ_UPDATED, PRJ_SQDEFAULT 와 같은 정보들도 같이 뿌려주면 사이트와 거의 동일한 화면을 구성할 수 있습니다.














YouTube 는 사용자(user-channel) 가 여러개의 동영상을 묶어 놓을 수 있는 기능을 제공합니다.

이것을 재생목록, Playlist, 이라고 합니다. 일종의 북마크, Bookmark, 와도 비슷한 기능인데요.

실제로는 그 이상의 기능을 수행할 수 있습니다. 이와 관련된 이야기는 뒤에서 계속하고, 우선 API 부터 직접 살펴보지요.


https://gdata.youtube.com/feeds/api/playlists/B54BB58F4DC29C40?v=2&alt= 


{"apiVersion": "2.1","data": {"id": "PLB54BB58F4DC29C40","author": "chanyhan","title": "Pororo Season 1","description": "","totalItems": 49,"startIndex": 1,"itemsPerPage": 25,}}


이 API 에서도 앞의 user api 와 동일하게 start-index 와 max-result option 을 사용할 수 있습니다.

기본적인 사용방법은 https://gdata.youtube.com/feeds/api/playlists/ [Playlist ID] ?v=2 [&options] 입니다.

여기서 주의해야할 것은 [Playlist ID] 값입니다.

위 입력값에서 보시면 [Playlist ID] = B54BB58F4DC29C40 입니다만, 결과값에서는 "data"-"id":"PLB54BB58F4DC29C40" 라는 것을 확인할 수 있습니다.

보통 플레이리스트의 아이디 값으로는 PL 이라는 Prefix 가 붙지만, 실제 API 를 호출할 때는 PL 을 지우고 사용하셔야 합니다.


일단 결과 값은 user api 를 사용했을 때와 거의 동일하니 위 결과값에 대한 설명은 생략하겠습니다.


아래는 "items" 배열의 결과 값 중 하나입니다.



{
"id": "PLSlR4rjeFeOOxEKqleFT_Hn3_sSL923rB","position": 1,"author": "chanyhan","video": {"id": "QQyYCAvkOXY","uploaded": "2011-05-27T01:53:07.000Z","updated": "2013-01-02T02:05:24.000Z","uploader": "pororotv","category": "Shows","title": "뽀로로 - S1_1화 우리는 친구","description": "얼음 나라 작은 숲속 마을에 호기심 많은 꼬마 펭귄 뽀로로가 살고 있었어요. 여느 때 처럼 얼음 동산에서 신나게 놀던 뽀로로는 숲속 나무 밑에서 커다란 알을 발견하게 되었답니다. 알을 보고 배가 고파진 뽀로로는 집으로 가져와 요리를 하려고 하는데, 알이 깨지며 나타난 것은 아기 공룡이었어요. 뽀로로는 무서운 공룡을 상상하고 겁에 질려 도망치기 시작하는데...","duration": 301,"rating": 2.7650375,"likeCount": "939","ratingCount": 2128,"viewCount": 1881367,"favoriteCount": 0,"commentCount": 58,}},


1 depth 의 값들보다는 "video" 하위의 2 depth 값들이 이 재생목록에 추가된 동영상(video)의 정보가 중요합니다.

- id : video(재생목록) 의 아이디입니다. 이 값을 이용해서, 직접 video 를 재생할 수 있습니다.

- uploaded : 동영상을 업로드한 날짜

- updated : 업데이트 된 날짜

- uploader : 업로드한 사람

- category : 분류 - 보통 업로드한 사람이 설정해 놓는 것으로 동영상이 어떤 종류인지 알 수 있습니다. 

    https://developers.google.com/youtube/2.0/reference#Category_search 에서 보시면 category 에 어떤 값들이 들어갈 수 있는지 알 수 있습니다. 

- title : 제목

- description : 설명

- thumnail : 대표 이미지 썸네일

- player, content : 생략

- duration : 재생 시간, 단위:초

- rating : 별점

- likeCount : 좋아요 횟수

- ratingCount : 별점 횟수

- viewCount : 시청 횟수

- favoriteCount 

- commentCount : 댓글 갯수

- contentRating : 컨텐츠 수위 (이를 테면, 19금 과 같은 정보입니다.)

- accessControl : 접근제어, commnet, commentVote, rate, autoPlay 와 같은 정보를 허용하는지 아닌지를 알려주는 정보입니다. 이 필드 안의 syndicate 필드는 mobile 에서 재생이 허용되어 있는지 아닌지를 알려줍니다.


이 API 를 호출한 내용들은 

https://www.youtube.com/playlist?list=PLB54BB58F4DC29C40



에서 볼 수 있습니다.









그 동안 YouTube 에 공개된 Open API 를 접하면서 알게된 것들을 공유하고자 이 글을 쓰게 되었습니다.

아래 내용은 https://developers.google.com/youtube/ 의 내용을 예제와 함께 풀어 쓴 것이며, v2.0 을 기준으로 작성되었습니다.


YouTube 에 공개된 Open API 를 사용하면, 거의 YouTube 사이트와 동일한 사이트를 하나 만들 수 있을 정도로 잘 만들어져 있습니다.

Google 이 이런 정책을 펴는 이유 중 하나는 Google 은 이 정도의 Data API 를 공개해도 결국 동영상은 YouTube 를 통해 재생되기 때문에, 

그 API 를 통해 YouTube 동영상이 재생된다면, 결국 Google 은 돈을 벌 수 있기 때문입니다.


그럼, 대표적인 API 하나를 확인해 보지요.


https://gdata.youtube.com/feeds/api/users/chanyhan/playlists?v=2


위 api 는 YouTube 의 chanyhan 이라는 channel 의 playlist 를 보여주는 api 입니다.

YouTube 에서 channel(채널) = user(사용자) 와 와 같습니다.

default 는 xml 이라서 복잡해 보이고 뭐가 뭔지 잘 눈에 안보입니다.

그래서, 이에 해당하는 간략정보를 JSON 타입으로 보는 것이 개발자들에게는 좀 더 편합니다.


(1) https://gdata.youtube.com/feeds/api/users/chanyhan/playlists?v=2&alt=jsonc


url 파라미터로 &alt=jsonc 를 추가해 주시면 됩니다. 

&alt=jsonc 대신 &alt=json 을 추가해주시면, 좀 더 많은 정보를 확인할 수 있습니다.

어떤 것이 더 편한지 그건 쓰시는 분 마음입니다만, 이 글에서는 alt=jsonc 를 기본으로 가져가겠습니다.

그 이유는 jsonc 옵션이 간략하게 볼 수 있으면서도 왠간한 정보는 모두 가지고 있기 때문입니다.


아래는 Chrome 에서 JSON Formatter 라는 플러그인을 사용해서 본 결과 값입니다.

{"apiVersion": "2.1","data": {"totalItems": 10,"startIndex": 1,"itemsPerPage": 25,}}


위 API 는 YouTube 의 chanyhan 이란 사용자가 가지고 있는 Playlist 정보입니다.

총 10개(totalitems) 를 가지고 있으며, 페이지당 25개를 보여주며(itemsPerPage":25), 그 첫번째 페이지("startIndex"=1)라는 것입니다.

(1) 에서 &max-result=50 으로 설정해주시면, "itemsPerPage":50 으로 나오는 걸 확인하실 수 있습니다. 즉 기본값은 25 라는거죠.

마찬가지로 &start-index=2 로 설정해주시면, "startIndex":2 로 나오는 걸 확인하실 수 있습니다.

startIndex 는 위 결과에서 "items" 에 해당하는 결과값이 시작하는 번호의 차이입니다.


(2) https://gdata.youtube.com/feeds/api/users/chanyhan/playlists?v=2&alt=jsonc

&start-index=11&max-results=50


{"apiVersion": "2.1","data": {"totalItems": 10,"startIndex": 11,"itemsPerPage": 50}}


총 아이템 갯수가 10개이기 때문에 시작위치가 11이 되면, "data"-"items" 의 결과 값은 없게 됩니다.


이제 "items" 안의 내용들을 확인해 보지요.


{"id": "PLB54BB58F4DC29C40","created": "2011-07-26T01:03:33.000Z","updated": "2011-07-28T05:10:33.000Z","author": "chanyhan","title": "Pororo Season 1","description": "","size": 49,"thumbnail": {"sqDefault": "http://i.ytimg.com/vi/QQyYCAvkOXY/default.jpg","hqDefault": "http://i.ytimg.com/vi/QQyYCAvkOXY/hqdefault.jpg"}},


- id : Playlist(재생목록) 의 아이디입니다. 이 값을 이용해서, 직접 재생목록에 접근할 수 있습니다.

- created : 생성된 날짜

- updated : 업데이트 된 날짜

- author : 만든 사람

- title : 제목

- description : 설명

- size : 재생목록에 포함되어 있는 동영상의 총 갯수

- thumnail : 대표 이미지 썸네일


참고로 이 데이터들은 아래 url 에서 보여지는 것들입니다.

https://www.youtube.com/user/chanyhan/videos?flow=grid&view=1


이 item 이 실제 YouTube 사이트에서 보여지는 것은 아래와 같습니다. 













+ Recent posts

티스토리 툴바