4320


プッシュ通知実装を行っているのですが、サーバからのデータを受け取る段階でクラッシュしてしまいます。 環境はEclipseでgoogle play
service libはプロジェクトを作ってimportし、ライブラリとして追加。 suport v4 はandroid toolsからadd
support libraryして追加しました。

エラー：

[code]

    FATAL EXCEPTION: main
    java.lang.RuntimeException: Unable to instantiate receiver org.techbooster.gcmsample.GCMBroadcastReceiver: java.lang.ClassNotFoundException: Didn't find class "org.techbooster.gcmsample.GCMBroadcastReceiver" on path: /data/app/org.techbooster.gcmsample-1.apk
        at android.app.ActivityThread.handleReceiver(ActivityThread.java:2371)
        at android.app.ActivityThread.access$1500(ActivityThread.java:149)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1322)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:213)
        at android.app.ActivityThread.main(ActivityThread.java:5092)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:564)
        at dalvik.system.NativeStart.main(Native Method)
    Caused by: java.lang.ClassNotFoundException: Didn't find class "org.techbooster.gcmsample.GCMBroadcastReceiver" on path: /data/app/org.techbooster.gcmsample-1.apk
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:65)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
        at android.app.ActivityThread.handleReceiver(ActivityThread.java:2366)
        ... 10 more
    
[/code]

アクティビティ

