안드로이드 개발자에 필요한 오픈소스이야기

141
안안안안안 안안안안 안안 안안 안안 안안안 ( 안안 : 안 OpenSource 안 OpenSource) 안안안안안 안안안안안 안안안안

Upload: youngsu-son

Post on 13-May-2015

10.460 views

Category:

Technology


0 download

DESCRIPTION

안드로이드 개발에 필요한 오픈소스

TRANSCRIPT

안드로이드 개발자를 위한 오픈 소스 이야기

( 부제 : 以 OpenSource 治 OpenSource)오픈소스로 오픈소스를 다스린다

손영수

Filpboard 팀 ligbuf 팀

SW 아키텍트 포럼 모바일 분과 fHalo 팀

요즘 업계 흐름은알고 가시죠 ^^

Google 이 꿈꾸는 ..

Android 의 미래

Google 은 왜 modu 의 특허를 50 억에 샀을까 ?

modu 의 Jacket 시스템

이게 왜 중요하지 ?..

Series1

236676546050

1162950

2197563

3805989

6253991

2010 2011 2012 2013 2014 2015

갈수록 증가하는 모바일 Traffic

단위 TB/ 월Cisco (2012), Cisco Visual Networking Index

사실 Google 의 서비스는 Cloud 에 ..

Android 는 Google 의 서비스를

( 개인 , 가정이 ) 소비하게 만드는 Hub

Android 는 더 이상

Gadget 을 위한 OS 가 아니다 .

EmbeddedSystem 을

포괄할 OS 로 봐야 함 .

하지만 ..

제조사 입장에서Android 는

독이 든 성배 ..

Openness

23

58 58 61 65 68 71

84

Android Qt Symbian MeegoMozilla Webkit Linux Eclipse

안드로이드의 개방성

Vision Mobile Report July, 2011- http://bit.ly/oTmEmF

오픈 소스 이긴 한데 .. 구글러가 아니면 할수 있는게 없다…

정리하면 ..

버그만 잡아줘 ..

Android 의 단점을 극복할 대체제들을 잘써야 한다 .

UI

Network

Common

BaaS

android-bindingandroid-action-bar

actionbar she-lock

side-naviga-tion

android ui patterns

gson (json)Simple (REST)

Facebook (fhalo)

Android billing (In app pur-

chase)roboguice

USERGRID (BaaS Open

Source)

microlog4android sensing

User BehaviorAnalytics

Welcome to my Jour-ney!

Agenda• 안드로이드 이해

– Binder (Broker 패턴 ) 그리고 Intent

• 오픈 소스 그리고 사례– Simple Framework (Restful)– microlog4android– 불편하지 않은 화면 갱신 (Publisher-Subscriber)– android-actionbar (+ actionbar sherlock)– Android Binding Framework– fHalo (facebook client famework)

• 분석 방법– Localytics 사용법– STAN 을 이용한 Android App 분석 방법

# 1. Binder..

Activity

Con-tents

Provider

Service

Broad-castRe-

ciever

하지만…

우리가 주목해야 할 것은 ..

왜 Binder 가 중요하지 ?

Android 내의 모든 상황을

감독하는 감시관 !

갑자기 뚝 하고 나온 녀석이 아니다 .

아주 .. 일반적인 아키텍쳐일뿐 .

Client

in args operation()

out args,return

IDLSTUBS

BinderINTERFACE

IDLSKEL

Object Adapter

Binder

IDLCompiler

OBJREF

Object

Binder Architecture

Binder 를 느낄 수 있는 예제

AIDL 샘플 참고

http://bit.ly/85E5SV

1. AIDL 파일 생성

package aexp.aidl; 

// Adder service interface. interface IAdderService

{int add( in int i1, in int i2 );

}

2. AIDL 툴로 Java 파일 생성

수동 코드 생성sdk/platforms/android- <n>/tools/aidl  에 간다

C:\Android-project\ApiDemos\src\com\example\android\apis\app>aidl -IC:\An-droid-project\ApiDemos\src\ IRemoteService.aidl

Eclipse 에서는 aidl 만 넣고 빌드하면 자동으로 소스 생성 됨

