GCM Android App致命异常

时间:2014-04-30 23:34:38

标签: java android push google-cloud-messaging

我一直在努力了解Google云端消息传递如何在Android应用中运行,特别是多播消息传递,因此我找到了一个包含源代码的教程。不幸的是,我可以让程序无错误地编译,但是当它运行时,我会得到致命的异常。谁知道出了什么问题?

以下是主要活动:

    package com.ganyo.pushtest;

    import android.app.Activity;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;

    import com.google.android.gcm.GCMRegistrar;

    import static com.ganyo.pushtest.Util.*;
    import static com.ganyo.pushtest.Util.TAG;

    public class PushMainActivity extends Activity {

      private TextView messageTextView;
      private Button sendButton;
      private AlertDialogManager alert = new AlertDialogManager();

      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // this is a hack to force AsyncTask to be initialized on main thread. Without this things
        // won't work correctly on older versions of Android (2.2, apilevel=8)
        try {
            Class.forName("android.os.AsyncTask");
        } catch (Exception ignored) {}

        GCMRegistrar.checkDevice(this);
        GCMRegistrar.checkManifest(this);

        initUI();

        AppServices.loginAndRegisterForPush(this);
      }

      private void initUI() {
        setContentView(R.layout.main);
        messageTextView = (TextView)findViewById(R.id.lblMessage);

        sendButton = (Button)findViewById(R.id.sendButton);
        sendButton.setOnClickListener(new View.OnClickListener() {
          public void onClick(View v) {
            AppServices.sendMyselfANotification(v.getContext());
          }
        });

        registerReceiver(notificationReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION));
      }

      /**
       * Receives push Notifications
       * */
      private final BroadcastReceiver notificationReceiver = new BroadcastReceiver() {

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

          // Waking up mobile if it is sleeping
          WakeLocker.acquire(getApplicationContext());

          /**
           * Take some action upon receiving a push notification here!
           **/
          String message = intent.getExtras().getString(EXTRA_MESSAGE);
          if (message == null) { message = "Empty Message"; }

          Log.i(TAG, message);
          messageTextView.append("\n" + message);

          alert.showAlertDialog(context, getString(R.string.gcm_alert_title), message);
          Toast.makeText(getApplicationContext(), getString(R.string.gcm_message, message), Toast.LENGTH_LONG).show();

          WakeLocker.release();
        }
      };

      // this will be called when the screen rotates instead of onCreate()
      // due to manifest setting, see: android:configChanges
      @Override
      public void onConfigurationChanged(Configuration newConfig)
      {
        super.onConfigurationChanged(newConfig);
        initUI();
      }

      @Override
      protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(notificationReceiver);
      }

    }

这是清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.ganyo.pushtest"
          android:versionCode="1"
          android:versionName="1.0">

    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16"/>

    <permission android:name="com.ganyo.pushtest.permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="com.ganyo.pushtest.permission.C2D_MESSAGE" />

    <!-- App receives GCM messages. -->
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

    <!-- GCM connects to Google Services. -->
    <uses-permission android:name="android.permission.INTERNET" />

    <!-- GCM requires a Google account. -->
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />

    <!-- Keeps the processor from sleeping when a message is received. -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.VIBRATE"/>

    <application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
        <activity android:name="com.ganyo.pushtest.PushMainActivity"
                  android:label="@string/app_name"
                  android:configChanges="keyboardHidden|orientation|screenSize">
            <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.ganyo.pushtest" />
            </intent-filter>
        </receiver>

        <service android:name="GCMIntentService" />

    </application>
</manifest>

这是Appservices:

package com.ganyo.pushtest;

import android.content.Context;

import android.util.Log;

import com.apigee.sdk.ApigeeClient;
import com.apigee.sdk.data.client.DataClient;
import com.apigee.sdk.data.client.callbacks.ApiResponseCallback;
import com.apigee.sdk.data.client.callbacks.DeviceRegistrationCallback;
import com.apigee.sdk.data.client.entities.Device;
import com.apigee.sdk.data.client.entities.Entity;
import com.apigee.sdk.data.client.response.ApiResponse;
import com.apigee.sdk.data.client.utils.JsonUtils;
import com.google.android.gcm.GCMRegistrar;

import com.apigee.sdk.data.client.push.GCMPayload;
import com.apigee.sdk.data.client.push.GCMDestination;

import java.util.HashMap;

import static com.ganyo.pushtest.Util.*;
import static com.ganyo.pushtest.Settings.*;

public final class AppServices {

  private static DataClient client;
  private static Device device;

  static synchronized DataClient getClient(Context context) {
    if (client == null) {
        if (ORG.equals("<<your org name here>>")) {
            Log.e(TAG, "ORG value has not been set.");
        } else {
            ApigeeClient apigeeClient = new ApigeeClient(ORG,APP,API_URL,context);
            client = apigeeClient.getDataClient();
        }
    }
    return client;
  }