[code]

    package org.techbooster.gcmsample;
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    
    import com.google.android.gms.common.ConnectionResult;
    import com.google.android.gms.common.GooglePlayServicesUtil;
    import com.google.android.gms.gcm.GoogleCloudMessaging;
    
    import org.techbooster.gcmsample.CommonUtilities;
    import org.techbooster.gcmsample.*;
    
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.content.pm.PackageInfo;
    import android.content.pm.PackageManager.NameNotFoundException;
    import android.util.Log;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    public class MainActivity extends Activity implements OnClickListener{
    
        private static final String TAG = "TechBoosterSample";
    
        public static final String EXTRA_MESSAGE = "message";
        public static final String PROPERTY_REG_ID = "registration_id";
        private static final String PROPERTY_APP_VERSION = "appVersion";
        private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
    
        GoogleCloudMessaging gcm;
        String regid;
        Context context;
    
        /**
         * サーバー通信用AsyncTask
         */
        AsyncTask<Void, Void, Void> mRegisterTask;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button btnRegist = (Button) findViewById(R.id.btn_regist);
            btnRegist.setOnClickListener(this);
            Button btnUnregist = (Button) findViewById(R.id.btn_unregist);
            btnUnregist.setOnClickListener(this);
    
            context = getApplicationContext();
    
            // デバイスにPlayサービスAPKが入っているか検証する
            if (checkPlayServices()) {
                gcm = GoogleCloudMessaging.getInstance(context);
                regid = getRegistrationId(context);
            } else {
                Log.i(TAG, "Google Play Services APKが見つかりません");
            }
        }
    
        /*
         * PlayサービスのAPKチェック
         */
        private boolean checkPlayServices() {
            int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
            if (resultCode != ConnectionResult.SUCCESS) {
                if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                    GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                            PLAY_SERVICES_RESOLUTION_REQUEST).show();
                } else {
                    Log.i(TAG, "Playサービスがサポートされていない端末です");
                    finish();
                }
                return false;
            }
            return true;
        }
    
        /*
         * レジストレーションIDの取得
         */   
        private String getRegistrationId(Context context) {
            final SharedPreferences prefs = getGCMPreferences(context);
            String registrationId = prefs.getString(PROPERTY_REG_ID, "");
    
            if (regid == null) return "";
            // プリファレンスに格納されていない場合は空で返却
            if (regid.equals("")) {
                Log.i(TAG, "レジストレーションIDが見つかりません");
                return "";
            }
            // アプリケーションがバージョンアップされていた場合、レジストレーションIDを必ずクリアしないといけません
            // すでにレジストレーションIDが存在していた場合、再生成は行いません。
            int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
            int currentVersion = getAppVersion(context);
            if (registeredVersion != currentVersion) {
                Log.i(TAG, "アプリケーションバージョンが変更されています");
                return "";
            }
            return registrationId;
        }
    
        /*
         * アプリケーションバージョン情報を取得する
         */
        private static int getAppVersion(Context context) {
            try {
                PackageInfo packageInfo = context.getPackageManager()
                        .getPackageInfo(context.getPackageName(), 0);
                return packageInfo.versionCode;
            } catch (NameNotFoundException e) {
                throw new RuntimeException("パッケージ名が見つかりません : " + e);
            }
        }
    
        /*
         * SharedPreferencesを取得
         */
        private SharedPreferences getGCMPreferences(Context context) {
            return getSharedPreferences(MainActivity.class.getSimpleName(),
                    Context.MODE_PRIVATE);
        }
    
        /*
         * レジストレーションIDの保存
         */
        private void storeRegistrationId(Context context, String regId) {
            final SharedPreferences prefs = getGCMPreferences(context);
            int appVersion = getAppVersion(context);
            Log.i(TAG, "レジストレーションIDを登録。登録時のアプリケーションバージョン: " + appVersion);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putString(PROPERTY_REG_ID, regId);
            editor.putInt(PROPERTY_APP_VERSION, appVersion);
            editor.commit();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            checkPlayServices();
        }
    
        @Override
        protected void onDestroy() {
            if (mRegisterTask != null) {
                mRegisterTask.cancel(true);
            }
            gcm.close();
            super.onDestroy();
        }
    
        @Override
        public void onClick(View v) {
            if(v.getId() == R.id.btn_regist){
                if (regid.equals("")) {
                    // GCM登録用AsyncTaskの実行
                    mRegisterTask = new AsyncTask<Void, Void, Void>() {
                        @Override
                        protected Void doInBackground(Void... params) {
                            if (gcm == null) {
                                // インスタンスがなければ取得する
                                gcm = GoogleCloudMessaging.getInstance(context);
                            }
                            try {
                                // GCMサーバーへ登録する
                                regid = gcm.register(CommonUtilities.SENDER_ID);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            // レジストレーションIDを自分のサーバーへ送信する
                            // レジストレーションIDをつかえば、アプリケーションにGCMメッセージを送信できるようになります
                            Log.i(TAG,"送信対象のレジストレーションID: " + regid);
                            register(regid);
    
                            // レジストレーションIDを端末に保存
                            storeRegistrationId(context, regid);
                            return null;
                        }
    
                        @Override
                        protected void onPostExecute(Void result) {
                            mRegisterTask = null;
                        }
                    };
                    mRegisterTask.execute(null, null, null);
                }
            }else if(v.getId() == R.id.btn_unregist){
                //GCMサーバーから登録を解除するAsyncTaskの実行
                mRegisterTask = new AsyncTask<Void, Void, Void>() {
                    @Override
                    protected Void doInBackground(Void... params) {
                        if (gcm == null) {
                            // インスタンスがなければ取得する
                            gcm = GoogleCloudMessaging.getInstance(context);
                        }
                        try {
                            // GCMサーバーの登録を解除する
                            gcm.unregister();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        // レジストレーションIDを自分のサーバーでも削除する
                        unregister(regid);
    
                        return null;
                    }
    
                    @Override
                    protected void onPostExecute(Void result) {
                        mRegisterTask = null;
                    }
    
                };
                mRegisterTask.execute(null, null, null);
            }
        }
    
        /*
         * 
         */
        public static boolean register(String regId) {
    
            String serverUrl = CommonUtilities.SERVER_URL + "/register";
            Map<String, String> params = new HashMap<String, String>();
            params.put("key", regId);
            try {
                post(serverUrl, params);
                return true;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }
    
        public static void unregister(String regId) {
    
            String serverUrl = CommonUtilities.SERVER_URL + "/unregister";
            Map<String, String> params = new HashMap<String, String>();
            params.put("key", regId);
            try {
                post(serverUrl, params);
            } catch (IOException e) {
            }
        }
    
        public static void post(String endpoint, Map<String, String> params)
                throws IOException {
            URL url;
            try {
                url = new URL(endpoint);
            } catch (MalformedURLException e) {
                throw new IllegalArgumentException("invalid url: " + endpoint);
            }
            StringBuilder bodyBuilder = new StringBuilder();
            Iterator<Entry<String, String>> iterator = params.entrySet().iterator();
            // POSTするパラメータ
            while (iterator.hasNext()) {
                Entry<String, String> param = iterator.next();
                bodyBuilder.append(param.getKey()).append('=')
                .append(param.getValue());
                if (iterator.hasNext()) {
                    bodyBuilder.append('&');
                }
            }
            String body = bodyBuilder.toString();
            byte[] bytes = body.getBytes();
            HttpURLConnection conn = null;
            try {
                conn = (HttpURLConnection) url.openConnection();
                conn.setDoOutput(true);
                conn.setUseCaches(false);
                conn.setFixedLengthStreamingMode(bytes.length);
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Content-Type",
                        "application/x-www-form-urlencoded;charset=UTF-8");
                // ポスト送信
                OutputStream out = conn.getOutputStream();
                out.write(bytes);
                out.close();
                // サーバーレスポンス受信
                int status = conn.getResponseCode();
                if (status != 200) {
                    throw new IOException("Post failed with error code " + status);
                }
            } finally {
                if (conn != null) {
                    conn.disconnect();
                }
            }
        }
    }
    
[/code]

レシーバクラス

[code]

    package org.techbooster.gcmsample;
    
    import com.google.android.gms.gcm.GoogleCloudMessaging;
    
    import android.app.Notification;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.content.res.Resources;
    import android.media.RingtoneManager;
    import android.net.Uri;
    import android.os.Bundle;
    import android.support.v4.content.WakefulBroadcastReceiver;
    import android.util.Log;
    
    public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
        private static final String TAG = "gcm debug";
    
        @Override
        public void onReceive(Context context, Intent intent) {
            // 送られてきたデータを受け取る
            GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
            String messageType = gcm.getMessageType(intent);
    
            // 送られてきたデータのメッセージ
            Bundle extras = intent.getExtras();
            String mess = extras.toString();
    
            if (!extras.isEmpty()) {
                // エラー
                if (messageType
                        .equals(GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR)) {
                    Log.d(TAG, "MESSAGE_TYPE_SEND_ERROR：" + mess);
                }
                // サーバーでメッセージ削除
                else if (messageType
                        .equals(GoogleCloudMessaging.MESSAGE_TYPE_DELETED)) {
                    Log.d(TAG, "MESSAGE_TYPE_DELETED：" + mess);
                }
                // 正常に受信
                else if (messageType
                        .equals(GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE)) {
                    Resources res = context.getResources();
    
                    Notification n = new Notification(); // Notificationの生成
                    n.icon = R.drawable.ic_launcher; // アイコンの設定
    
                    // 通知されたときに通知バーに表示される文章
                    n.tickerText = mess + "(short)"; // メッセージの設定
                    n.flags = Notification.FLAG_AUTO_CANCEL; // 通知を選択した時に自動的に通知が消えるための設定
    
                    // 通常の着信音を選択する
                    Uri uri = RingtoneManager
                            .getDefaultUri(RingtoneManager.TYPE_ALARM); // アラーム音
                    n.sound = uri; // サウンド
    
                    Intent i = new Intent(context, MainActivity.class);
                    i.putExtra("MESS", mess);
    
                    PendingIntent pi = PendingIntent.getActivity(context, 0, i,
                            PendingIntent.FLAG_UPDATE_CURRENT);
                    // 上から通知バーを下してきたときに表示される文章をセット
                    n.setLatestEventInfo(context, res.getString(R.string.app_name),
                            mess + "(long)", pi);
    
                    long[] vibrate_ptn = { 0, 100, 300, 1000 }; // 独自バイブレーションパターン
                    n.vibrate = vibrate_ptn; // 独自バイブレーションパターンを設定
    
                    n.defaults |= Notification.DEFAULT_LIGHTS; // デフォルトLED点滅パターンを設定
    
                    // NotificationManagerのインスタンス取得
                    NotificationManager nm = (NotificationManager) context
                            .getSystemService(Context.NOTIFICATION_SERVICE);
                    nm.notify(1, n); // 設定したNotificationを通知する
                }
            }
        }
    }
    
