안녕하세요. 안드로이드 초짜 개발자 입니다.
구글에서 C2DM 대용으로 만든 GCM을 사용하고자 하는데요. 현재 개발자 등록이 된 Sender_ID도 가지고 있는 상태입니다.
주로 증상은 아래 소스를 빌드하면 결과가 아래와 같습니다.
-> 01-04 12:30:55.435: E/data(10075): onRecoverableError error: SERVICE_NOT_AVAILABLE
구글링을 통하여 확인을 해보면은 500/503내지는 단말 응답부분에서 뭐가 잘못되었다고는 하는데요. 당췌 무슨 말인지 하나도
모르겠더라구요.
소스 코드 는 아래 와 같습니다.
제가 알기로는 아래 (#1)번을 하면은 (#2)번으로 등록여부가 와야 하는 것 같은데, (#3)번으로 에러만 출력하더라구요.
그리고 만약에 정상적으로 단말의 senderid로 등록이 완료되면은 GCMIntentService 의 onRegistered()에서 서버로 부터 registrationID를 받
오는 것은 알겠는데, GCMBroadcastReceiver 의 onReceive()는 어떤 역활을 하는건가요? 데모프로그램을 봐도 따로 호출해 주는 부분은
없는 것 같은데요.
<MainActivity>
public class Android_Activity extends Activity
{
static final String SENDER_ID = "xxxxx~~~";
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);
final String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals(""))
{
Log.e(TAG, " (2) registration id :" + regId);
GCMRegistrar.register(this, SENDER_ID); <--(#1)
}
else
{
if (GCMRegistrar.isRegisteredOnServer(this))
{
Log.e(TAG,"this device is already posted on App Server.");
}
}
}
@Override
protected void onDestroy()
{
unregisterReceiver(messageReceiver);
GCMRegistrar.onDestroy(this);
super.onDestroy();
}
@Override
protected void onPause()
{
super.onPause();
GCMRegistrar.unregister(this);
}
}
< GCMIntentService >
import com.google.android.gcm.GCMBaseIntentService;
public class GCMIntentService extends GCMBaseIntentService
{
String TAG = "GCMIntentService ";
static final String SENDER_ID = "140480833493";
String c2dm_msg = null;
public GCMIntentService()
{
super(SENDER_ID);
Log.e(TAG, "GCMIntentService created.");
}
@Override
protected void onRegistered(Context context, String registrationId) <--(#2)
{
Log.e(TAG, "Device registered: regId = " + registrationId);
GCMAppServer.post(context, registrationId);
}
@Override
protected void onUnregistered(Context context, String registrationId)
{
Log.e(TAG, "unregistered = "+ registrationId);
GCMAppServer.delete(context, registrationId);
}
@Override
protected void onError(Context arg0, String errorId)
{
Log.e(TAG, "onError error: " + errorId);
}
@Override
protected boolean onRecoverableError(Context context, String errorId) <--(#3)
{
Log.e(TAG, "onRecoverableError error: " + errorId);
return super.onRecoverableError(context, errorId);
}
@Override
protected void onMessage(Context context, Intent intent)
{
Log.e(TAG, "onMessage received");
if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE"))
{
c2dm_msg = intent.getStringExtra("message"); ///intent.getExtras().getString("msg");
GET_GCM();
Log.e(TAG, c2dm_msg);
}
}
public void GET_GCM()
{
Thread thread = new Thread(new Runnable()
{
public void run()
{
handler.sendEmptyMessage(0);
}
});
thread.start();
}
private Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
Context context = getApplicationContext();
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, c2dm_msg, duration);
toast.show();
c2dm_msg = null;
}
};
}
< GCMBroadcastReceiver >
public class GCMBroadcastReceiver extends BroadcastReceiver
{
static final String TAG = "GCMtest";
@Override
public final void onReceive(Context context, Intent intent)
{
Log.e(TAG, "onReceive: " + intent.getAction());
String className = getGCMIntentServiceClassName(context);
Log.e(TAG, "GCM IntentService class: " + className);
setResult(Activity.RESULT_OK, null /* data */, null /* extra */);
}
/**
* Gets the class name of the intent service that will handle GCM messages.
*/
protected String getGCMIntentServiceClassName(Context context)
{
String className = context.getPackageName() + DEFAULT_INTENT_SERVICE_CLASS_NAME;
return className;
}
}
< XML menifest 파일 >
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test.sync"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".Android_SyncActivity"
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="com.test.sync" />
</intent-filter>
</receiver>
<service android:name=".GCMIntentService"/>
</application>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<permission android:name="com.test.sync.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<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="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.test.sync.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.google.android.c2dm.permission.SEND" />
</manifest>
끝까지 읽어주셔서 감사합니다.
제가 잘 이해를 못했습니다. 제가 알고 있기로는 단말에서 푸쉬서비스를 받으려면 google GCM서버로 senderID를 등록해서 성공하면, google GCM서버에서 인증 키 비슷한 등록 번호를 주면은 이것을 "서드파티 서버"에 같이 보내주고 등록하여 ~ 대략 이런 방식으로 알고 있는데요.
문제는 googleGCM서버에서 제가 등록한 SenderID에 대한 응답으로 registrationId를 주어야 하는데, 안주는게 문제인것 같은데요.
이것은 단순히 GCMRegistrar.register(this, SENDER_ID);를 실행하면 GCMIntentService의 onRegistered()으로 단말이 받아오는게 아닌지요?
제가 잘 몰라서 여줘봅니다.




일단 onReceive()는 인위적으로 호출하는게 아니라 특정 작업이 끝나면 자동으로 호출되는
콜백 메서드입니다. GCM에서는 RegId등록이 되거나 메세지를 받으면 호출이 되죠
근데 manifest 를 보니
<receiver android:name="com.google.android.gcm.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" >
이렇게 되어있네요. 이건 GCM라이브러리에 정의되어있는 브로드캐스트를 쓰겠다는거니
GCMBroadcastReceiver클래스는 필요없습니다.