QPair SDK 를 어떻게 사용하는지, 간단한 예제와 함께 소개드리겠습니다.


"클립보드 공유"라는 것인데요, 이 예제는 2014년 3차 모바일 앱 개발 과정에서 사용했던 소스를 거의 그대로 인용할 겁니다.


처음 QPair SDK를 접했을 때는 '디바이스 연결'이라는 특성 때문에 다른 디바이스를 제어하고 파일을 공유하는 것이 가장 먼저 떠올랐어요. 연결된 디바이스의 상태를 보거나 바꾸는 것, 연결된 디바이스의 파일을 확인하고 다운로드 하는 것, 연결 디바이스로 사진을 찍는 것 등등.

하지만 이런 예제는 다소 복잡하니, QPair SDK의 기능을 명확히 전달하려면 좀 더 단순한 예제가 좋을 것 같습니다.

그래서 생각해 본 것이 클립보드 공유입니다.


저는 폰과 태블릿, 게다가 컴퓨터까지 세 가지를 골고루 사용하면서, 장소에 따라 가지고 있는 디바이스로 작업을 해요. 그 때 마다 폰에서 보던 것을 좀 더 큰 화면에서 보려고 URL이나 보던 파일을 메일 등으로 전달하는 것이 불편하더라고요. 


이럴 때 클립보드 공유가 된다면?


한 디바이스에서 보던 것을 복사만 해도 다른 디바이스에서 붙여넣기 할 수 있으니 얼마나 편할까요?

물론 폰 - 태블릿 - 노트북까지 공유가 되면 더없이 좋겠지만 (요세미티에서 되던가요??), 일단 QPair가 지원하는 폰과 태블릿까지만 적용해도 만족스럽겠습니다.


얼마전에 QPair SDK 앱 컨테스트에서 HubToDate라는 앱이 나왔는데, 이 앱에도 클립보드 공유 기능이 있습니다.


앱 동작 구조

일단 어떤 식으로 앱을 만들지 생각해봅시다.


클립보드 공유를 위해서는 다음과 같은 기능이 있어야겠지요.

  • 로컬 기기에서 특정 내용을 복사하면, 복사된 내용을 자동으로 피어 기기로 전달한다.
  • 그러기 위해서는 클립보드에 ‘복사’가 일어났다는 것을 알아내어 피어로 내용을 전송하는 서비스가 필요하다.
  • 피어 기기에서도 클립보드에 내용을 입력할 서비스가 필요하다.
  • 이 서비스를 항상 실행하기 보다는, 사용자가 실행 여부를 선택할 수 있어야 한다. (그래야 편리하겠죠?)

아래 그림이 간단히 그린 앱 동작 구조도입니다.

 

앱 동작 구조

 

그리고 너무도 단순한 서비스 실행 창!

 


준비하기

앱 기획이 끝났으니(너무 간단한가요? ^^;) 개발 준비를 해야겠군요.

개발은 안드로이드 스튜디오로 할게요. QPair SDK는 maven central repository에 있기 때문에 gradle 빌드가 편하거든요~

안드로이드 프로젝트를  하나 만드신 다음, 앱 모듈의 gradle.build에 다음 내용을 추가해주세요.


1
2
3
dependencies {
compile 'com.lge.developer:qpair-apis:2.0.0'
}


이렇게만 하면 QPair SDK를 쓸 준비는 끝!


서비스 실행 화면 만들기

앞서 정했듯, 우리가 만드는 클립보드 공유 서비스는 사용자가 실행하고 종료할 수 있어야 합니다. 그러니 서비스 실행/종료가 가능한 Activity 를 만들어야겠지요. 이 Activity에는 서비스를 실행하고 종료할 수 있는 토글 버튼용 Button 이 있어야 해요. (layout 구현은 생략합니다!)


토글 버튼에 기능을 입혀주기 위해 Activity의 onCreate() 메소드에 다음 내용을 추가해주세요.


1
2
3
4
5
6
7
8
btn = (Button) findViewById(R.id.start);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startQPairClipboard(!isStarted);
isStarted = !isStarted;
}
});


startQPairClipboard()는 다음과 같습니다.


1
2
3
4
5
6
7
8
9
private void startQPairClipboard(boolean start) {
Intent intent = new Intent(this, QPairClipboardService.class);
intent.setAction(ACTION_STARTSERVICE);
 
if( start )
startService(intent);
else
stopService(intent);
}


단순하게 QPairClipboardService 인텐트를 실행했습니다. QPairClipboardService는 다음에 구현하기로 하죠. 하지만 실망하기는 이릅니다. 이 토글 버튼이 간단해보이지만, 놓친 것이 하나 있다는 사실!

토글이다보니 서비스 동작 상태에 따라 표시할 텍스트가 달라져야 합니다. 그러려면 서비스가 실행 중인지 아닌지 확인을 해야겠지요. 안 그러면 앱을 종료하고 다시 실행할 때 서비스 상태와 무관하게 항상 '실행' 버튼이 될테니까요. (혹은 '종료' 버튼이)