[/code]

サービスクラス

[code]

    package org.techbooster.gcmsample;
    
    import com.google.android.gms.gcm.GoogleCloudMessaging;
    
    import android.app.IntentService;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.SystemClock;
    import android.support.v4.app.NotificationCompat;
    import android.util.Log;
    
    public class GcmIntentService extends IntentService {
        private static final String TAG = "TechBoosterSample";
        public static final int NOTIFICATION_ID = 1;
        private NotificationManager mNotificationManager;
        NotificationCompat.Builder builder;
    
        public GcmIntentService() {
            super("GcmIntentService");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            Bundle extras = intent.getExtras();
            GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
            // The getMessageType() intent parameter must be the intent you received
            // in your BroadcastReceiver.
            String messageType = gcm.getMessageType(intent);
    
            if (!extras.isEmpty()) {  // has effect of unparcelling Bundle
                /*
                 * Filter messages based on message type. Since it is likely that GCM
                 * will be extended in the future with new message types, just ignore
                 * any message types you're not interested in, or that you don't
                 * recognize.
                 */
                if (GoogleCloudMessaging.
                        MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
                    sendNotification("Send error: " + extras.toString());
                } else if (GoogleCloudMessaging.
                        MESSAGE_TYPE_DELETED.equals(messageType)) {
                    sendNotification("Deleted messages on server: " +
                            extras.toString());
                    // If it's a regular GCM message, do some work.
                } else if (GoogleCloudMessaging.
                        MESSAGE_TYPE_MESSAGE.equals(messageType)) {
                    // This loop represents the service doing some work.
                    for (int i=0; i<5; i++) {
                        Log.i(TAG, "Working... " + (i+1)
                                + "/5 @ " + SystemClock.elapsedRealtime());
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                        }
                    }
                    Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
                    // Post notification of received message.
                    sendNotification("Received: " + extras.toString());
                    Log.i(TAG, "Received: " + extras.toString());
                }
            }
            // Release the wake lock provided by the WakefulBroadcastReceiver.
            org.techbooster.gcmsample.GcmBroadcastReceiver.completeWakefulIntent(intent);
        }
    
        // Put the message into a notification and post it.
        // This is just one simple example of what you might choose to do with
        // a GCM message.
        private void sendNotification(String msg) {
            mNotificationManager = (NotificationManager)
                    this.getSystemService(Context.NOTIFICATION_SERVICE);
    
            PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                    new Intent(this, MainActivity.class), 0);
    
            NotificationCompat.Builder mBuilder =
                    new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.ic_launcher)
            .setContentTitle("GCM Notification")
            .setStyle(new NotificationCompat.BigTextStyle()
            .bigText(msg))
            .setContentText(msg);
    
            mBuilder.setContentIntent(contentIntent);
            mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
        }
    }   
    
