使用GCM到Android客户端的App Engine

时间:2014-02-13 01:01:22

标签: java android google-app-engine google-cloud-messaging

目标:向Android客户端发送ping。我在用户对象中保存了一系列设备注册ID。

在我的应用程序中自动创建的GCMIntentService.java中,我在这里获得了注册ID

    /**
 * Called back when a registration token has been received from the Google
 * Cloud Messaging service.
 * 
 * @param context
 *            the Context
 */
@Override
public void onRegistered(Context context, String registration) {
    Log.d(TAG, "onRegistered(context, registration), Registration: " + registration);

然后创建DeviceInfo对象(也预先定义了app引擎),然后通过另一个端点将此ID添加到用户。我已经确认这是有效的/看到保持的字符串并假设我的设备现在已正确注册。

当后端发生某些事情时,我有一个自定义通知类并运行此方法:

    public void sendNotificationPingToUsers(
        @Named("userIds") ArrayList<Long> userIds,
        ZeppaNotification notification) throws IOException {

    Sender sender = new Sender(Constants.SENDER_ID);
    PersistenceManager mgr = getPersistenceManager();

    try {
        ArrayList<String> allDevices = new ArrayList<String>();

        for (int i = 0; i < userIds.size(); i++) {
            long userId = userIds.get(i);

            ZeppaUser zeppaUser = mgr
                    .getObjectById(ZeppaUser.class, userId);

            if (zeppaUser != null) {
                ZeppaNotification specificNotification = new ZeppaNotification();
                specificNotification.setToUserId(userId);
                specificNotification.setFromUserId(notification
                        .getFromUserId());
                specificNotification.setEventId(notification.getEventId());
                specificNotification.setExtraMessage(notification
                        .getExtraMessage());
                specificNotification.setNotificationType(notification
                        .getType());

                String extraMessage = specificNotification
                        .getExtraMessage();
                if (extraMessage.length() > 1000) {
                    extraMessage = extraMessage.substring(0, 1000)
                            + "[...]";
                }

                mgr.makePersistent(specificNotification);

                allDevices.addAll(zeppaUser.getDevices());

            }

        }

        if (!allDevices.isEmpty()) {
            Message msg = new Message.Builder().collapseKey("sendToSync")
                    .build();

            MulticastResult result = sender.send(msg, allDevices, 5);
            result.getTotal();

        }

    } catch (IOException ex) {
        ex.printStackTrace();

    } finally {

        mgr.close();
    }

}

我传入了另一个通知,因此我可以为所有用户重新创建它,将其保存在通知表中,然后对设备执行ping操作,以便它可以将此项和其他任何用户拉出来并创建状态栏通知。

此方法,同样在GCMIntentService中:

    @Override
public void onMessage(Context context, Intent intent) {
    Log.d(TAG, "received message ping");

永远不会被调用,这就是我试图从设备方面处理所有事情的地方。任何人都可以指出我可能做错了什么,或者我是否错误地解释了这项服务的工作方式?

谢谢

<?xml version="1.0" encoding="utf-8" standalone="no"?>

<uses-sdk
    android:minSdkVersion="15"
    android:targetSdkVersion="19" />

<permission
    android:name="com.minook.zeppa.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />

<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.minook.zeppa.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

<application
    android:name=".ZeppaApplication"
    android:allowBackup="true"
    android:icon="@drawable/zeppa_icon"
    android:label="@string/app_name"
    android:testOnly="false"
    android:theme="@style/ZeppaTheme"
    android:uiOptions="none" >
    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />

    <activity
        android:name=".LoginActivity"
        android:label="@string/app_name"
        android:logo="@drawable/zeppa_icon"
        android:screenOrientation="portrait" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name=".CreateAccountActivity"
        android:label="@string/create_account"
        android:logo="@drawable/zeppa_icon" >
    </activity>
    <activity
        android:name=".NewFriendsActivity"
        android:label="@string/add_friends"
        android:logo="@drawable/zeppa_icon" >
    </activity>
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name" >
    </activity>
    <activity
        android:name=".EventViewActivity"
        android:label="@string/app_name"
        android:logo="@drawable/zeppa_icon" >
    </activity>
    <activity
        android:name=".NewEventActivity"
        android:label="@string/app_name"
        android:logo="@drawable/zeppa_icon" >
    </activity>
    <activity
        android:name=".UserActivity"
        android:label="@string/app_name"
        android:logo="@drawable/zeppa_icon" >
    </activity>
    <activity
        android:name=".ZeppaPreferenceActivity"
        android:label="@string/event_details"
        android:logo="@drawable/zeppa_icon" >
    </activity>

    <!--  
    <activity
        android:name=".RegisterActivity"
        android:launchMode="singleTop" >
    </activity> 
    -->

    <service android:name=".GCMIntentService" />

    <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" />

            <category android:name="com.minook.zeppa" />
        </intent-filter>
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

            <category android:name="com.minook.zeppa" />
        </intent-filter>
    </receiver>
</application>

另一个注意:我尝试使用项目编号和GAE控制台生成的服务器密钥,没有指定的IP。到目前为止都没有工作过。

1 个答案:

答案 0 :(得分:0)

我刚才意识到我再也没有回过头来。 事实证明,他的app-engine创建的GCM代码并不是理想的做法。这是我的应用程序中的基本代码,现在成功地从后端发送发送到同步并在状态栏中显示通知。

public class ZeppaGCMReceiver extends WakefulBroadcastReceiver {

    final private static String TAG = "GCMIntentService";
    private static String registrationId = null;

    public static void register(final ZeppaApplication application) {

        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(application
                .getApplicationContext());
        try {

            registrationId = gcm.register(Constants.PROJECT_NUMBER);
            Log.d(TAG, "gcm.register( " + registrationId + " )");

            ZeppaUser currentUser = ZeppaUserSingleton.getInstance().getUser();
            if (currentUser.getDevices() == null
                    || !currentUser.getDevices().contains(registrationId)) {
                new AsyncTask<Void, Void, Void>() {

                    @Override
                    protected Void doInBackground(Void... params) {
                        Zeppauserendpoint.Builder endpointBuilder = new Zeppauserendpoint.Builder(
                                AndroidHttp.newCompatibleTransport(),
                                new JacksonFactory(),
                                application.getGoogleAccountCredential());
                        endpointBuilder = CloudEndpointUtils
                                .updateBuilder(endpointBuilder);

                        Zeppauserendpoint userEndpoint = endpointBuilder
                                .build();
                        try {
                            RegisterUserDevice registerTask = userEndpoint
                                    .registerUserDevice(
                                            ZeppaUserSingleton.getInstance().getUserId(),
                                            registrationId);
                            registerTask.execute();

                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                        return null;
                    }

                }.execute();
            } else {
                Log.d(TAG, "Already Registered");
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void unregister(final ZeppaApplication application) {
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(application
                .getApplicationContext());
        // TODO: registration id in preferences and
        try {
            gcm.unregister();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    @Override
    public void onReceive(Context context, Intent intent) {

        Log.d(TAG, "received message ping");

        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
        String messageType = gcm.getMessageType(intent);

        Log.d(TAG, "MessageType: " + messageType);

        if (messageType == null) {
            Log.d(TAG, "Message is null");
            return;
        } else if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
                .equals(messageType)) {
            Log.d(TAG, "Error!");
            return;
        } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
                .equals(messageType)) {
            Log.d(TAG, "Deleted");
            return;
        } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
                .equals(messageType)) {
            Log.d(TAG, "Message");
            handlePingInAsync(context);
        } else {
            Log.d(TAG, "WTF are you..? " + intent.toString());
        }

    }

    private void handlePingInAsync(Context context) {

        Context[] param = {context};
        new AsyncTask<Context, Void, Void>() {

            @Override
            protected Void doInBackground(Context... params) {
                Context context = params[0];
                GoogleAccountCredential credential = getCredential(context);
                if (credential == null) {
                    return null;
                }

                Zeppanotificationendpoint.Builder endpointBuilder = new Zeppanotificationendpoint.Builder(
                        AndroidHttp.newCompatibleTransport(),
                        new JacksonFactory(), credential);
                endpointBuilder = CloudEndpointUtils
                        .updateBuilder(endpointBuilder);
                Zeppanotificationendpoint notificationEndpoint = endpointBuilder
                        .build();

                try {
                    SharedPreferences prefs = context.getSharedPreferences(
                            Constants.SHARED_PREFS, Context.MODE_PRIVATE);

                    Long userId = prefs.getLong(Constants.USER_ID, -1);
                    if (userId > 0) {
                        GetUnseenNotifications getUnseenNotifications = notificationEndpoint
                                .getUnseenNotifications(userId);
                        CollectionResponseZeppaNotification collectionResponse = getUnseenNotifications
                                .execute();
                        if (collectionResponse == null
                                || collectionResponse.getItems() == null) {
                        } else {

                            List<ZeppaNotification> notifications = collectionResponse
                                    .getItems();
                            sendNotificationsForResult(notifications,
                                    context);

                            try {
                                NotificationSingleton.getInstance()
                                        .addAllNotifcations(notifications);
                            } catch (NullPointerException ex) {
                                ex.printStackTrace();
                            }
                        }

                    } else {
                        Log.d(TAG, "No Set userId");
                    }
                } catch (IOException ioEx) {
                    ioEx.printStackTrace();
                }
                return null;

            }

        }.execute(param);

    }

    private GoogleAccountCredential getCredential(Context context) {
        GoogleAccountCredential credential = ((ZeppaApplication) context.getApplicationContext())
                .getGoogleAccountCredential();
        if (credential == null) {
            SharedPreferences prefs = context.getSharedPreferences(
                    Constants.SHARED_PREFS, Context.MODE_PRIVATE);
            String email = prefs.getString(Constants.EMAIL_ADDRESS, null);
            if (email != null && !email.isEmpty() && Constants.IS_CONNECTED) {
                credential = GoogleAccountCredential.usingAudience(context,
                        Constants.APP_ENGINE_AUDIENCE_CODE);
                credential.setSelectedAccountName(email);
                return credential;
            }

            return null;
        } else {
            return credential;
        }
    }

    @SuppressLint("NewApi")
    @SuppressWarnings("deprecation")
    private void sendNotificationsForResult(List<ZeppaNotification> resultList,
                                            Context context) {

        Log.d(TAG, "trying to send Notifications for result");
        Notification.Builder notifBuilder = new Notification.Builder(context);

        if (resultList.size() > 1) {
            notifBuilder.setContentTitle(resultList.size()
                    + " new notifications");

            StringBuilder stringBuilder = new StringBuilder();
            for (ZeppaNotification notification : resultList) {
                stringBuilder.append(notification.getExtraMessage()).append(
                        '\n');
            }

            notifBuilder.setContentText(stringBuilder.toString());

            Intent intent = new Intent(context, MainActivity.class);
            intent.putExtra(Constants.INTENT_NOTIFICATIONS, true);
            PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
                    intent, 0);
            notifBuilder.setContentIntent(pendingIntent);
        } else {
            ZeppaNotification notification = resultList.get(0);
            manageSingleNotification(context, notification, notifBuilder);
            notifBuilder.setContentText(notification.getExtraMessage());
        }

        notifBuilder.setLights(Color.CYAN, 750, 3000);
        notifBuilder.setAutoCancel(true);
        notifBuilder.setSmallIcon(R.drawable.notif_ic_zeppa);
        Notification notification = null;

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
            notifBuilder.setPriority(Notification.PRIORITY_DEFAULT);
            notification = notifBuilder.build();
        } else {
            notification = notifBuilder.getNotification();
        }
        NotificationManager notificationManager = (NotificationManager) context
                .getSystemService(Context.NOTIFICATION_SERVICE);

        Log.d(TAG, "Notification Should Post");
        notificationManager.notify(0, notification);

    }

    private void manageSingleNotification(Context context,
                                          ZeppaNotification notification, Notification.Builder builder) {

        Intent intent = null;
        switch (notification.getNotificationOrdinal()) {
            case 0:
                builder.setContentTitle("New Friend Request");
                intent = new Intent(context, NewFriendsActivity.class);
                break;
            case 1:
                builder.setContentTitle("New Connection");
                intent = new Intent(context, UserActivity.class);
                intent.putExtra(Constants.INTENT_ZEPPA_USER_ID,
                        notification.getFromUserId());
                break;

            case 2:
                builder.setContentTitle("Event Recommendation");
                intent = new Intent(context, EventViewActivity.class);
                intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
                        notification.getEventId());
                break;

            case 3:
                builder.setContentTitle("New Invite");
                intent = new Intent(context, EventViewActivity.class);
                intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
                        notification.getEventId());
                break;

            case 4:
                builder.setContentTitle("Event Comment");
                intent = new Intent(context, EventViewActivity.class);
                intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
                        notification.getEventId());
                break;

            case 5:
                builder.setContentTitle("Event Canceled");
                intent = new Intent(context, MainActivity.class);
                intent.putExtra(Constants.INTENT_NOTIFICATIONS, false);
                break;

            case 6:
                builder.setContentTitle("Event Updated");
                intent = new Intent(context, EventViewActivity.class);
                intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
                        notification.getEventId());
                break;

            case 7:
                builder.setContentTitle("Friend Joined Event");
                intent = new Intent(context, EventViewActivity.class);
                intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
                        notification.getEventId());
                break;

            case 8:
                builder.setContentTitle("Friend Left Event");
                intent = new Intent(context, EventViewActivity.class);
                intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
                        notification.getEventId());
                break;

            case 9:
                builder.setContentTitle("Let's Find a Time?");
                break;

            case 10:
                builder.setContentTitle("Time Found!");
                break;

            case 11:
                builder.setContentTitle("Event Reposted");
                intent = new Intent(context, EventViewActivity.class);
                intent.putExtra(Constants.INTENT_ZEPPA_EVENT_ID,
                        notification.getEventId());
                break;

            default: // this shouldnt happen
                builder.setContentTitle("New Zeppa Notification");
                intent = new Intent(context, MainActivity.class);
                intent.putExtra(Constants.INTENT_NOTIFICATIONS, false);
                break;
        }

        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
                intent, 0);

        builder.setContentIntent(pendingIntent);
    }
}

