2011-07-15 20 views
5

Tôi đang phát triển ứng dụng Nhắn tin C2DM. Trong đó tôi nhận được id đăng ký bằng cách sử dụng lớp học C2DMBroadcastReceiver, C2DMBaseReceiverC2DMMessaging. Tôi sẽ là C2DMReceiver trong gói của tôi kéo dài C2DMBaseReceiver.C2DMBroadcastBộ phận nhận diện của người nhận không thực hiện (Để đăng ký)

Dưới đây là đoạn mã của tôi

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 */);   
    } 

} 

tập tin Manifest

<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"); 
    } 
    .......... 

}

Bây giờ vấn đề của tôi là,

tôi gọi Đăng ký của C2DMMessaging từ hoạt động của tôi bằng cách thông qua các ngữ cảnh, Dịch vụ được tạo trong C2DMMessaging, Sau đó im không nhận được bất kỳ thứ gì g trong số C2DMBroadcastReceive's onReceive().

Đây là mã tôi nhận được từ vogille.de. Điều này làm việc tốt nếu tôi sử dụng này như vậy nhưng khi im sử dụng này trong ứng dụng của tôi vấn đề này đang đến.

Tôi đã đi qua một số bài đăng googled một cái gì đó mà tôi thấy rằng vấn đề có thể là trong manifest tệp.

tôi không biết nơi nào sai. Bất cứ ai có thể giúp đỡ về điều này?

Trả lời

7

Vì lý do không rõ ràng, lớp người nhận của bạn, C2DMReceiver, phải nằm trong thư mục gốc của gói của bạn, được khai báo là tên gói trong tệp kê khai của bạn. Đây là cách duy nhất tôi quản lý để làm việc này ... vì vậy thay vì:

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

thử

service android:name=".C2DMReceiver" 

đây là trích đoạn biểu hiện của tôi (ngoại trừ các điều khoản)

<!--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

Tôi đã cung cấp com.sample.gt.c2dm.C2DMReceiver vì tên gói của tôi là com.sample.gt nhưng bộ thu C2DM nằm trong gói được chỉ định ở trên. Nếu tôi cung cấp cho đơn giản là .C2DMReceiver nó được đưa ra lỗi (không thể tìm thấy lớp) – Hussain

+0

@ Hussain không muốn âm thanh thô lỗ hoặc bất cứ điều gì, nhưng bạn cũng nên di chuyển lớp trong thư mục gốc của gói của bạn;) ở gốc, và do đó được khai báo nằm trong thư mục gốc bên trong tệp kê khai. – olamotte

+0

Cảm ơn bạn đã dành thời gian cho điều này :), Có cần thiết rằng .C2DMReceiver nên có sẵn trong thư mục gốc. cos, im có nhiều hoạt động n tập tin lớp khác vì vậy nó sẽ tốt hơn cho tôi nếu nó trong gói có sẵn bên trong gói gốc. – Hussain

4

Tôi cảm thấy đau đớn của bạn, tôi đã cố gắng để C2DM hoạt động cũng như xem vogille.de giữa các trang web khác. Điều cuối cùng làm việc cho tôi là sử dụng tệp C2DM.jar được tạo bởi nhật thực "Dự án Android của Máy ứng dụng đã kết nối" (trong Tệp> Mới> Dự án> Google).

Lưu ý: tại thời điểm viết bài này, bạn phải cài đặt phiên bản beta của plugin để có tùy chọn này! http://code.google.com/eclipse/beta/docs/download.html

phần có liên quan của file manifest của tôi:

<?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> 

Dưới đây là đoạn code tôi sử dụng để tương tác với các dịch vụ 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) { 
    } 
} 

Mẫu mã được tạo ra bao gồm một ứng dụng AppEngine Java dựa.Tôi đang sử dụng python, đây là đoạn code liên quan đến khỏa lấp bài đăng này:

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() 

ứng dụng Android của bạn nên gọi phương pháp/C2DM/đăng ký và/C2DM/unregister để thiết lập và xóa các thiết bị mã C2DM với backend. Mã phụ trợ khác nên gọi sendMessage để yêu cầu Google chuyển tiếp thư tới thiết bị.

Mã này bao gồm mật khẩu gmail của bạn. Tôi sử dụng một địa chỉ gmail throwaway cho các nhu cầu c2dm của tôi và thực sự thiết lập mật khẩu thông qua thao tác datastore trực tiếp thay vì có nó trong plaintext trong mã. Thậm chí nếu ai cũng biết cách quản lý xác thực tốt hơn thì tôi rất muốn nghe về nó.