[/code]

マニュフェスト

[code]

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="org.techbooster.gcmsample"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="9"
            android:targetSdkVersion="17" />
    
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.GET_ACCOUNTS" />
        <uses-permission android:name="android.permission.READ_CONTACTS"/>
        <uses-permission android:name="android.permission.WAKE_LOCK" />
        <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    
        <permission
            android:name="org.techbooster.gcmsample.permission.C2D_MESSAGE"
            android:protectionLevel="signature" />
    
        <uses-permission android:name="org.techbooster.gcmsample.permission.C2D_MESSAGE" />
    
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <meta-data
                android:name="com.google.android.gms.version"
                android:value="@integer/google_play_services_version" />
    
            <activity
                android:name="org.techbooster.gcmsample.MainActivity"
                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="org.techbooster.gcmsample.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="org.techbooster.gcmsample" />
                </intent-filter>
            </receiver>
    
            <service android:name="org.techbooster.gcmsample.GCMIntentService" />
        </application>
    
    </manifest>
    
[/code]


CC BY-SA 3.0
2015-01-08T07:22:19.520
4279
2015-01-09T04:31:49.357
525
question
android gcm
androidのプッシュ通知実装：ClassNotFoundException


単純に名称が間違っていました。

誤り

[code]

    android:name="org.techbooster.gcmsample.GCMIntentService"
    android:name="org.techbooster.gcmsample.GCMBroadcastReceiver"
    
[/code]

正しい

[code]

    android:name="org.techbooster.gcmsample.GcmIntentService"
    android:name="org.techbooster.gcmsample.GcmBroadcastReceiver"
    
[/code]


CC BY-SA 3.0
2015-01-09T04:31:49.357
4320
2015-01-09T04:31:49.357
525
4279
answer