2011-07-15 3 views
5

私はC2DM Messagingアプリケーションを開発しています。その中で私はC2DMBroadcastReceiverC2DMBaseReceiverC2DMMessagingクラスを使って登録IDを受け取ります。私はC2DMBaseReceiverを拡張する私のパッケージにC2DMReceiverになります。ここでC2DMBroadcastReceiverのonReceiveが実行されていません(登録のため)

は私のコードスニペット

C2DMMessaging.java

package com.google.android.c2dm; 

import android.app.PendingIntent; 
import android.content.Context; 
import android.content.Intent; 
import android.content.SharedPreferences; 
import android.content.SharedPreferences.Editor; 
import android.util.Log; 

public class C2DMessaging { 
    public static final String EXTRA_SENDER = "sender"; 
    public static final String EXTRA_APPLICATION_PENDING_INTENT = "app"; 
    public static final String REQUEST_UNREGISTRATION_INTENT = "com.google.android.c2dm.intent.UNREGISTER"; 
    public static final String REQUEST_REGISTRATION_INTENT = "com.google.android.c2dm.intent.REGISTER"; 
    public static final String LAST_REGISTRATION_CHANGE = "last_registration_change"; 
    public static final String BACKOFF = "backoff"; 
    public static final String GSF_PACKAGE = "com.google.android.gsf"; 

    // package 
    static final String PREFERENCE = "com.google.android.c2dm"; 

    private static final long DEFAULT_BACKOFF = 30000; 

    /** 
    * Initiate c2d messaging registration for the current application 
    */ 
    public static void register(Context context, 
      String senderId) { 
     Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT); 
     registrationIntent.setPackage(GSF_PACKAGE); 
     registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, 
       PendingIntent.getBroadcast(context, 0, new Intent(), 0)); 
     registrationIntent.putExtra(EXTRA_SENDER, senderId); 
     context.startService(registrationIntent); 
     Log.e("C2DM Services","Service Started"); 

    } 

    /** 
    * Unregister the application. New messages will be blocked by server. 
    */ 
    public static void unregister(Context context) { 
     Intent regIntent = new Intent(REQUEST_UNREGISTRATION_INTENT); 
     regIntent.setPackage(GSF_PACKAGE); 
     regIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, PendingIntent.getBroadcast(context, 
       0, new Intent(), 0)); 
     context.startService(regIntent); 
     Log.e("C2DM Services","unregister"); 
    } 

    /** 
    * Return the current registration id. 
    * 
    * If result is empty, the registration has failed. 
    * 
    * @return registration id, or empty string if the registration is not complete. 
    */ 
    public static String getRegistrationId(Context context) { 
     final SharedPreferences prefs = context.getSharedPreferences(
       PREFERENCE, 
       Context.MODE_PRIVATE); 
     String registrationId = prefs.getString("dm_registration", ""); 
     Log.e("C2DM Services","get registration id"); 
     return registrationId; 

    } 

    public static long getLastRegistrationChange(Context context) { 
     final SharedPreferences prefs = context.getSharedPreferences(
       PREFERENCE, 
       Context.MODE_PRIVATE); 
     Log.e("C2DM Services","getlastregchange"); 
     return prefs.getLong(LAST_REGISTRATION_CHANGE, 0); 
    } 

    static long getBackoff(Context context) { 
     final SharedPreferences prefs = context.getSharedPreferences(
       PREFERENCE, 
       Context.MODE_PRIVATE); 
     Log.e("C2DM Services","getbackoff"); 
     return prefs.getLong(BACKOFF, DEFAULT_BACKOFF); 
    } 

    static void setBackoff(Context context, long backoff) { 
     final SharedPreferences prefs = context.getSharedPreferences(
       PREFERENCE, 
       Context.MODE_PRIVATE); 
     Editor editor = prefs.edit(); 
     editor.putLong(BACKOFF, backoff); 
     editor.commit(); 
     Log.e("C2DM Services","setbackoff"); 
    } 

    // package 
    static void clearRegistrationId(Context context) { 
     final SharedPreferences prefs = context.getSharedPreferences(
       PREFERENCE, 
       Context.MODE_PRIVATE); 
     Editor editor = prefs.edit(); 
     editor.putString("dm_registration", ""); 
     editor.putLong(LAST_REGISTRATION_CHANGE, System.currentTimeMillis()); 
     editor.commit(); 
     Log.e("C2DM Services","clearregid"); 
    } 

    // package 
    static void setRegistrationId(Context context, String registrationId) { 
     final SharedPreferences prefs = context.getSharedPreferences(
       PREFERENCE, 
       Context.MODE_PRIVATE); 
     Editor editor = prefs.edit(); 
     editor.putString("dm_registration", registrationId); 
     editor.commit(); 
     Log.e("C2DM Services","setregid"); 
    } 
} 