그러니 서비스를 실행하거나 종료할 때 어딘가에 저장을 해 두어야합니다. 다음 코드처럼 SharedPreference에 저장해봅시다.


1
2
3
4
5
6
7
8
9
10
private final static String TAG_PEERCLIP = "QPair clipboard";
private final static String PREF_NAME = "servicestatus";
 
private void saveStatus(boolean start) {
SharedPreferences sp = 
getSharedPreferences(TAG_PEERCLIP, MODE_PRIVATE);
SharedPreferences.Editor ed = sp.edit();
ed.putBoolean(PREF_NAME, start);
ed.commit();
}


그런 다음, startQPairClipboard()를  다음과 같이 수정하여, 서비스 상태 변경을 SharedPreference에 업데이트 하게 합니다.


1
2
3
4
5
6
7
8
9
10
11
private void startQPairClipboard(boolean start) {
Intent intent = new Intent(this, QPairClipboardService.class);
intent.setAction(ACTION_STARTSERVICE);
 
if( start )
startService(intent);
else
stopService(intent);
 
saveStatus(start);
}


QPair 상태 확인하기

서비스를 실행해도 QPair가 꺼져 있거나 연결이 되지 않은 경우에는 클립보드를 공유할 수 없습니다. 그러니 사용자의 오해(!)를 피하기 위해서는, QPair의 상태에 문제가 있을 때 서비스를 자동으로 종료하게 해야 합니다. 


QPair의 온오프는 QPairConstants.ACTION_STATE_CHANGED에 저장된 이름의 인텐트가, QPair 연결 여부는 QPairConstants.ACTION_CONNECTION_CHANGED에 저장된 이름의 인텐트가 알려줍니다. 다음과 같이 QPair 상태를 확인하는 BroadcastReceiver를 구현합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private BroadcastReceiver receiver = new BroadcastReceiver() {
Boolean qpairAvailable = false;
 
@Override
public void onReceive(Context context, Intent intent) {
if( QPairConstants.ACTION_CONNECTION_CHANGED
.equals(intent.getAction())) {
qpairAvailable = intent.getBooleanExtra(
QPairConstants.EXTRA_QPAIR_CONNECTED, false);
}
else if (QPairConstants.ACTION_STATE_CHANGED
.equals(intent.getAction())) {
qpairAvailable = intent.getBooleanExtra( 
QPairConstants.EXTRA_QPAIR_IS_ON, false);
}
  // Service is running but QPair is not available
if( !qpairAvailable && isStarted ) {
startQPairClipboard(false);
Toast.makeText(MyActivity.this,
"Cannot run QPair Clipboard Service.",
Toast.LENGTH_SHORT)
.show();
}
}
};


이렇게 만든 BroadcastReceiver를 등록하시고요.


1
2
3
4
IntentFilter filter = new IntentFilter();
filter.addAction(QPairConstants.ACTION_CONNECTION_CHANGED);
filter.addAction(QPairConstants.ACTION_STATE_CHANGED);
this.registerReceiver(receiver, filter);


좀 더 완전한 앱을 위해서, 실행할 때 QPair 상태를 확인하여 서비스 실행 버튼을 비활성화시키는 기능도 구현해보겠습니다. 이 때는 브로드캐스트 대신 QPair property를 이용해야 합니다. QPair 온오프는 is_on에, QPair 연결 여부는 is_connected에 저장되어 있습니다.

먼저 다음처럼 QPair property의 접근 URI을 선언하세요.


1
2
3
4
5
final String QPairIsOn = QPairConstants.PROPERTY_SCHEME_AUTHORITY 
+ "/local/qpair/is_on";
final String QPairIsConnected = 
QPairConstants.PROPERTY_SCHEME_AUTHORITY 
+ "/local/qpair/is_connected";


그리고, Activity의 onCreate()에서 QPair property를 읽어서 토글 버튼을 비활성화합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protected void onCreate(Bundle savedInstanceState) {
Boolean qpairAvailable = true;
 
if( "false".equals(readProperty(QPairIsOn)) )
qpairAvailable = false;
if( "false".equals(readProperty(QPairIsConnected)) )
qpairAvailable = false;
 
if( !qpairAvailable ) {
startQPairClipboard(false);
btn.setEnabled(false);
}
}


readProperty() 메소드는 일반적인 ContentResolver 사용법과 같습니다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private String readProperty(String uri) {
Cursor cursor = getContentResolver().query(
Uri.parse(uri), null, null, null, null);
String value = null;
if(cursor != null) {
try {
if (cursor.moveToFirst()) {
value =cursor.getString(0);
}
} finally {
cursor.close();
}
}
return value;
}


이제 QPair SDK를 이용한 클립보드 서비스를 "동작" 시킬 수 있는 환경이 만들어졌습니다. 이제 실제 서비스를 구현하면 되겠군요. 



저작자 표시 비영리 변경 금지
신고