※ (6/11) コメント頂いたgetPendingIntentを修正
cocos2d-xでローカル通知を出したい
cocos2d-xでiOS/Androidのローカル通知(LocalNotification)を出すコードです。
iOSの場合
iOSの場合は、実装ファイルの拡張子を*.mmに変えるだけでObjective-Cを呼び出せるので簡単。
LocalNotification.h
#ifndef ___LocalNotificationSample__LocalNotification__
#define ___LocalNotificationSample__LocalNotification__
#include <string>
class LocalNotification {
public:
/**
* Show local notification
* @param message Message should be shown in notificatin
* @param interval Interval in seconds
* @param tag Tag to specify notification
*/
static void show(std::string message, int interval, int tag);
/**
* Cancel local notification specified by ID
* @param tag Tag of local notification
*/
static void cancel(int tag);
};
#endif /* defined(___LocalNotificationSample__LocalNotification__) */
LocalNotification_iOS.mm
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
#include "LocalNotification.h"
using namespace std;
void LocalNotification::show(std::string message, int interval, int tag)
{
// 通知を作成する
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = [[NSDate date] dateByAddingTimeInterval:interval];
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.alertBody = [NSString stringWithCString:message.c_str()
encoding:[NSString defaultCStringEncoding]];
notification.alertAction = @"Open";
notification.soundName = UILocalNotificationDefaultSoundName;
NSNumber* tag1 = [NSNumber numberWithInteger:tag];
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:tag1 forKey:@"ID"];
notification.userInfo = infoDict;
// 通知を登録する
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
[notification release];
}
void LocalNotification::cancel(int tag)
{
for(UILocalNotification *notification in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
if([[notification.userInfo objectForKey:@"ID"] integerValue] == tag) {
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
}
#endif // CC_TARGET_PLATFORM == CC_PLATFORM_IOS
Androidの場合
iOSとは違って、ちょっとめんどくさいです。
JavaでLocalNotificationを出すメソッドを定義して、JNI経由でC++から呼び出します。
Androidの通知UIのAPIはバージョンによって差分があるので、Support Library v4に入ってるNotificationCompatクラスを使用しましょう。
Cocos2dxActivity.java
package org.cocos2dx.cpp;
import java.util.Calendar;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.NativeActivity;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class Cocos2dxActivity extends NativeActivity{
private static final String TAG = Cocos2dxActivity.class.getSimpleName();
private static Activity sActivity;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
//For supports translucency
//1.change "attribs" in cocos\2d\platform\android\nativeactivity.cpp
/*const EGLint attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
//EGL_BLUE_SIZE, 5, -->delete
//EGL_GREEN_SIZE, 6, -->delete
//EGL_RED_SIZE, 5, -->delete
EGL_BUFFER_SIZE, 32, //-->new field
EGL_DEPTH_SIZE, 16,
EGL_STENCIL_SIZE, 8,
EGL_NONE
};*/
//2.Set the format of window
// getWindow().setFormat(PixelFormat.TRANSLUCENT);
// LocalNotification
sActivity = this;
}
public static void showLocalNotification(String message, int interval, int tag) {
Log.v(TAG, "showLocalNotification");
PendingIntent sender = getPendingIntent(message, tag);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, interval);
AlarmManager am = (AlarmManager)sActivity.getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), sender);
}
public static void cancelLocalNotification(int tag) {
Log.v(TAG, "cancelLocalNotification");
PendingIntent sender = getPendingIntent(null, tag);
AlarmManager am = (AlarmManager)sActivity.getSystemService(ALARM_SERVICE);
am.cancel(sender);
}
private static PendingIntent getPendingIntent(String message, int tag) {
Intent i = new Intent(sActivity.getApplicationContext(), LocalNotificationReceiver.class);
i.putExtra("notification_id", tag);
i.putExtra("message", message);
PendingIntent sender = PendingIntent.getBroadcast(sActivity, tag, i, PendingIntent.FLAG_UPDATE_CURRENT);
return sender;
}
}
LocalNotificationReceiver.java
package org.cocos2dx.cpp;
import com.MyCompany.AwesomeGame.R;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v4.app.NotificationCompat;
public class LocalNotificationReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int notificationId = intent.getIntExtra("notification_id", 0);
String message = intent.getStringExtra("message");
Intent intent2 = new Intent(context, Cocos2dxActivity.class);
intent2.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent2,
PendingIntent.FLAG_UPDATE_CURRENT);
Bitmap largeIcon = BitmapFactory.decodeResource(context.getResources(),
R.drawable.icon);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setContentTitle(context.getString(R.string.app_name));
builder.setContentText(message);
builder.setSmallIcon(R.drawable.icon);
builder.setLargeIcon(largeIcon);
builder.setTicker(message);
builder.setAutoCancel(true);
builder.setDefaults(Notification.DEFAULT_ALL);
builder.setContentIntent(pendingIntent);
NotificationManager manager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(notificationId, builder.build());
}
}
AndroidManifest.xmlに以下の1行を追加します。
AndroidManifest.xml
<!-- ローカル通知のレシーバー -->
<receiver android:name="org.cocos2dx.cpp.LocalNotificationReceiver" android:process=":remote" />
C++側の実装は以下です。iOS版とAPIを合わせています。
LocalNotification_Android.cpp
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "LocalNotification.h"
#include "platform/android/jni/JniHelper.h"
#include <jni.h>
using namespace std;
// Java class
// NativeActivityのパッケージ名・クラス名に合わせて修正してください
#define CLASS_NAME "org/cocos2dx/cpp/Cocos2dxActivity"
static bool getJNIStaticMethodInfo(cocos2d::JniMethodInfo &methodinfo,
const char *methodName,
const char *paramCode) {
return cocos2d::JniHelper::getStaticMethodInfo(methodinfo,
CLASS_NAME,
methodName,
paramCode);
}
void LocalNotification::show(std::string message, int interval, int tag)
{
cocos2d::JniMethodInfo methodInfo;
if (! getJNIStaticMethodInfo(methodInfo, "showLocalNotification", "(Ljava/lang/String;II)V")) {
return;
}
jstring stringArg = methodInfo.env->NewStringUTF(message.c_str());
methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, stringArg, interval, tag);
methodInfo.env->DeleteLocalRef(stringArg);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
}
void LocalNotification::cancel(int tag)
{
cocos2d::JniMethodInfo methodInfo;
if (! getJNIStaticMethodInfo(methodInfo, "cancelLocalNotification", "(I)V")) {
return;
}
methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, tag);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
}
#endif // CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
使い方
こんな感じで呼び出します。
// 10sec後に表示
LocalNotification::show("Hello Notification!", 10, 1);
// タグ1の通知をキャンセル
LocalNotification::cancel(1);