요번에 C2DM이 GCM으로 정식서비스를 하여서 많은 분들이 혼란을 겪고 있는거 같아
저같은 초보분들 삽질하지 마시라고 가이드를 적어봅니다. (근데 왜 강좌/학습 게시판에 글작성이 안되나요??ㅜㅜ)
몇몇 블로그에 예제들을 보았지만 제가 하려는것과 속성이 틀려서 결국
되지도 않는 영어실력으로 개발자문서를 보며 만들었습니다. ㅜㅜ
저는 웹페이지를 거치지않고 자바단에서만 동작하게 하였습니다(필요시 웹DB 사용)
여기서 사용되는 소스의 주 타겟은 컨텐츠서비스를 하는 어플입니다.
무슨 말이냐하면 유저들 정보를 가지고 있으면 한꺼번에 푸쉬하는거죠(이벤트알림이나 공지사항 등등)
여기선 간단히 설명드리고 자세한건 첨부파일을 받아서 봐주세요.
-------------------- GCMMain.java --------------------
private static final String TAG = "GCM";
private static final String PASSWORD = "1111";
//자신의 Project ID 를 넣어주세요
private static final String SENDER_ID = "자신의 프로젝트 아이디";
private EditText managerPassword;
private Button managerButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//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);
}
setInit();
}
-----
-------------------------------------------------
GCMMain.java 에서는 위에 SENDER_ID에 자신의 Project ID를 넣어주시면 됩니다.
-------------------- GCMIntentService.java --------------------
private static final String TAG = "GCM";
private static final String INSERT_PAGE = "http://자신의 서버 아이피/insert_registration.php";
private static final String SENDER_ID = "자신의 프로젝트 아이디";
private GCMHttpConnect httpConnect = null;
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);
// 단일전송일때 주석처리
// insertRegistrationID(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){
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, 어플이 처음 시작되는 클래스명.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);
}
public void insertRegistrationID(String id){
httpConnect = new GCMHttpConnect(INSERT_PAGE + "?regID=" + id, httpRequest);
httpConnect.start();
}
-------------------------------------------------------------
GCMIntentService.java 에서는 INSERT_PAGE와 SENDER_ID가 있습니다.
SENDER_ID는 GCMMain.java 와 같이 자신의 Project ID를 넣어주면 됩니다.
INSERT_PAGE에는 메세지를 일괄전송시에 RegID값들을 DB에서 불러오기 위한 서버주소입니다.
서버가 없고 RegID값을 DB가 아닌 어플내에서 관리한다면 필요없는 부분입니다.
그 밑에 PendingIntent 에서 주석으로 된 부분에 어플이 시작되는 클래스명을 적어주면
메세지 수신시 인디케이터에 메시지가 뜨면서 클릭시 해당 액티비티를 실행시키는 겁니다.
그리고 insertRegistrationID(String id)부분은 마찬가지로 웹서버에서 DB데이터를 뽑아오는
함수입니다. "?regID=" 부분은 파라메터 인자값이고요. 역시 서버가 없다면 주석처리 하시면 됩니다.
-------------------- GCMSendMessage.java --------------------
private Sender gcmSender; //GCM Sender
private Message gcmMessage; //GCM Message
private Result gcmResult; //GCM Result(단일 전송)
private MulticastResult gcmMultiResult; //GCM Multi Result(일괄 전송)
//일괄전송에 필요한 List 변수
private List<String> registrationIds = new ArrayList<String>();
//단일전송에 필요한 변수
private String registrationId = "이곳에 RegId를 입력하세요";
//DB에서 RegID를 가져오기 위해 만들어진 서버 페이지 주소
private static final String SELECT_PAGE = "http://자신의 서버 아이피/select_registration.php";
//파싱하기 위해 데이터를 담을 변수
private static String JSON = null;
//개발자 콘솔에서 발급받은 API Key
private static String API_KEY = "자신이 발급받은 API KEY를 입력하세요";
//메세지의 고유 ID(?)정도로 생각하면 됩니다. 메세지의 중복수신을 막기 위해 랜덤값을 지정합니다
private static String COLLAPSE_KEY = String.valueOf(Math.random() % 100 + 1);
//기기가 활성화 상태일 때 보여줄 것인지.
private static boolean DELAY_WHILE_IDLE = true;
//기기가 비활성화 상태일 때 GCM Storage에 보관되는 시간
private static int TIME_TO_LIVE = 3;
//메세지 전송 실패시 재시도할 횟수
private static int RETRY = 3;
private EditText pushTicker;
private EditText pushTitle;
private EditText pushMessage;
private TextView pushLength;
private Button pushShow;
private Button pushTrans;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.send_message);
setLayout();
// 단일전송시에는 주석처리
// getJson(SELECT_PAGE);
// 단일전송시에는 주석처리
// getToken();
}
public void setMessage(){
gcmSender = new Sender(API_KEY);
gcmMessage = new Message.Builder()
.collapseKey(COLLAPSE_KEY)
.delayWhileIdle(DELAY_WHILE_IDLE)
.timeToLive(TIME_TO_LIVE)
.addData("ticker", pushTicker.getText().toString())
.addData("title", pushTitle.getText().toString())
.addData("msg", pushMessage.getText().toString())
.build();
}
public void sendMessage(){
//일괄전송시에 사용
// try {
// gcmMultiResult = gcmSender.send(gcmMessage, registrationIds, RETRY);
// } catch (IOException e) {
// Log.w(TAG, "IOException " + e.getMessage());
// }
// Log.w(TAG, "getCanonicalIds : " + gcmMultiResult.getCanonicalIds() + "\n" +
// "getSuccess : " + gcmMultiResult.getSuccess() + "\n" +
// "getTotal : " + gcmMultiResult.getTotal() + "\n" +
// "getMulticastId : " + gcmMultiResult.getMulticastId());
//단일전송시에 사용
try {
gcmResult = gcmSender.send(gcmMessage, registrationId, RETRY);
} catch(IOException e) {
Log.w(TAG, "IOException " + e.getMessage());
}
Log.w(TAG, "getCanonicalIds : " + gcmResult.getCanonicalRegistrationId() + "\n" +
"getMessageId : " + gcmResult.getMessageId());
}
-----------------------------------------------------------------
메세지를 보내는 GCMSendMessage.java 부분입니다.
String registrationId 는 단일전송시에 직접 입력하는 부분입니다. 등록시 얻은 RegID를 적어주시면 됩니다.
List<String> registrationIds 는 일괄전송시에 사용되는 변수로 onCreate에서
데이터를 얻어오고 그 수만큼 add하고 있습니다.
SELECT_PAGE는 DB에서 RegID들을 얻어오기 위한 서버페이지입니다.
역시 서버가 없다면 무시해도 됩니다.
API_KEY는 Api Console 센터에서 발급받은 Key입니다. 뭐 Project ID와 API_KEY 는 전부 아시리라 믿습니다.
---------- 정리 ------------
- 단일전송일 경우(한명에게 보내고자 할 경우 or 테스트용)
위에서 말한 API_KEY, SENDER_ID, RegID 변수에 자신의 값들을 넣어주시고 테스트하시면 됩니다.
- 일괄전송일 경우
(개인 서버가 있는경우)
위 소스에 있는 주석들을 풀어준 후 자신의 서버주소를 적어주시면 됩니다.
(개인 서버가 없는경우)
RegID 값들을 알 수 있다면 List에 직접 add하여 주시거나
SharedPreferences를 이용하여 데이터를 불러와 add하셔도 됩니다.
혹시 서버페이지를 만드시려고 하는분이 있으시면 참고되시라고 같이 올렸습니다.
---------------------------
--------- 필수로 해야할것들 ---------
이 소스를 이용하여 자신의 프로젝트에 적용시킬 때 주의하실점이 있습니다.
- Manifest GCM관련 퍼미션등록 여부와 리시버 등록 여부 확인 (첨부된 프로젝트와 비교하세요)
- 각종 퍼미션 (WAKE_LOCK, INTERNET, GET_ACCOUNTS, VIBRATE) <- 요거안해주면 고생많이 합니다.
- !!!GCM라이브러리 추가!!!(gcm.jar gcm-server.jar json_simple-1.1.jar)
제일 중요합니다. 꼭 libs폴더에 넣어서 빌드패스에 추가하셔야합니다.
특히 json_simple-1.1.jar 요놈 없으면 NodefClassException이라는 상큼한 에러가 나옵니다.
라이브러리는 다음과 같은 경로에 있습니다.(개발환경마다 경로가 다를 수 있습니다)
SDK/android-sdk/extras/google/gcm/gcm-client/dlist/gcm.jar
SDK/android-sdk/extras/google/gcm/gcm-server/dlist/gcm-server.jar
SDK/android-sdk/extras/google/gcm/gcm-server/lib/json_simple1.1.jar
-----------------------------------
이상으로 글을 마칩니다. 모르시는 부분이 있으면 코드 조금만 분석해보시면
금방 알 수 있을거에요. ㅎㅎ 워낙 허접한 코드라서..
저같은 초보분들에게 바칩니다. 해보시고 잘되시면 칭찬한번씩만 해주세요.
회사에서 하라는 일은 안하고 이런짓하고 있어요.