[Raspberry pi] - 1편 스마트 콘센트? Smart Plug!
[Raspberry pi] - 2편 스마트 콘센트? Smart Plug!
[Raspberry pi] - 3편 스마트 콘센트? Smart Plug!
[Raspberry pi] - 4편 스마트 콘센트? Smart Plug! + 앱위젯
[Raspberry pi] - 5편 스마트 콘센트? Smart Plug! + 터치스위치
[Raspberry pi] - 6편 스마트 콘센트? Smart Plug! + Node.js Push 서버 (개요편)
[Raspberry pi] - 7편 스마트 콘센트? Smart Plug! + Node.js Push 서버 (Firebase 등록)
[Raspberry pi] - 8편 스마트 콘센트? Smart Plug! + Node.js Push 서버 (서버편)
[Raspberry pi] - 9편 스마트 콘센트? Smart Plug! + Node.js Push 서버 (App편)
이제 Push를 받을 안드로이드 App을 구현할 차례이다.
일전에 언급한대로 구버전의 GCM API 기반으로 작성하였다.
App 구성은 이렇다.
1. App Widget : 스마트폰 화면에서 바로 Plug를 켜고 끄고 할 Widget
2. Basic Activity: Plug 켜고 끄기, GCM 등록하기 등의 단위 테스트 및 상태표시 용도
3. Service: Push가 발생되었을 때에 호출되는 Listener Service
1번 App Widget은 이미 구현되어 있고, Push 이벤트를 받아서 갱신시켜주는 코드만 추가하면 된다.
App Widget 구현은 4편을 참고
[Raspberry pi] - 4편 스마트 콘센트? Smart Plug! + 앱위젯
3번 Service는 Push를 수신하고, 이를 App Widget에 넘겨주는 기능만 한다.
자 시작.
우선 firebase에서 다운로드 받은 google-services.json 파일을 프로젝트/app 밑에 배치시킨다.
google-services.json은 Push 서비스에 필요한 api key와 프로젝트 번호 등이 저장된 파일이다.
다운로드 경로를 모르겠으면 7편 firebase 등록 편을 다시 보면 된다.
[Raspberry pi] - 7편 스마트 콘센트? Smart Plug! + Node.js Push 서버 (Firebase 등록)
App Widget 수정
Widget이 스마트폰 바탕화면에 처음 추가될 때에 업데이트 이벤트가 발생하고, 이 때에 Registration ID를 서버에 전송하고자 한다.
Registration ID는 최초 한번 전송하면 되고, 서버는 이 정보를 기반으로 GCM에 Push를 요청한다.
한 번 받은 Registration ID는 SharedPreferences에 저장하여, 반복 전송을 방지한다.
@Override
public void onReceive(Context context, Intent intent){
................중략................
if(intent.getAction().equals(ACTION_UPDATE) || intent.getAction().equals(ACTION_STATE)) {
int[] appWidgetIds = manager.getAppWidgetIds(new ComponentName(context, getClass()));
for(int id:appWidgetIds) {
Log.d(TAG, "onReceive.appWidgetId : " + String.valueOf(id));
manager.updateAppWidget(id, views);
}
regid = getRegistrationId(context);
if (regid.isEmpty()) {
registerInBackground(context);
Log.d(TAG, "Issue gcm regid : " + regid);
}
}................중략................ }
private String getRegistrationId(Context context) {
SharedPreferences prefs = context.getSharedPreferences(Plug.class.getSimpleName(), Context.MODE_PRIVATE);
return prefs.getString(PROPERTY_REG_ID, "");
}
private void storeRegistrationId(Context context, String regid) {
SharedPreferences prefs = context.getSharedPreferences(Plug.class.getSimpleName(), Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(PROPERTY_REG_ID, regid);
editor.apply();
}
private void registerInBackground(final Context context) {
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
String msg = "";
try {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
regid = gcm.register(defaultSenderId);
String user = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
sendRegistrationIdToBackend(user);
storeRegistrationId(context, regid);
} catch (IOException e) {
e.printStackTrace();
}
return msg;
}
@Override
protected void onPostExecute(String msg) {
Log.d(TAG, msg);
}
}.execute(null, null, null);
}
private void sendRegistrationIdToBackend(String user) {
RequestPI requestPi = null;
String url = strRegClient + "?user=" + user + "®id=" + regid;
Log.d(TAG, url);
requestPi = new RequestPI(url);
requestPi.start();
}
GcmListenerService 추가
서버로 부터 Push가 수신되었을 때에 호출되는 Listener Service 이다.
단순히 Push 메시지를 받아서 App Widget 에 던져주기만 하면 된다.
public class PushListnerService extends GcmListenerService {
private final static String ACTION_STATE = "com.viewise.home.plugwidget.GETPUSH";
public PushListnerService() {
}
@Override
public void onMessageReceived(String s, Bundle bundle) {
String state = bundle.getString("state");
Log.d("GCM", state);
Intent intent = new Intent(this, Plug.class);
intent.setAction(ACTION_STATE);
intent.putExtra("state", state);
sendBroadcast(intent);
super.onMessageReceived(s, bundle);
}
}
App 수준 gradle
.........................중략.......................... dependencies { compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.0'
compile 'com.google.android.gms:play-services-gcm:9.0.0'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:design:25.3.0'
testCompile 'junit:junit:4.12'
}
Project 수준 gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.google.gms:google-services:3.0.0'
} } .........................후략..........................
AndroidManifest.xml
.........................중략.......................... <service
android:name=".PushListnerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service> .........................중략..........................
처음 구현할때에는 고민이 많아서 복잡하게 코딩한 듯 했는데 정리해보니 생각보다 단촐하다.
이미 한번 올린 시험영상이지만 한 번 더...
아래의 빨간색 상자에 집중해서 보면 된다.
Plug를 켜면 스마트폰 위젯도 켜지고, 끄면 같이 꺼진다.
총 9편으로 스마트 콘센트(Smart Plug) 기능은 이제 완성된 듯 하다.
'Raspberry pi' 카테고리의 다른 글
Swap 늘리기 (0) | 2017.06.15 |
---|---|
4편 PLEX 최적화 - 자막 일괄변환 (0) | 2017.05.21 |
8편 스마트 콘센트? Smart Plug! + Node.js Push 서버 (서버편) (0) | 2017.05.03 |
라즈베리파이에 Node.js 설치 (0) | 2017.04.29 |
3편 PLEX 최적화 - PLEX Media Server 재설치 (2) | 2017.04.29 |