C2DMBroadcastReceiver.java

package com.google.android.c2dm; 

import android.app.Activity; 
import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.Intent; 
import android.util.Log; 

public class C2DMBroadcastReceiver extends BroadcastReceiver { 

    @Override 
    public final void onReceive(Context context, Intent intent) { 
     // To keep things in one place. 
      Log.e("C2DM Broadcast receiver","onReceive"); 
     C2DMBaseReceiver.runIntentInService(context, intent); 
     setResult(Activity.RESULT_OK, null /* data */, null /* extra */);   
    } 

} 

マニフェストファイルである

<permission android:name="com.sample.gt.permission.C2D_MESSAGE" 
     android:protectionLevel="signature" /> 
<uses-permission android:name="android.permission.INTERNET" /> 
    <uses-permission android:name="com.sample.gt.permission.C2D_MESSAGE" /> 
    <!-- Permissions --> 
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> 
    <uses-permission android:name="android.permission.WAKE_LOCK" /> 
    <uses-permission android:name="android.permission.GET_ACCOUNTS" /> 
    <service android:name="com.sample.gt.c2dm.C2DMReceiver" /> 

    <!-- 
     Only C2DM servers can send messages for the app. If permission is not 
     set - any other app can generate it 
    --> 
    <receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver" 
     android:permission="com.google.android.c2dm.permission.SEND"> 
     <!-- Receive the actual message --> 
     <intent-filter> 
      <action android:name="com.google.android.c2dm.intent.RECEIVE" /> 
      <category android:name="com.sample.gt.c2dm" /> 
     </intent-filter> 
     <!-- Receive the registration id --> 
     <intent-filter> 
      <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> 
      <category android:name="com.sample.gt.c2dm" /> 
     </intent-filter> 
    </receiver> 

C2DMMessaging.java

public class C2DMessaging { 
    public static final String EXTRA_SENDER = "sender"; 
    public static final String EXTRA_APPLICATION_PENDING_INTENT = "app"; 
    public static final String REQUEST_UNREGISTRATION_INTENT = "com.google.android.c2dm.intent.UNREGISTER"; 
    public static final String REQUEST_REGISTRATION_INTENT = "com.google.android.c2dm.intent.REGISTER"; 
    public static final String LAST_REGISTRATION_CHANGE = "last_registration_change"; 
    public static final String BACKOFF = "backoff"; 
    public static final String GSF_PACKAGE = "com.google.android.gsf"; 


    // package 
    static final String PREFERENCE = "com.google.android.c2dm"; 

    private static final long DEFAULT_BACKOFF = 30000; 

    /** 
    * Initiate c2d messaging registration for the current application 
    */ 
    public static void register(Context context, 
      String senderId) { 
     Intent registrationIntent = new Intent(REQUEST_REGISTRATION_INTENT); 
     registrationIntent.setPackage(GSF_PACKAGE); 
     registrationIntent.putExtra(EXTRA_APPLICATION_PENDING_INTENT, 
       PendingIntent.getBroadcast(context, 0, new Intent(), 0)); 
     registrationIntent.putExtra(EXTRA_SENDER, senderId); 
     context.startService(registrationIntent); 
     Log.e("C2DM Services","Service Started"); 
    } 
    .......... 

}

今私の問題は、私は、コンテキストを渡すことで、私の活動からC2DMMessagingの登録を呼び出し、

あり、サービスはC2DMMessagingで作成され、その後はanythinを受信しませんg C2DMBroadcastReceiverのonReceive()

これはvogille.deのコードです。これは私がこれを私のアプリケーションで使っているときにこの問題が起こっているときにこれを使うとうまくいきます。

私はいくつかのポストnのgoogled何か私は問題manifestファイルにある可能性があることがわかった。

どこが間違っているかわかりません。 誰でもこれを助けることができますか?

答えて

7

あなたのレシーバクラスC2DMReceiverは、パッケージのルートになければなりません。これはマニフェストのパッケージ名として宣言されています。 これは私がこの作業を取得するために管理する唯一の方法です...ので、代わりに:

service android:name="com.sample.gt.c2dm.C2DMReceiver" 