3. Service Class 구현 ……public class AdderServiceImpl extends Service {

@Override public IBinder getBinder() { return mBinder; }

@Override public void onCreate() { super.onCreate();

Log.d( "ADDERSERVICEIMPL","onCreate" ); }

/** The IAdderService is defined through IDL */ private final IAdderService.Stub mBinder = new IAdderService.Stub() {

public int add( int i1, int i2 ) {return i1+i2; }

};

@Override protected void onDestroy() {

super.onDestroy( Log.d( "ADDERSERVICEIMPL","onDestroy" ); }

}

4. Manifest 에 서비스 등록<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="aexp.aidl"> <application> <activity class=".AIDLServiceActivity"

android:label="AIDLServiceActivity"> <intent-filter> <action android:value="android.intent.action.MAIN" /> <category android:value="android.intent.category.LAUNCHER" /> </intent-filter> </activity>

<service class=".AdderServiceImpl"/> </application></manifest>

5. Client 에 호출을 위해 Binder 로 이름 찾는 로직

class AdderServiceConnection implements ServiceConnection { public void onServiceConnected(ComponentName className,

IBinder boundService ) { service = IAdderService.Stub.asInterface((IBinder)boundService);

Log.d( "ADDERSERVICECLIENT","onServiceConnected" ); }

public void onServiceDisconnected(ComponentName className) { service = null;

Log.d( "ADDERSERVICECLIENT","onServiceDisconnected" ); } };

6. 시작 , 해제 로직 넣을 것private void initService() {

conn = new AdderServiceConnection(); Intent i = new Intent(); i.setClassName( "aexp.aidl", "aexp.aidl.AdderServiceImpl" ); bindService( i, null, conn, Context.BIND_AUTO_CREATE);

}

private void releaseService() {

unbindService( conn ); conn = null;

}

7. 클라이언트에서 서비스 호출하기

private void invokeService( int i1, int i2 ) { TextView t = (TextView)findViewById(R.id.invokeserv_result); if( service == null )

t.setText( "Service not available" ); else {

try { int result = service.add( i1,i2 ); t.setText( Integer.toString( result ) );} catch( DeadObjectException ex ) { t.setText( "Service invocation error" );}

} ….

Broker

Bridge

pack_datauppack_dataforward_messagetransmit_message

calls

Server-sideProxy

pack_datauppack_datacall_servicesend_response

Client-sideProxy

pack_datauppack_datasend_requestreturn

Broker

main_event_loopupdate_repositoryregister_serviceacknowledgmentfind_serverFind_clientForward_requestForward_response

Server

initializeenter_main_looprun_serviceuse_Broker_API

Client

call_serverstart_taskuse_Broker_API

transfermessage

calls

calls

uses API

transfermessage

uses API

Registration

acknowledgment

register_service()

main_evnet_loop()

Service, BR, Activity… Broker

enter_main_loop()

startInitialize()

update_repository()

Sending Request

Client Client-Side Proxy

Server-Side Proxy

Broker Server

call_server

result

send_requestpack_data

forward_request

find_server

call_serviceunpack_data

run_service

pack_dataforward_response

find_clientreturn

unpack_data

사용하기 힘든 Binder..

Intent 는 Binder 를 쉽게 사용할 수 있는 추상화 도구 .

BINDER

AIDL

IN-TENT

Intent 를 잘 알면 . Android 를 잘 ~~ 개발 할 수 있다 .

Intent 로 Activity 호출

Intent intent = new Intent(getApplicationContext(), MyOtherActivi-

ty.class);startActivityForResult(intent, SHOW_SUBACTIVITY);

그런데 , Activity 이름이 바뀌면…

그래서 묵시적 Intent

Manifest 파일에 Intent Filter 등록<activity android:name="DirectoryDialog"

android:theme="@android:style/Theme.Translucent">

<intent-filter><action android:name="filemanager.action.PICKFILES" /><category

android:name="android.intent.category.DEFAULT" /></intent-filter></activity>

호출 Intent filemanager =  new Intent("filemanager.action.PICKFILES");startActivity(filemanager);

Activity 만 되는게 아님

# 2. 아직도 Log-cat?

여러분이 만든 시스템이 죽었다 .

미국에서… .

Logcat 보러 출장 ?

새로운 log..

4

먼저 Log Management

패턴부터…

log4xxx

Microlog4android 사용법• http://code.google.com/p/microlog4android/downloads/ 에서

microlog4android-1.0.0.jar 다운

• Android 프로젝트에 jar 추가

• AndroidManifest.xml 에 android.permission.WRITE_EXTERNAL_STORAG E 추가

public class LogtestActivity extends Activity {static public Logger logger = LoggerFactory.getLogger(); @Override public void onCreate(Bundle savedInstanceState) { PatternFormatter formatter = new PatternFormat-ter(); formatter.setPattern( " %d{ISO8601} [%P] %m %T " ); logger.setLevel(Level.INFO); // write to LogCat LogCatAppender logCatAppender = new LogCatAp-pender(); logCatAppender.setFormatter(formatter); logger.addAppender(logCatAppender); // write to text file of SD-card. FileAppender fileAppender = new FileAppender(); fileAppender.setAppend( true ); fileAppender.setFileName( "microlog4android.log" ); fileAppender.setFormatter(formatter); logger.addAppender(fileAppender);

로그를 Network 서버로 보내는

Appender 도 있으나약간의 코딩이 필요 .

# 3. REST 의 귀찮음 .

Rest is unrest..

Stub

Proxy

DAOController

REST

GETDTO

같이 뭉쳐 다니는 파라메터는 ParameterObject 로

묶어라 !

AfterRefactoringCustomer

+AmountInvoicedIn(Period: DateRange)+AmountRecievedIn(Period: DateRange)+AmountOverDueIn(Period: DateRange)

BeforeReactoringCustomer

+AmountInvoicedIn(start: Date, end: Date)+AmountRecievedIn(start: Date, end: Date)+AmountOverDueIn(start: Date, end: Date)

XML 파싱 이렇게 ??<categoryList> <categorys> <category> <id>1</id> <name>AA</name> <date>2011-11-01</date> </category> <category> <id>2</id> <name>BB</name> <date>2011-12-10</date> </category> </categorys> </categoryList>

while(true) { int eventType = xpp.nextTag(); if(eventType == XmlPullParser.START_TAG) { String tag = xpp.getName(); if("id".equals(tag)) { category.setId(Integer.parseInt(xpp.nextText())); }else if ("name".equals(tag)) { category.setName(xpp.nextText());

}else if ("date".equals(tag)) { category.setDate(xpp.nextText());

}else{if(XmlPullParser.TEXT == xp-

p.next())xpp.nextTag();

} } else break; }

Simple Framework 를 이용하세요 .

http://simple.source-forge.net/

이렇게 됩니다 .<categoryList> <categorys> <category> <id>1</id> <name>fruit</name> <date>201110051200</date> </category> <category> <id>2</id> <name>animal</name> <date>201110051200</date> </category> <category> <id>3</id> <name>food</name> <date>201110051200</date> </category> </categorys> </categoryList>

@Rootpublic class CategoryList {

@ElementListprivate ArrayList<Category> categorys;

public void setCategorys(ArrayList<Category> categorys) {

this.categorys = categorys;}

public ArrayList<Category> getCategorys() {return categorys;

}}

이렇게 됩니다 .while(true) { int eventType = xpp.nextTag(); if(eventType == XmlPullParser.START_TAG) { String tag = xpp.getName(); if("id".equals(tag)) { category.setId(Integer.parseInt(xpp.nextText())); }else if ("name".equals(tag)) { category.setName(xpp.nextText());

}else if ("date".equals(tag)) { category.setDate(xpp.nextText());

}else{if(XmlPullParser.TEXT == xp-

p.next())xpp.nextTag();

} } else break; }

Serializer serializer = new Persister();Reader reader = new StringReader(xmlData);CategoryList categoryList = serializer.read(CategoryList.class, reader, false);

# 4. 화면 갱신

My Market 을 기억하시나요 ?

시작하자마자 Loading.. 화면이 뜨면

누가 접속하나요 ??

시작하자 마자 화면이 나오게 .

그럼 . 사용자가 직접 당겨서 동기화를 ?

Activ-ity

Con-tents

Provider

XXXAdapter

1. Register

SyncSer-vice

Notifi-cation

2. Insert

3. Notification

4. GetData..

@Overridepublic Uri insert(Uri uri, ContentValues values) {

String tableName;Uri contentUri;long id;

switch(matcher.match(uri)){case SITES:

tableName = Bookmark.sites._TABLENAME;contentUri = Bookmark.sites.CONTENT_URI;break;

default:throw new IllegalArgumentException();

}

id = mDB.insert(tableName, null, values);if(id > 0){

Uri itemUri = ContentUris.withAppendedId(contentUri, id);

return itemUri;}else

throw new SQLException();}

ContentValues values = new ContentValues();values.put(Bookmark.sites.NAME, stk[i][0]);values.put(Bookmark.sites.ADDRESS, stk[i][1]);getContentResolver().insert(Bookmark.sites.CONTENT_URI, values);getContentResolver().notifyChange(Bookmark.sites.CONTENT_URI, null);

# 5. UI Patterns

http://bit.ly/QyDjMV

다양한 안드로이드 UI 오픈소스들을 소개

Android UI Patterns App

Android UI Patterns App

예제 1 - android-action-bar

스크린샷 1 스크린샷 2 XML 기능 Action Action 예제 색변경

스크린샷 1 스크린샷 2 XML 기능 Action Action 예제 색변경

스크린샷 1 스크린샷 2 XML 기능 Action Action 예제 색변경

스크린샷 1 스크린샷 2 XML 기능 Action Action 예제 색변경

스크린샷 1 스크린샷 2 XML 기능 Action Action 예제 색변경

스크린샷 1 스크린샷 2 XML 기능 Action Action 예제 색변경

colors.xml

스크린샷 1 스크린샷 2 XML 기능 Action Action 예제 색변경

예제 2 android-binding-frame-

work

http://code.google.com/p/android-bind-ing/ http://bit.ly/cxxwCF

Event 에 대한 Binding

다음과 같이 버튼에 대한 이벤트Method OnClick()

Main.xml

CalculateViewModel.java

Option.xml

Main Activity

Main Activity

# 6. fhalo

framework

facebook framework Project

세계에서 가장 큰 서비스

854,750,780( 약 8 억 5 천만 )

가장 오랜시간 이용하는 서비스

Social Plugin ?Open Graph ?Social Channels ?Authentication ?Graph API ?

을 개발하려면… 너무 많은 것을 알아야 한다 .

framework

facebook framework Project

그래서 우리는 ..

를 시작했습니다 .

93

Facebook 기본 개념 - 소셜 그래프

94

About Graph API• Graph API

– 소셜 그래프의 Object( 친구 , 페이지 , 사진 등 ) 를 다루는 API

• Graph API 의 구조– https://graph.facebook.com/OBJECT_ID/

CONNECTION_TYPE

• ID 는 사용자 , 페이지 , 이벤트 , 사진 등의 Object ID– 약 20 개의 Object 를 지원– 모든 Object 의 ID 는 unique 하다– JSON 형태로 응답을 받는다

95

Graph API Example• https://graph.facebook.com/100001066448386/

• https://graph.facebook.com/40796308305/

신재명 ID

코카콜라 페이지 ID

96

Graph API - Connection

• Graph API 의 구조– https://graph.facebook.com/OBJECT_ID/CONNECTION_TYPE

• Connection 이란 ?– Object 의 연관 ( 관계 ) 개념

• User object 의 Connection 종류– Family, friends, album, likes, posts …– User object 경우 약 25 개의 Connection 을 제공– https://developers.facebook.com/docs/reference/api/user/ 참고

97

Connection - Example• Graph API 예시

– https://graph.facebook.com/100001066448386/friends

그럼 보안문제는 ???

98

Access Token

• 페이스북 API 를 사용하기 위해 Access Token(인증 ) 이 필요하다 .

• Graph API Explorer 를 통하여 쉽게 Access To-ken 을 받아올 수 있음

About Graph API

• Graph API Explorer– Access Token 받을 수 있다–각종 Graph API 를 테스트 해볼 수 있다

https://developers.facebook.com/tools/explorer#!/tools/explorer

100

사용법

Step1Import fHalo.jar

Step2Get access token

Step3Create instance

Step4Using API

101

Access Token

• 페이스북 API 를 사용하기 위해 Access Token(인증 ) 이 필요하다 .

• Graph API Explorer 를 통하여 쉽게 Access To-ken 을 받아올 수 있음

친구 리스트 가져오기 ( 페이스북 API)

친구 리스트 가져오기– Rest FB

• Connection<User> myFriends = facebookClien-t.fetchConnection("me/friends", User.class);

– fHalo• Connection<Friends> friends =

user.friends();

피드 올리기 ( 페이스북 API)

피드 올리기– Rest FB

• FacebookType publishMessageResponse =facebookClient.publish("me/feed", FacebookType.-class,Parameter.with("message", "RestFB test"), Parame-ter.with(“caption", “caption test"), Parameter.with(“description", “description test"),);

– fHalo• Feed feed = new feed();

feed.setMessage("Message Test"); feed.setCaption("Caption Test"); feed.setDescrip-tion("Description Test"); user.publishFeed(me, feed);

# 7. 분석은 어떻게 ?

Sleep If you can.

Thanks 신재명

Issue..

월드 와이드 앱

모바일 어플리케이션 분석 플랫폼

메인 DASHBOARD

Daypart

Device ( 국내는… )

Device ( 월드 와이드 앱은 ..)

App Version

TagEvent ( 사용자가 많이쓰는 기능 )

사용자가 어떤 화면을 많이 사용하는지 ( 유료기능 )

이외에도 ..

• New vs Returning• Carrier• Country• OS Version

적용방법• http://www.localytics.com/ 에서

• 탭 에서 어플리케이션 등록

• http://bit.ly/KnZzpx 에서 소스코드 다운

• Android 프로젝트 src/ 폴더에 소스코드 추가

• AndroidManifest.xml 에 퍼미션 추가 <uses-permission

android:name="android.permission.INTERNET“>

• 클래스 내부에 session object 추가

• Main Activity 에 Import

•  OnCreate 함수에 아래 소스 추가

import com.localytics.an-droid.*;

private LocalyticsSession localytic-sSession;

public void onCreate(Bundle savedInstanceState){ .

.

.

this.localyticsSession = new LocalyticsSession(this.getApplicationContext(),

"APP KEY FROM STEP 2");this.localyticsSession.open(); // open the sessionthis.localyticsSession.upload(); // upload any data

.

.

.

}

• onResume 메소드 Override

• onPause 메소드 Overridepublic void onPause(){

this.localyticsSession.close();this.localyticsSession.upload();super.onPause();

}

public void onResume(){

super.onResume();this.localyticsSes-sion.open();

}

• TagEvent 남기기localyticsSession.tagEvent(“TagEvent 남김 ");

# 8. 1000 피트의 뷰 .

높이 (30000 feet) 봐야 할까 ?

높이 봐야 할까 ?

자세히 (0 feet) 봐야 할까 ?

자세히 봐야 할까 ?

3 만 피트 vs 0 피트의 뷰 .

3 만 피트• 다이어그램의 Line 의 의미는 ?

• 의존성 ?• 데이터 흐름 ?• 버스와 같은 공유자원 ?

0 피트• 너무 상세한 정보임 .• 전체적인 구조를 보지

못함 .

해결책은 ..적절한 1000 피트의 뷰

STAN (Structure Analysis for Java)

STAN - http://stan4j.com/eclipse/eclipse-integration.html

Demo

Robert C. Martin 의 그래프

Instability

•패키지의 움직일 수 있는 여력을 판단하는 지표

•다른 패키지에 영향을 미치지 않고 , 해당 패키지를 쉽게 변경 할 수 있는가 ?

•Instability I = Ce / (Ca+Ce)

•Ce = Efferent Coupling (Ingoing Dependencies)•Ca = Afferent Coupling (Outgoing Dependencies )

Instability

Instability I = Ce / (Ca+Ce)

당신의 패키지가 다른 사람이 많이 쓴다면 , 즉 Outgoing, Ca 가 많다면 , 여러분의 패키지는 변경하기 어렵다 .

반대로 Outgoing 하는 Ca 가 적고 , Ingoing( 다른 패키지만 사용만 하는 ) Ce,여러분의 패키지는 쉽게 변경해도 된다 .

즉 0.0 에서 0.3 이면 안정적인 버전 , 0.7 에서 1.0 이면 불안정적인 상태다

당신의 패키지를

누군가 많이 쓰고 있다면

바꾸기 쉽지 않다 .

Abstractness

Interface(Abstract) 와 Concrete Class 를 비교

A = (#abstract classes / total # of classes)

•Abstract class = interface, abstract 다 포함•Total # class = abstract class + concrete class

•0 이면 concrete class 만 있다 . •1 이면 abstract class 만 있다 .

다시 보는 그래프

다른데서 많이 쓰는 녀석이니 조금 더

abstract 를 높여야 돼 !

그 외 용어

•Tangled Complexity•순환 참조가 있어 Boundary 를 깰 때

•Cyclomatic Complexity•분기 문이 많아 hotspot 이 될 가망성이 높은 곳

경고 !!!환자의 외부 증상만 고치는 의사가 되지 말자 !!

이러한 정보는 좋은 가이드일뿐 !! 숫자에 의존하다가 오히려 아키텍쳐가 무너진다 .

Q&A