2015년 5월 27일 수요일

안드로이드 : GCM Message 사용(2) : 앱에서 GCM Service ID 등록


일단 구글 개발자 사이트에서 GCM Service 를 등록했으면, 이제 앱에서 사용자 폰을 GCM Service 에 등록하고 ID 를 받아야 한다.

이클립스에서 일단 구글 서비스 패키지가 설치가 되어 있어야 하니...


"Android SDK Manager" 를 실행해서...


"Google Play service" 가 설치되어 있어야 한다.
이게 설치되어 있으면...

{안드로이드 SDK 설치된폴더}/sdk/extras/android/support/v4/android-support-v4.jar

에 있는 "android-support-v4.jar" 를 lib 폴더에 복사해 준다.


이 때, "gcm.jar" 파일도 필요한데... 이건 뭐... 인터넷에서 검색해 넣자... 많이 나온다.
이게 원래는 "Android SDK Manager" 에서 "Google Cloud Messaging for Android Library" 설치하면 나오는 파일인데, 이게 어떨때는 설치항목에 나오고 어떤때는 안나오고 막 그렇다.
파일만 있으면 해당 패키지가 설치되어 있지 않더라도 상관없으니, 그냥 다운 받아 넣어도 된다.

이렇게 라이브러리를 등록하고... 앱을 만들면...


대충 이런 형태가 된다.
MainActivity.java 는 그냥 최초 로딩 되는 폼일 뿐이고,
GCMHttpConnect.java 와 GCMIntentService.java 가 실제 동작하는 클래스다.

소스를 살펴보면...

[AndroidManifest.xml]

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kr.blogspot.son10001"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
   
    <permission android:name="kr.blogspot.son10001.permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="kr.blogspot.son10001.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
 <uses-permission android:name="android.permission.VIBRATE"/>
   
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
       
  <receiver android:name="com.google.android.gcm.GCMBroadcastReceiver"
      android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
                <category android:name="kr.blogspot.son10001" />
            </intent-filter>
        </receiver>
        <service android:name=".GCMIntentService" />
    </application>
</manifest>

[MainActivity.java]

package kr.blogspot.son10001;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

import com.google.android.gcm.GCMRegistrar;

public class MainActivity extends Activity {
 private static final String TAG = "GCM";
 private static final String SENDER_ID = "529212329497"; 
 
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        registerGcm();
    }
    
    public void registerGcm() {
  GCMRegistrar.checkDevice(this);
     GCMRegistrar.checkManifest(this);
      
        //GCM 등록여부
       final String regId = GCMRegistrar.getRegistrationId(this);

       //등록된 ID가 없으면 ID값을 얻어옵니다
       if (regId.equals("") || regId == null) {
        GCMRegistrar.register(this, SENDER_ID);
       }else{
        Log.w(TAG, "Already Registered : " + regId);
       }
    }

}


[GCMHttpConnect.java]

package kr.blogspot.son10001;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class GCMHttpConnect extends Thread{
 private static final String TAG = "HTTP";
 private Request mRequest;
 private String mString;
 
 public GCMHttpConnect(String url, Request request) {
  mString = url;    
  mRequest = request;
 }
 
 @Override
 public void run() {
  download(mString);
  
  Message msg = new Message();
  msg.what = 0;
  mHandler.sendMessage(msg);
 }
 
 Handler mHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
   // TODO Auto-generated method stub
   if (mRequest != null) {  
    mRequest.OnComplete();
   }
  }  
 };
 
 public static interface Request {
  public void OnComplete();
 }
 
 public void download(String address) {
  StringBuilder jsonHtml = new StringBuilder();
     try{
      //연결 url 설정
      URL url = new URL(address);
      //컨넥션 객체 생성
      HttpURLConnection conn = (HttpURLConnection)url.openConnection();
      conn.setDefaultUseCaches(false);                                           
            conn.setDoInput(true);                         // 서버에서 읽기 모드 지정
            conn.setDoOutput(false);                       // 서버로 쓰기 모드 지정 
            conn.setRequestMethod("POST");         // 전송 방식은 POST
            
      //연결되었다
      if(conn != null){
       conn.setConnectTimeout(10000);
       conn.setUseCaches(false);
       //연결확인 코드가 리턴되었을 때
       if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
        for(;;){
         String line = br.readLine();
         if(line == null) break;
         jsonHtml.append(line);
        }
        br.close();
       }
       conn.disconnect();
      }
     }catch(Exception e){
      Log.w(TAG, e.getMessage());
     }
 }
}