がここ

service android:name=".C2DMReceiver" 

を試すには、(権限を除く)私のマニフェストの抜粋

<!--C2DM --> 
    <service android:name=".C2DMReceiver" /> 
    <receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver" 
     android:permission="com.google.android.c2dm.permission.SEND"> 
     <!-- Receive the actual message --> 
     <intent-filter> 
      <action android:name="com.google.android.c2dm.intent.RECEIVE" /> 
      <category android:name="my.package" /> 
     </intent-filter> 
     <!-- Receive the registration id --> 
     <intent-filter> 
      <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> 
      <category android:name="my.package" /> 
     </intent-filter> 
    </receiver> 
+0

パッケージ名がcom.sample.gtだがC2DM受信者が上記の指定されたパッケージにあるため、私はcom.sample.gt.c2dm.C2DMReceiverを指定しました。もし私が単に.C2DMReceiverとして与えるとエラー(クラスを見つけることができませんでした)が返されます。 – Hussain

+0

@Hussainは失礼や何かを聞きたくありませんが、あなたのパッケージのルートにもクラスを移動する必要があります;ルートで宣言され、マニフェストファイル内のルートにあると宣言されます。 – olamotte

+0

この時間を費やしてくれてありがとう:)、ルートで.C2DMReceiverを利用できるようにする必要があります。 cos、私は多くのアクティビティが他のクラスのファイルを持っているので、Rootパッケージの中にあるパッケージの中にあればそれが良いでしょう。 – Hussain

4

私はあなたの苦痛を感じます、私は他のサイトの間でvogille.deを見ても動作するようにC2DMを取得するのに苦労しました。私のために働いたのは、Eclipseの「App Engine Connected Android Project」(ファイル>新規>プロジェクト> Googleの下)で作成されたC2DM.jarファイルを使用することでした。

注:この執筆時点では、このオプションを使用するには、プラグインのベータ版をインストールする必要があります。私のマニフェストファイルの http://code.google.com/eclipse/beta/docs/download.html

関連する部分:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
     ... 
> 
    <permission 
     android:name="my_package_name.permission.C2D_MESSAGE" 
     android:protectionLevel="signature" 
    /> 
    <uses-permission android:name="my_package_name.permission.C2D_MESSAGE" /> 
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> 
    <uses-permission android:name="android.permission.WAKE_LOCK" /> 

    <application 
     ... 
    > 
     <!-- Only C2DM servers can send messages for the app. If permission is not set - any other app can generate it --> 
     <receiver 
      android:name="com.google.android.c2dm.C2DMBroadcastReceiver" 
      android:permission="com.google.android.c2dm.permission.SEND" 
     > 
      <!-- Receive the actual message --> 
      <intent-filter> 
       <action android:name="com.google.android.c2dm.intent.RECEIVE" /> 
       <category android:name="my_package_name" /> 
      </intent-filter> 
      <!-- Receive the registration id --> 
      <intent-filter> 
       <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> 
       <category android:name="my_package_name" /> 
      </intent-filter> 
     </receiver> 
    </application> 
</manifest> 

は、ここで私はC2DMサービスと対話するために使用するコードです:サンプルコードが生成さ

package my_package_name 

import com.google.android.c2dm.C2DMBaseReceiver; 
import com.google.android.c2dm.C2DMessaging; 

import android.content.Context; 
import android.content.Intent; 
import android.os.Bundle; 

/** 
* Receive C2DM state changes. 
* 
* Be careful: the various onX receivers may be called from a mysterious 
* context -- in particular they cannot safely create new AsyncTask objects. 
*/ 
public class C2DMReceiver extends C2DMBaseReceiver { 

    // GMail account associated with the C2DM application. Must agree with 
    // what the 3rd party server uses to authenticate with C2DM. 
    private static final String C2DM_SENDER = "[email protected]"; 

    // ----------------------------------------------------------------- 

    /** 
    * Ask this device to register for C2DM messaging. Will trigger 
    * onRegistered (or onError) when finished. 
    */ 
    public static void register(Context context) { 
     C2DMessaging.register(context, C2DM_SENDER); 
    } 

    /** 
    * Unregister this device from further C2DM messaging. 
    */ 
    public static void unregister(Context context) { 
     C2DMessaging.unregister(context); 
    } 

    // ----------------------------------------------------------------- 

    public C2DMReceiver() { 
     super(C2DM_SENDER); 
    } 