  static void loginAndRegisterForPush(final Context context) {

    if ((USER != null) && (USER.length() > 0)) {
        DataClient dataClient = getClient(context);
        if (dataClient != null) {
            dataClient.authorizeAppUserAsync(USER, PASSWORD, new ApiResponseCallback() {

                @Override
                public void onResponse(ApiResponse apiResponse) {
                    Log.i(TAG, "login response: " + apiResponse);
                    registerPush(context);
                }

                @Override
                public void onException(Exception e) {
                    displayMessage(context, "Login Exception: " + e);
                    Log.i(TAG, "login exception: " + e);
                }
            });
        } else {
            Log.e(TAG,"Data client is null, did you set ORG value in Settings.java?");
        }
    } else {
      registerPush(context);
    }
  }

  static void registerPush(Context context) {

    final String regId = GCMRegistrar.getRegistrationId(context);

    if ("".equals(regId)) {
      GCMRegistrar.register(context, Settings.GCM_SENDER_ID);
    } else {
      if (GCMRegistrar.isRegisteredOnServer(context)) {
        Log.i(TAG, "Already registered with GCM");
      } else {
        AppServices.register(context, regId);
      }
    }
  }


  /**
   * Register this user/device pair on App Services.
   */
  static void register(final Context context, final String regId) {
    Log.i(TAG, "registering device: " + regId);

    DataClient dataClient = getClient(context);
    if (dataClient != null) {

        dataClient.registerDeviceForPushAsync(dataClient.getUniqueDeviceID(), NOTIFIER, regId, null, new DeviceRegistrationCallback() {

      @Override
      public void onResponse(Device device) {
        Log.i(TAG, "register response: " + device);
        AppServices.device = device;
        displayMessage(context, "Device registered as: " + regId);
        DataClient dataClient = getClient(context);

        if (dataClient != null) {
            // connect Device to current User - if there is one
            if (dataClient.getLoggedInUser() != null) {
                dataClient.connectEntitiesAsync("users", dataClient.getLoggedInUser().getUuid().toString(),
                                           "devices", device.getUuid().toString(),
                                           new ApiResponseCallback() {
                    @Override
                    public void onResponse(ApiResponse apiResponse) {
                        Log.i(TAG, "connect response: " + apiResponse);
                    }

                    @Override
                    public void onException(Exception e) {
                        displayMessage(context, "Connect Exception: " + e);
                        Log.i(TAG, "connect exception: " + e);
                    }
                });
            }
        } else {
            Log.e(TAG,"data client is null, did you set ORG value in Settings.java?");
        }
      }

      @Override
      public void onException(Exception e) {
        displayMessage(context, "Register Exception: " + e);
        Log.i(TAG, "register exception: " + e);
      }

      @Override
      public void onDeviceRegistration(Device device) { /* this won't ever be called */ }
    });
    } else {
        Log.e(TAG, "Data client is null, did you set ORG value in Settings.java?");
    }
  }

  static void sendMyselfANotification(final Context context) {
      if (device == null) {
          displayMessage(context, "Device not registered. ORG value set in Settings.java?");
      } else {
          DataClient dataClient = getClient(context);
          if (dataClient != null) {
              GCMDestination destination = GCMDestination.destinationSingleDevice(device.getUuid());
              GCMPayload payload = new GCMPayload();
              payload.setAlertText("Hi there!");

              dataClient.pushNotificationAsync(payload, destination, "google", new ApiResponseCallback() {

                  @Override
                  public void onResponse(ApiResponse apiResponse) {
                      Log.i(TAG, "send response: " + apiResponse);
                  }

                  @Override
                  public void onException(Exception e) {
                      displayMessage(context, "Send Exception: " + e);
                      Log.i(TAG, "send exception: " + e);
                  }
              });
          } else {
              Log.e(TAG, "data client is null, did you set ORG value in Settings.java?");
          }
      }
  }

  /**
   * Unregister this device within the server.
   */
  static void unregister(final Context context, final String regId) {
    Log.i(TAG, "unregistering device: " + regId);
    register(context, "");
  }
}