[GCMIntentService.java]

package kr.blogspot.son10001;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gcm.GCMBaseIntentService;

public class GCMIntentService extends GCMBaseIntentService {
 private static final String TAG = "GCM";
 private static final String SENDER_ID = "529212329497";
 private GCMHttpConnect.Request httpRequest = new GCMHttpConnect.Request() {
  @Override
  public void OnComplete() {
   // TODO Auto-generated method stub
   showToast();
  }
 };
 
 public GCMIntentService() {
  super(SENDER_ID);
 }

 @Override
 protected void onMessage(Context context, Intent intent) {
  if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
   showMessage(context, intent);
  }
 }

 @Override
 protected void onError(Context context, String msg) {
  // TODO Auto-generated method stub
  Log.w(TAG, "onError!! " + msg);
 }

 @Override
 protected void onRegistered(Context context, String regID) {
  // TODO Auto-generated method stub
  if(!regID.equals("") || regID != null){
   Log.w(TAG, "onRegistered!! " + regID);
  }
 }

 @Override
 protected void onUnregistered(Context context, String regID) {
  // TODO Auto-generated method stub
  Log.w(TAG, "onUnregistered!! " + regID);
 }
 
 public void showToast(){
  Toast.makeText(this, "RegID 등록 완료", Toast.LENGTH_LONG).show();
 }
 
 private void showMessage(Context context, Intent intent){
  Log.w(TAG, "onShowMessage!! ");

  String title = intent.getStringExtra("title");
  String msg = intent.getStringExtra("msg");
  String ticker = intent.getStringExtra("ticker");
  
  NotificationManager notificationManager = (NotificationManager)context.getSystemService(Activity.NOTIFICATION_SERVICE);
  
  //행하는 이벤트를 하고싶을 때 아래 주석을 풀어주세요
  PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, 
    new Intent(context, MainActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0);
//  PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, new Intent(), 0);
  
  Notification notification = new Notification();
  notification.icon = R.drawable.ic_launcher;
  notification.tickerText = ticker;
  notification.when = System.currentTimeMillis();
  notification.vibrate = new long[] { 500, 100, 500, 100 };
  notification.sound = Uri.parse("/system/media/audio/notifications/20_Cloud.ogg");
  notification.flags = Notification.FLAG_AUTO_CANCEL;
  notification.setLatestEventInfo(context, title, msg, pendingIntent);
  
  notificationManager.notify(0, notification);
 }
 
}


대강 이렇다.
중요한 것은...


AndroidManifest 에 있는 "service" 항목에 있는 클래스가 실제 GCM 을 컨트롤 하는 함수라는것을 알고 있으면, 어떻게든 분석이 가능 할 것이다.

이렇게 하고 앱을 실행 해 보면...


저렇게 GCM service 등록 ID 를 알아 낼수 있는데, 이걸 이용해서 서버에서 특정 사용자에게 Push 메시지를 보낼 수 있다.

일반적으로는 앱을 실행 할때 등록 ID 을 생성해서 서버에다 전송해 등록해 놓고, 필요 할 때, 저 ID 를 이용해 메시지를 보내면, 해당 폰에서 메시지를 받아 볼 수 있게 된다.

이제 저 ID 를 이용해 Push 서버에 메시지를 보내기만 하면 된다.