    @Override 
    protected void onMessage(Context context, Intent intent) { 
     // Extras contains whatever your server put into the C2DM message. 
     final Bundle extras = intent.getExtras(); 
    } 

    @Override 
    public void onError(Context context, String error_id) { 
    } 

    @Override 
    public void onRegistered(Context context, String registration_id) { 
    } 

    @Override 
    public void onUnregistered(Context context) { 
    } 
} 

は、JavaベースのAppEngineアプリが含まれています。私はここでこの記事を締めくくりするため、関連するコードだ、のpythonを使用しています:

class C2dmAuthToken(db.Model): 
    """Maintain an auth token used to talk to the C2DM service. There is at 
    most one of these records.""" 
    role_email = db.StringProperty(indexed=False, default='[email protected]') 
    passwd = db.StringProperty(indexed=False, default='my_password') 
    token = db.TextProperty(indexed=False, default='') 

class C2dmRegistration(db.Model): 
    """Map from user to the C2DM registration id needed for the C2DM 
    service to send messages to the registered device.""" 
    user_id = db.IntegerProperty(required=True) 
    registration_id = db.StringProperty(indexed=False) 

class RegisterHandler(MyRequestHandler.MyRequestHandler): 
    def post(self): 
     # Parse arguments. 
     user_id = self.parseId('user_id') 
     registration_id = self.parseStr('registration_id') 

     # Create or update the device record. 
     record = C2dmRegistration.gql('WHERE user_id = :1', user_id).get() 
     if record == None: 
      record = C2dmRegistration(user_id=user_id) 
     record.registration_id = registration_id 
     record.put() 

class UnregisterHandler(MyRequestHandler.MyRequestHandler): 
    def post(self): 
     # Parse arguments. 
     user_id = self.parseId('user_id') 

     # Unregister this device. 
     record = C2dmRegistration.gql('WHERE user_id = :1', user_id).get() 
     if record != None: 
      record.delete() 

def getAuthToken(): 
    """Return an auth token associated with the role account. Login to 
    Google and store the auth token if needed.""" 
    token_record = C2dmAuthToken.all().get() 
    if token_record == None: 
     token_record = C2dmAuthToken() 

    if len(token_record.token) > 0: 
     return token_record.token 

    form_fields = { 
     'accountType' : 'GOOGLE', 
     'Email' : token_record.role_email, 
     'Passwd' : token_record.passwd, 
     'service' : 'ac2dm', 
     'source' : 'my_source_name', 
    } 
    headers = { 
     'Content-Type' : 'application/x-www-form-urlencoded', 
    } 
    result = urlfetch.fetch(url='https://www.google.com/accounts/ClientLogin', 
          payload=urllib.urlencode(form_fields), 
          method=urlfetch.POST, 
          headers=headers) 
    if result.status_code != 200: 
     logging.warning('getAuthToken: client login http error %d' % result.status_code) 
     return None 

    for line in result.content.split('\n'): 
     if line.startswith('Auth='): 
      token_record.token = line[5:] 

    if len(token_record.token) == 0: 
     logging.warning('getAuthToken: no token') 
     return None 

    logging.info('getAuthToken allocated new token %s' % token_record.token) 
    token_record.put() 
    return token_record.token 

def setAuthToken(token): 
    """Update the auth token.""" 
    token_record = C2dmAuthToken.all().get() 
    if token_record == None: 
     token_record = C2dmAuthToken() 
    token_record.token = token 
    token_record.put() 

def sendMessage(dst_user_id, message): 
    """Send a message to the dst user's device using C2DM.""" 

    registration_record = C2dmRegistration.gql('WHERE user_id = :1', dst_user_id).get() 
    if registration_record == None: 
     logging.warning('SendMessage: no such dst_user_id %ld' % dst_user_id) 
     return False 

    # Use http and not https to avoid an invalid certificate error. 
    # Since the request originates inside google hopefully it is 
    # never snoop-able to the outside world, and does not contain 
    # critically secure info (such as the role password). 
    form_fields = { 
     'registration_id' : registration_record.registration_id, 
     'collapse_key' : '%d' % int(time.time() * 1000), 
     'data.message' : message, 
    } 
    headers = { 
     'Content-Type' : 'application/x-www-form-urlencoded', 
     'Authorization': 'GoogleLogin auth=%s' % getAuthToken(), 
    } 
    result = urlfetch.fetch(url='http://android.apis.google.com/c2dm/send', 
          payload=urllib.urlencode(form_fields), 
          method=urlfetch.POST, 
          headers=headers) 
    if result.status_code != 200: 
     logging.warning('sendMessage: http error %d' % result.status_code) 
     return None 
    if 'Update-Client-Auth' in result.headers: 
     logging.info('updating auth token') 
     setAuthToken(result.headers['Update-Client-Auth']) 
    return True 