Gmcintentservices:

    package com.ganyo.pushtest;

    import android.app.Notification;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.util.Log;
    import android.support.v4.app.NotificationCompat;
    import android.support.v4.app.NotificationCompat.Builder;

    import com.google.android.gcm.GCMBaseIntentService;

    import static com.ganyo.pushtest.Settings.GCM_SENDER_ID;
    import static com.ganyo.pushtest.Util.displayMessage;

    public class GCMIntentService extends GCMBaseIntentService {

      public GCMIntentService() {
        super(GCM_SENDER_ID);
      }

      /**
       * Method called on device registered
       **/
      @Override
      protected void onRegistered(Context context, String registrationId) {
        Log.i(TAG, "Device registered: " + registrationId);
        displayMessage(context, getString(R.string.gcm_registered, registrationId));
        AppServices.register(context, registrationId);
      }

      /**
       * Method called on device unregistered
       * */
      @Override
      protected void onUnregistered(Context context, String registrationId) {
        Log.i(TAG, "Device unregistered");
        displayMessage(context, getString(R.string.gcm_unregistered, registrationId));
        AppServices.unregister(context, registrationId);
      }

      /**
       * Method called on receiving a new message
       * */
      @Override
      protected void onMessage(Context context, Intent intent) {
        String message = intent.getExtras().getString("data");
        Log.i(TAG, "Received message: " + message);

        displayMessage(context, message);
        generateNotification(context, message);
      }

      /**
       * Method called on receiving a deleted message
       * */
      @Override
      protected void onDeletedMessages(Context context, int total) {
        Log.i(TAG, "Received deleted messages notification");
        String message = getString(R.string.gcm_deleted, total);
        displayMessage(context, message);
        generateNotification(context, message);
      }

      /**
       * Method called on Error
       * */
      @Override
      public void onError(Context context, String errorId) {
        Log.i(TAG, "Received error: " + errorId);
        displayMessage(context, getString(R.string.gcm_error, errorId));
      }

      @Override
      protected boolean onRecoverableError(Context context, String errorId) {
        Log.i(TAG, "Received recoverable error: " + errorId);
        displayMessage(context, getString(R.string.gcm_recoverable_error, errorId));
        return super.onRecoverableError(context, errorId);
      }

      /**
       * Issues a Notification to inform the user that server has sent a message.
       */
      private static void generateNotification(Context context, String message) {
        int icon = R.drawable.ic_launcher;
        long when = System.currentTimeMillis();
        NotificationManager notificationManager = (NotificationManager)
            context.getSystemService(Context.NOTIFICATION_SERVICE);

        Intent notificationIntent = new Intent(context, PushMainActivity.class);
        // set intent so it does not start a new activity
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);

        Notification notification = new NotificationCompat.Builder(context)
            .setContentText(message)
            .setContentTitle(context.getString(R.string.app_name))
            .setSmallIcon(icon)
            .setWhen(when)
            .setContentIntent(intent)
            .build();

        notification.flags |= Notification.FLAG_AUTO_CANCEL;

        // Play default notification sound
        notification.defaults |= Notification.DEFAULT_SOUND;

        // Vibrate if vibrate is enabled
        notification.defaults |= Notification.DEFAULT_VIBRATE;
        notificationManager.notify(0, notification);
      }
    }

 Alertdialoguemanager:

package com.ganyo.pushtest;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;

public class AlertDialogManager {

  public void showAlertDialog(Context context, String title, String message) {

    AlertDialog alertDialog = new AlertDialog.Builder(context).create();
    alertDialog.setTitle(title);
    alertDialog.setMessage(message);

    alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
      public void onClick(DialogInterface dialog, int which) {
      }
    });

    alertDialog.show();
  }
} 

的Util:

package com.ganyo.pushtest;

import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.google.android.gcm.GCMRegistrar;

public final class Util {

  static final String TAG = "com.ganyo.pushtest";
  static final String DISPLAY_MESSAGE_ACTION = "com.ganyo.pushtest.DISPLAY_MESSAGE";
  static final String EXTRA_MESSAGE = "message";

  static void displayMessage(Context context, String message) {
    Intent intent = new Intent(DISPLAY_MESSAGE_ACTION);
    intent.putExtra(EXTRA_MESSAGE, message);
    context.sendBroadcast(intent);
  }

}

Wakelocker:

package com.ganyo.pushtest;

import android.content.Context;
import android.os.PowerManager;

public abstract class WakeLocker {
  private static PowerManager.WakeLock wakeLock;

  public static void acquire(Context context) {
    if (wakeLock != null) wakeLock.release();

    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    wakeLock = pm.newWakeLock(PowerManager.ON_AFTER_RELEASE |
        PowerManager.ACQUIRE_CAUSES_WAKEUP |
        PowerManager.ON_AFTER_RELEASE |
        PowerManager.SCREEN_DIM_WAKE_LOCK, "WakeLock");
    wakeLock.acquire();
  }

  public static void release() {
    if (wakeLock != null) wakeLock.release(); wakeLock = null;
  }
}

这是致命异常的logcat区域:

