Android2.3.5から4.0.3にアップデートしたらPUSH通知が動かねえ! | 超キレやすいプログラマのブログ

超キレやすいプログラマのブログ

キレてキレてキレまくる

俺の使っているスマホはARROWS Z ISW11Fだ。
ネットじゃホッカイロとか言われてるらしいが、雪国の俺には全然気にならない。むしろありがたい。

嫁のスマホも同機種の色違いなんだが、嫁の方は内部ストレージが怪しかったり、やたらと電源消費が激しかったり(嫁は機械に疎いので全然アプリとか入れてないんだが)と、当たり外れの激しい機種でもあるようだ。

しかし、OSを4.0.3にアップデートすれば、ホッカイロ機能が軽減されるという情報をネットで見かけた。
熱量下がるってことは、電源消費も抑えられるんじゃない?
ということで、嫁のやつだけOSアップデートかけてみた。



さて、前置きが長かったがここからが本題だ。
アップデートを終えた嫁のスマホで、俺の作っていたPUSH通信のテストアプリを動かしてみたところ、全然動かない。。。
当然、2.3.5のままの俺の携帯では動く。

本家サイトを見て、AndroidManifest.xmlに1つパーミッションが抜けていた(&ltuses-permission android:name="android.permission.GET_ACCOUNTS" />)ので追加したけど、やっぱ駄目。

5時間位、試して、調べて、試して、調べて、試して、調べて、試して、調べて、試して、調べて、挫折して、キレた。
このFuckin' crazyが!!
PUSH通信ぐらいチェックボックス1つオンにすれば動くようにしとけよ!!
バージョンの違いなんてそっちで回収しろ!!


ソースは以下の通り。



画面イメージ
$超キレやすいプログラマのブログ


AndroidManifest.xml


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

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

<uses-permission android:name="android.permission.INTERNET" />

<permission
android:name="com.example.pushtest.permission.C2D_MESSAGE"
android:protectionLevel="signature" />

<uses-permission android:name="com.example.pushtest.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" >
</uses-permission>

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.pushtest.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="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.example.pushtest" />
</intent-filter>
</receiver>

<service android:name=".GCMIntentService" android:process=":remote" >
</service>
</application>

</manifest>




activity_main.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<Button
android:id="@+id/btnRegist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="この端末を登録し、一意のIDを取得する。(既に登録済みの場合はIDを表示する。)" />

<TextView android:id="@+id/txtMessage"
android:layout_below="@+id/btnRegist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />

</RelativeLayout>




MainActivity.java


package com.example.pushtest;

import org.apache.http.message.BasicNameValuePair;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gcm.GCMRegistrar;

public class MainActivity extends Activity {

private static final String SENDER_ID = "9999999999999";

private static final String SERVER_URL = "http://レンタルサーバ/push_regist.php";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

((Button) findViewById(R.id.btnRegist))
.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {

Context context = getApplicationContext();

try {
// デバイスがGCMに対応しているかどうかをチェック
GCMRegistrar.checkDevice(context);
// GCMを利用するうえでマニフェストが適切に書かれているかどうかをチェック
GCMRegistrar.checkManifest(context);
} catch (UnsupportedOperationException e) {
e.printStackTrace();
Toast.makeText(
context,
"stating error UnsupportedOperationException",
Toast.LENGTH_SHORT).show();

} catch (IllegalStateException e) {
e.printStackTrace();
Toast.makeText(context,
"stating error IllegalStateException",
Toast.LENGTH_SHORT).show();
}
// RegistrationIDを取得
final String regId = GCMRegistrar
.getRegistrationId(context);

// GCMサーバ(Googleが管理するサーバ)にサインアップしていない場合
if (regId == null || regId.equals("")) {
// 取得したSender IDを使ってGCMサーバにサインアップする
GCMRegistrar.register(context, SENDER_ID);
} else {
// GCMサーバ(Googleが管理するサーバ)にサインアップしている場合、メッセージを出力する
((TextView) findViewById(R.id.txtMessage))
.setText("id:\n" + regId);
// RegistrationIDを所有サーバに登録する
doPost(SERVER_URL + "?id=" + regId);
}
}

});
}

private void doPost(String url, BasicNameValuePair... params) {

// 非同期タスクを実行
if (params == null || params.length <= 0) {
new RequestString(url, new RequestStringHandler() {
@Override
public void onPostCompleted(String response) {
}
}).execute();
} else {
new RequestString(url, new RequestStringHandler() {
@Override
public void onPostCompleted(String response) {
}
}, params).execute();
}
}
}




GCMIntentService.java


package com.example.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 com.google.android.gcm.GCMBaseIntentService;

public class GCMIntentService extends GCMBaseIntentService {

public GCMIntentService() {
super("SENDER_ID");
}

@Override
public void onCreate() {
super.onCreate();
}

@Override
public void onRegistered(Context context, String registrationId) {
Log.w("registration id:", registrationId);
}

@Override
protected void onUnregistered(Context context, String registrationId) {
Log.w("C2DM Unregistered id:", registrationId);
}

@Override
public void onError(Context context, String errorId) {
Log.e("err:", errorId);
}

@Override
protected void onMessage(Context context, Intent intent) {

String message = intent.getStringExtra("message");
Log.w("message:", message);

NotificationManager notificationManager = (NotificationManager) context
.getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher,
message, System.currentTimeMillis());
notification.flags = Notification.FLAG_AUTO_CANCEL;
Intent remoteIntent = new Intent(context.getApplicationContext(),
MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(
context.getApplicationContext(), 0, remoteIntent, 0);
notification.setLatestEventInfo(context.getApplicationContext(),
context.getString(R.string.app_name), message, contentIntent);
notificationManager.notify(R.string.app_name, notification);
}
}





上記以外にHTTP通信を行う為のクラスが2つ(RequestString.java、RequestStringHandler.java)あるが、それは今回の趣旨とは関係ないので割愛。
(doPostのif文とか超カッコ悪いけど、愛嬌だ。)


アプリの動きはシンプルで、画面のボタンをクリックすると

①PUSH通信可能か判断。
②GCMRegistrar.getRegistrationId()で、端末を一意に識別するIDの取得を試みる。
③ID取得できた場合は画面に表示。取得できなかった場合はGCMにIDを取得しにいく。
④ID取得できた場合は、レンタルサーバにIDを登録する。

という動きになっている。

2.3.5でこのプログラムを動かすと、ボタンをポチポチと押していると、じきにIDの取得に成功し、画面にIDが表示される。(大概は2回目のクリックでID表示される)
しかし、4.0.3で動かしたところ、押せども押せどもIDは表示されない。
MainActivity.javaの

GCMRegistrar.getRegistrationId(context);

の戻り値が常に空文字になってしまうのである。

GCMIntentService.javaの
・onRegistered
・onUnregistered
・onError
・onMessage
にブレークポイントを張って実行してみたが、何度ボタンを押してもプレークしなかった。

また、LogCatの内容もチラチラ見てたが、IDが帰ってきた形跡は発見できず。

なんか、GCMサーバにハブられてる気がするわ。
でもそれならエラーって返してくれないもんかね。。。
プログラムやパーミッションの関連が4.0.xから変ったとかいう可能性も否定できん。
単純にソースが間違っているという可能性も否定できん。


もうわけわからん。
解決したらまた書きますわ。