def main():  
    application = webapp.WSGIApplication([ 
     ('/c2dm/register', RegisterHandler), 
     ('/c2dm/unregister', UnregisterHandler), 
     ], debug=True) 
    wsgiref.handlers.CGIHandler().run(application) 

if __name__ == '__main__': 
    main() 

あなたのAndroidアプリを設定するには、/ C2DM /登録および/ C2DM /登録解除メソッドを呼び出すと、デバイスは、バックエンドとトークンC2DMクリアする必要があります。他のバックエンドコードはsendMessageを呼び出して、メッセージをデバイスに中継するようにGoogleに依頼する必要があります。

このコードには、Gmailのパスワードが含まれています。私は自分のc2dmのニーズに使い捨てのGmailアドレスを使用し、実際にはコードの平文ではなく直接データストアの操作でパスワードを設定します。まだ誰かが認証を管理するためのよりよい方法を知っていれば、それについて聞いてみたいと思います。

こちらがお役に立てば幸いです。

+0

ですウルの助けをありがとう。私は、Eclipse Gallileoでファイル>新規>プロジェクト> Googleを見つけることはできません..私はまた、更新を行っている。 – Hussain

3

IDEセットアップが問題ではないと言うことから始めましょう。このプロセスでは、ファイル>新規>プロジェクトの下にGoogleオプションを追加するアプリケーションエンジンを備えたサーバー(今のところ)は必要ありません。

アンドロイドデバイスはGoogle C2DMサーバーにコンタクトして、プロセスが成功した場合は登録IDを取得します。後であなたのサーバーに送信できる登録IDを使用してGoogleの返信を行います。これでプロセスを取得して登録しますあなたはそれを処理することができます。私が理解できるように

は、あなたは、Androidのプロジェクトを作成し、彼らはあなたが呼ばれるスタートアップの活動でそうした後、自分のチュートリアル

で提供vogella.de電話の例に彼らのクロームで使用されるGoogleのクラスを取りました方法C2DMMessaging.register(this, "[email protected]);

ここで間違っている可能性のあるものがいくつかあります: psこれらは私の基準によって発生する可能性に応じて順序付けられていますが、あなたが言及したスニペットに当てはまらないケースも除外しています。

  1. Googleにあなたの役割のメールアカウントを登録していません。
    http://code.google.com/android/c2dm/signup.htmlに頭の上、次の操作を行い できるだけ正確にすべての必要な情報を記入し、次のフィールドに注意を払って慎重に
    それを読んだ後、ライセンスに同意してください:
    「あなたのAndroidアプリのパッケージ名」と
    このロールメールは、C2DMMessaging.registerメソッドとアプリケーションサーバーの後で使用するメールです。
  2. このテストで正しく構成されていないAndroidエミュレータでテストしています。
    このタスクのためにあなたのアンドロイドエミュレータを設定するには、以下を行う必要があります:
    メニュー>ウィンドウズ> Android SDKとAVDマネージャ>仮想デバイス>新規
    をクリックして、新しいAVD(Android仮想デバイス)を作成します。対象のGoogle API(Google Inc.) - APIレベル8を選択します[Available packages]> [Third Party Add-ons]> Google Inc.からダウンロードしてください)
    残念ながらお待ちください。
    新しいAVDを開始し、[設定]> [アカウント] & Sync>アカウントの追加> Google>任意のGoogleアカウントに移動します。
    私は私がのためにコメントすることはできませんあなたが


を作成し使用してサービスC2DMReceiverされているGoogleのクラスの残りの部分を参照してくださいする必要があり、他の場合に記入する前に、あなたのテスト

  • を繰り返し低いレピュテーションユーザ

  • +0

    フッサン氏1と2を試してみてください。うまくいかない場合は、残りのGoogleクラスを使用して私にサービスを提供してください。C2DMReceiverは、アプリケーションが動作していない理由を正確に回答します。 –

    +0

    ありがとうあなたの答えshereef。手順1と2は正しく実行され、他のサンプルアプリケーションではC2DMが正常に動作しています。今問題は、サービスが開始されたレジスタを呼び出すときですが、 'BroadcastReceiver'で何も受信していません。 – Hussain

    関連する問題