Tôi hy vọng điều này sẽ hữu ích!

+0

Cảm ơn bạn đã giúp đỡ ur .. Tôi không thể tìm thấy tập tin> New> Dự án> Google trong Eclipse Gallileo .. Tôi đã thực hiện cập nhật đó cũng. – Hussain

3

Hãy để tôi bắt đầu bằng cách nói rằng thiết lập IDE của bạn không phải là vấn đề ở đây và quá trình này thậm chí không cần máy chủ (hiện tại) với công cụ ứng dụng, điều này làm tăng thêm tùy chọn của Google trong tệp> Mới> Project

Thiết bị Android liên hệ với máy chủ Google C2DM để nhận id đăng ký nếu quá trình thành công Google trả lời bằng id đăng ký, sau này bạn có thể gửi tới máy chủ của mình, hiện tại chúng tôi sẽ cố gắng xử lý và đăng ký id trên thiết bị, sau đó bạn có thể xử lý điều đó.

Như tôi hiểu, bạn đã tạo một dự án Android, lấy lớp học trên Google mà họ sử dụng trong chrome của họ để dụ điện thoại, mà vogella.de cung cấp trong hướng dẫn của họ

sau khi làm như vậy trong hoạt động khởi động của bạn, bạn được gọi là phương thức C2DMMessaging.register(this, "[email protected]);

có một số điều có thể xảy ra ở đây: ps chúng được sắp xếp theo khả năng của chúng để xảy ra theo các tiêu chuẩn của tôi, ngoài ra tôi đã loại trừ một số trường hợp xuất hiện không áp dụng cho các đoạn trích bạn đã đề cập.

  1. bạn chưa đăng ký tài khoản email vai trò với google.
    hãy đi qua http://code.google.com/android/c2dm/signup.html và làm như sau chấp nhận giấy phép sau khi đọc nó một cách cẩn thận
    điền tất cả các thông tin cần thiết càng chính xác càng tốt, và chú ý đến các lĩnh vực sau:
    "Tên gói ứng dụng Android của bạn" và "Email tài khoản vai trò (người gửi)"
    email vai trò này là email bạn sẽ sử dụng trong phương thức C2DMMessaging.register và máy chủ ứng dụng của bạn sau trên
  2. Bạn đang thử nghiệm trên trình mô phỏng Android không được định cấu hình chính xác cho thử nghiệm này
    Để giả lập Android của bạn được định cấu hình cho tác vụ này, bạn nên làm như sau:
    Tạo AVD mới (Thiết bị ảo Android) bằng cách nhấp vào menu Window> Android SDK và Trình quản lý AVD> Thiết bị ảo> Mới
    chọn API Google mục tiêu (Google Inc.) - API cấp 8 (nếu tùy chọn này không khả dụng vui lòng tải xuống từ Gói có sẵn> Tiện ích bổ sung của bên thứ ba> Google Inc.)
    điền phần còn lại khi bạn vui lòng
    bắt đầu AVD mới và điều hướng đến Cài đặt> Tài khoản & Đồng bộ hóa> thêm tài khoản google> bất kỳ tài khoản google nào.
    lặp lại thử nghiệm của bạn
  3. Trước khi tôi có thể điền vào các trường hợp khác tôi cần phải nhìn thấy phần còn lại của lớp học trên Google bạn đang sử dụng và C2DMReceiver Dịch vụ mà bạn đã tạo


tôi không thể bình luận do là người dùng có danh tiếng thấp

+0

Ông Hussain, Vui lòng thử 1 và 2 và nếu họ không làm việc cung cấp cho tôi phần còn lại của các lớp Google khi bạn sử dụng chúng và Dịch vụ C2DMReceiver cho tôi để có câu trả lời chính xác về lý do đơn đăng ký của bạn không hoạt động –

+0

Cảm ơn câu trả lời của bạn shereef. Các bước 1 và 2 được thực hiện đúng, cos cho ứng dụng mẫu khác C2DM đang hoạt động tốt. Bây giờ vấn đề là khi tôi gọi đăng ký dịch vụ được bắt đầu, nhưng im không nhận được bất cứ điều gì trong 'BroadcastReceiver'. – Hussain

Các vấn đề liên quan