05-01 00:26:52.757: D/AndroidRuntime(166): Shutting down VM
05-01 00:26:52.777: D/jdwp(166): adbd disconnected
05-01 00:26:52.817: I/AndroidRuntime(166): NOTE: attach of thread 'Binder Thread #3' failed
05-01 00:26:53.050: I/ActivityThread(258): Publishing provider com.svox.pico.providers.SettingsProvider: com.svox.pico.providers.SettingsProvider
05-01 00:26:53.627: I/ActivityManager(58): Start proc com.ganyo.pushtest for activity com.ganyo.pushtest/.PushMainActivity: pid=267 uid=10036 gids={3003}
05-01 00:26:54.687: W/WindowManager(58): No window to dispatch pointer action 0
05-01 00:26:54.707: W/WindowManager(58): No window to dispatch pointer action 1
05-01 00:26:55.467: D/AndroidRuntime(267): Shutting down VM
05-01 00:26:55.467: W/dalvikvm(267): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
05-01 00:26:55.537: E/AndroidRuntime(267): FATAL EXCEPTION: main
05-01 00:26:55.537: E/AndroidRuntime(267): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.ganyo.pushtest/com.ganyo.pushtest.PushMainActivity}: java.lang.ClassNotFoundException: com.ganyo.pushtest.PushMainActivity in loader dalvik.system.PathClassLoader[/data/app/com.ganyo.pushtest-2.apk]
05-01 00:26:55.537: E/AndroidRuntime(267):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2585)
05-01 00:26:55.537: E/AndroidRuntime(267):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
05-01 00:26:55.537: E/AndroidRuntime(267):  at android.app.ActivityThread.access$2300(ActivityThread.java:125)
05-01 00:26:55.537: E/AndroidRuntime(267):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
05-01 00:26:55.537: E/AndroidRuntime(267):  at android.os.Handler.dispatchMessage(Handler.java:99)
05-01 00:26:55.537: E/AndroidRuntime(267):  at android.os.Looper.loop(Looper.java:123)
05-01 00:26:55.537: E/AndroidRuntime(267):  at android.app.ActivityThread.main(ActivityThread.java:4627)
05-01 00:26:55.537: E/AndroidRuntime(267):  at java.lang.reflect.Method.invokeNative(Native Method)
05-01 00:26:55.537: E/AndroidRuntime(267):  at java.lang.reflect.Method.invoke(Method.java:521)
05-01 00:26:55.537: E/AndroidRuntime(267):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
05-01 00:26:55.537: E/AndroidRuntime(267):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
05-01 00:26:55.537: E/AndroidRuntime(267):  at dalvik.system.NativeStart.main(Native Method)
05-01 00:26:55.537: E/AndroidRuntime(267): Caused by: java.lang.ClassNotFoundException: com.ganyo.pushtest.PushMainActivity in loader dalvik.system.PathClassLoader[/data/app/com.ganyo.pushtest-2.apk]
05-01 00:26:55.537: E/AndroidRuntime(267):  at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:243)
05-01 00:26:55.537: E/AndroidRuntime(267):  at java.lang.ClassLoader.loadClass(ClassLoader.java:573)
05-01 00:26:55.537: E/AndroidRuntime(267):  at java.lang.ClassLoader.loadClass(ClassLoader.java:532)
05-01 00:26:55.537: E/AndroidRuntime(267):  at android.app.Instrumentation.newActivity(Instrumentation.java:1021)
05-01 00:26:55.537: E/AndroidRuntime(267):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2577)
05-01 00:26:55.537: E/AndroidRuntime(267):  ... 11 more
05-01 00:26:55.617: W/ActivityManager(58):   Force finishing activity com.ganyo.pushtest/.PushMainActivity
05-01 00:26:56.499: W/ActivityManager(58): Activity pause timeout for HistoryRecord{460133f8 com.ganyo.pushtest/.PushMainActivity}
05-01 00:26:56.687: I/ARMAssembler(58): generated scanline__00000077:03515104_00000000_00000000 [ 33 ipp] (47 ins) at [0x3261a0:0x32625c] in 1336038 ns
05-01 00:26:56.777: I/ARMAssembler(58): generated scanline__00000177:03515104_00001001_00000000 [ 91 ipp] (114 ins) at [0x3265b8:0x326780] in 1506105 ns
05-01 00:26:57.337: I/ARMAssembler(58): generated scanline__00000077:03545404_00000004_00000000 [ 47 ipp] (67 ins) at [0x326788:0x326894] in 951792 ns
05-01 00:26:57.967: D/AndroidRuntime(271): >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<
05-01 00:26:58.009: D/AndroidRuntime(271): CheckJNI is ON
05-01 00:27:00.377: D/AndroidRuntime(271): --- registering native functions ---

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

原来是java文件夹中的所有.java文件。一旦我在src路径中重新编写它们,程序就能正常工作。