然后我的Manifest需要:

<permission
    android:name="package.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />

<uses-permission android:name="package.permission.C2D_MESSAGE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<receiver
        android:name="package.ZeppaGCMReceiver"
        android:exported="true"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />

            <category android:name="package.GCMIntentService" />
        </intent-filter>
    </receiver>

    <service
        android:name="package.ZeppaGCMService"
        android:enabled="true" />

然后,最后,从我的端点类,当某些事情输入数据库时​​,我确定应该通知哪些用户,并解雇了这个方法:

注意:getDevices只返回android设备IDS。我摆脱了DeviceInfo类,它似乎没有用,但这应该是处理这个的不正确方法。 iOS的处理方式不同,我相信你知道。如果我改变这个/如果人们想要看到iOS实现,将会更新。

public void sendNotificationPingToUsers(
        @Named("userIds") List<Long> userIds,
        ZeppaNotification notification) {

    Sender sender = new Sender(Constants.SENDER_ID);

    PersistenceManager mgr = getPersistenceManager();

    try {
        List<String> allDevices = new ArrayList<String>();

        for (int i = 0; i < userIds.size(); i++) {
            long userId = userIds.get(i);

            ZeppaUser zeppaUser = mgr
                    .getObjectById(ZeppaUser.class, userId);

            if (zeppaUser != null) {
                ZeppaNotification specificNotification = new ZeppaNotification();
                specificNotification.setToUserId(userId);
                specificNotification.setFromUserId(notification
                        .getFromUserId());
                specificNotification.setEventId(notification.getEventId());
                specificNotification.setExtraMessage(notification
                        .getExtraMessage());
                specificNotification.setNotificationType(notification
                        .getType());

                mgr.makePersistent(specificNotification);

                allDevices.addAll(zeppaUser.getDevices());

            }

        }
        if (!allDevices.isEmpty()) {

            Message msg = new Message.Builder().collapseKey("sendToSync")
                    .build();

            MulticastResult result = sender.send(msg, allDevices, 500);
            result.getTotal();

        }

    } catch (IOException ex) {
        ex.printStackTrace();
    } finally {
        mgr.close();
    }

}