unity3d 之本地推送

1. 本地推送主要包括在android和ios上,下面所有的代码都是本人写的,经过测试是没有问题的,已经运用到项目中了。首先是接口INotification:

using System;

public interface INotification : IDisposable
{
    /// <summary>
    /// 注册一个推送
    /// </summary>
    /// <param name="id">消息唯一标识</param>
    /// <param name="name">消息弹出一时在手机屏幕最上方显示的文字,对苹果无效</param>
    /// <param name="title">通知栏中消息的标题</param>
    /// <param name="content">通知栏中消息的正文</param>
    /// <param name="triggerTime">触发的时间</param>
    /// <param name="repeat">是否要每日重复触发</param>
    void Register(int id, string name, string title, string content, DateTime triggerTime, bool repeat);

    /// <summary>
    /// 取消一个推送
    /// </summary>
    /// <param name="id">消息唯一标识</param>
    void Unregister(int id);

    /// <summary>
    /// 取消所有推送
    /// </summary>
    void ClearAll();
}

2. android的实现:

#if UNITY_ANDROID

using System;
using UnityEngine;

public class AndroidNotification : INotification
{
    AndroidJavaObject m_javaObj = new AndroidJavaObject("com.example.localpush.AlarmReceiver");

    public void Register(int id, string name, string title, string content, DateTime triggerTime, bool repeat)
    {
        int secondsFromNow = (int)(triggerTime - DateTime.Now).TotalSeconds;

        m_javaObj.CallStatic("Register", new object[6]
        {
            id,
            name,
            title,
            content,
            secondsFromNow,
            repeat
        });
    }

    public void Unregister(int id)
    {
        m_javaObj.CallStatic("Unregister", id);
    }

    public void ClearAll()
    {
        var types = Enum.GetValues(typeof(NotificationType));
        for (int i = 0; i < types.Length * 100; i++)
            Unregister(i);
    }

    #region IDisposable

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            m_javaObj.Dispose();
            m_javaObj = null;
        }
    }

    ~AndroidNotification()
    {
        Dispose(false);
    }

    #endregion
}

#endif

  其中 "com.example.localpush.AlarmReceiver" 中的java代码如下:

package com.example.localpush;

import java.util.ArrayList;
import java.util.Calendar;
import android.app.Activity;
import android.app.AlarmManager;
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.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Log;
import com.unity3d.player.UnityPlayer;

public class AlarmReceiver extends BroadcastReceiver
{
    static final int NotificationCount = 10;
    static final int RepeatInterval = 24 * 60 * 60 * 1000;// 86400000

    // Inner class
    static class BleachNotification
    {
        public int Id;
        public String Name;
        public String Title;
        public String Content;
        public long TriggerMillis;
        public boolean Repeat;

        public BleachNotification(int id, String name, String title, String content, long triggerMillis, boolean repeat)
        {
            Id = id;
            Name=name;
            Title = title;
            Content = content;
            TriggerMillis = repeat?GetNextRepeatTime(triggerMillis):triggerMillis;
            Repeat = repeat;
        }

        private long GetNextRepeatTime(long time)
        {
            long now = System.currentTimeMillis();

            while(time<now)
                time+=RepeatInterval;

            return time;
        }
    }

     @Override
    public void onReceive(Context context, Intent intent)
    {
        String action = intent.getAction();

        Log.d("Unity", "Bleach: onReceive......................" + action);
        if (action!=null && action.equals("android.intent.action.BOOT_COMPLETED"))
        {
            for (BleachNotification bn : LoadAllNotification())
                Register(bn, false);
        }
        else
        {
            if (!intent.getBooleanExtra("repeat", true))
            {
                int id = intent.getIntExtra("id", -1);
                if (id != -1)
                    DisableNotification(context, id);
            }

            NotificationManager nm=(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

            ApplicationInfo applicationInfo=null;
             try
             {
                 final PackageManager pm=context.getPackageManager();
                 applicationInfo = pm.getApplicationInfo(context.getPackageName(),PackageManager.GET_META_DATA);
             }
             catch (NameNotFoundException e)
             {
               Log.d("Unity","Bleach: onReceive failed, reason: get applicationInfo failed.");
             }

            Notification notification=new Notification(applicationInfo.icon,intent.getStringExtra("name"),System.currentTimeMillis());

            Intent notificationIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
            notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
            PendingIntent pi = PendingIntent.getActivity(context, 0, notificationIntent, 0);

            notification.setLatestEventInfo(context, intent.getStringExtra("title"), intent.getStringExtra("content"), pi);

            // Notify
            nm.notify(intent.getIntExtra("id",0),notification);

            Log.d("Unity","Bleach: notify succeed!");
        }
    }

     public static void Register(int id, String name, String title, String content, int secondsFromNow, boolean repeat)
     {
         Calendar calendar=Calendar.getInstance();
         calendar.setTimeInMillis(System.currentTimeMillis());
         calendar.add(Calendar.SECOND, secondsFromNow);
         long time=calendar.getTimeInMillis();

         Register(new BleachNotification(id,name,title,content,time,repeat),true);
     }

    private static void Register(BleachNotification bn,boolean isSave)
    {
        Activity activity =UnityPlayer.currentActivity;

        Intent intent =new Intent(activity, AlarmReceiver.class);
        intent.putExtra("name", bn.Name);
        intent.putExtra("title", bn.Title);
        intent.putExtra("content", bn.Content);
        intent.putExtra("id", bn.Id);
        intent.putExtra("repeat",bn.Repeat);

        PendingIntent pi=PendingIntent.getBroadcast(activity, bn.Id, intent, PendingIntent.FLAG_CANCEL_CURRENT);

        // Schedule the alarm!
        AlarmManager am = (AlarmManager)activity.getSystemService(Context.ALARM_SERVICE);
        if(bn.Repeat)
            am.setRepeating(AlarmManager.RTC_WAKEUP, bn.TriggerMillis, RepeatInterval, pi);
        else
            am.set(AlarmManager.RTC_WAKEUP,bn.TriggerMillis, pi);

        if(isSave)
            SaveNotification(bn);

        Log.d("Unity", "Bleach: Start Alarm...,id: "+bn.Id+
                "  name: "+bn.Name+
                "  title: "+bn.Title+
                "  content: "+bn.Content+
                "  triggerMillis: "+bn.TriggerMillis+
                "  currentTime:"+System.currentTimeMillis()+
                "  repeat: "+bn.Repeat);
    }

    public static void Unregister(int id)
    {
        Activity activity = UnityPlayer.currentActivity;
        Intent intent = new Intent(activity, AlarmReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(activity, id, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        AlarmManager am = (AlarmManager)activity.getSystemService(Context.ALARM_SERVICE);
        am.cancel(pi);

        NotificationManager mNM = (NotificationManager)activity.getSystemService(Context.NOTIFICATION_SERVICE);
        mNM.cancel(id);

        DisableNotification(activity, id);

        Log.d("Unity","Bleach: Cancel, id: "+id);
    }

    private static void DisableNotification(Context context,int id)
    {
        SharedPreferences sp = context.getSharedPreferences("Notification", Context.MODE_APPEND);

        Editor edit = sp.edit();
        String sid = String.valueOf(id);
        edit.putInt(sid, -1);
        edit.commit();
    }

    private static void SaveNotification(BleachNotification notification)
    {
        SharedPreferences sp = UnityPlayer.currentActivity.getSharedPreferences("Notification", Context.MODE_APPEND);

        Editor edit = sp.edit();
        String sid = String.valueOf(notification.Id);
        edit.putInt(sid, 1);
        edit.putString(sid + "name", notification.Name);
        edit.putString(sid + "title", notification.Title);
        edit.putString(sid + "content", notification.Content);
        edit.putLong(sid + "triggerTime", notification.TriggerMillis);
        edit.putBoolean(sid + "repeat", notification.Repeat);
        edit.commit();
    }

    private static ArrayList<BleachNotification> LoadAllNotification()
    {
        ArrayList<BleachNotification> l = new ArrayList<BleachNotification>();
        SharedPreferences sp = UnityPlayer.currentActivity.getSharedPreferences("Notification", Context.MODE_APPEND);
        int index = 0;
        while (index < NotificationCount)
        {
            String id = String.valueOf(index);
            if (sp.getInt(id, -1) != -1)
            {
                BleachNotification bn=new BleachNotification(
                        index,
                        sp.getString(id + "name", ""),
                        sp.getString(id + "title", ""),
                        sp.getString(id + "content",""),
                        sp.getLong(id + "triggerTime", 0),
                        sp.getBoolean(id + "repeat", false)
                        );
                l.add(bn);
            }
            index++;
        }
        return l;
    }
}

  manifest配置为:

 <!-- Add by tj[-->
      <receiver android:name="com.example.localpush.AlarmReceiver">
        <intent-filter>
          <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
      </receiver>
          
      <activity
        android:name="com.unity3d.player.UnityPlayerProxyActivity"
        android:label="@string/app_name"
        android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" >
      </activity>
          
      <activity
        android:name="com.unity3d.player.UnityPlayerActivity"
        android:label="@string/app_name"
        android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" >
      </activity>

      <activity
        android:name="com.unity3d.player.UnityPlayerNativeActivity"
        android:label="@string/app_name"
        android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" >
              <meta-data android:name="android.app.lib_name" android:value="unity" />
              <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />
      </activity>
      <!-- ] -->

3. ios 直接调用 unity3d 的 api,实现如下:

#if  UNITY_IPHONE

using System;
using UnityEngine;

public class IOSNotification : INotification
{
    static IOSNotification()
    {
        Clear();

        NotificationServices.RegisterForLocalNotificationTypes(LocalNotificationType.Alert);
    }

    public void Register(int id, string name, string title, string content, DateTime triggerTime, bool repeat)
    {
        var iosNotification = new LocalNotification()
        {
            alertAction = content,
            alertBody = content,
            hasAction = true,
            applicationIconBadgeNumber = 1,
            fireDate = triggerTime,
            soundName = LocalNotification.defaultSoundName,
        };

        if (repeat)
        {
            iosNotification.repeatCalendar = CalendarIdentifier.ChineseCalendar;
            iosNotification.repeatInterval = CalendarUnit.Day;
        }

        NotificationServices.ScheduleLocalNotification(iosNotification);
    }

    public void Unregister(int id)
    {

    }

    public void ClearAll()
    {
        Clear();
    }

    static void Clear()
    {
        var ln = new LocalNotification()
        {
            applicationIconBadgeNumber = -1
        };

        NotificationServices.PresentLocalNotificationNow(ln);
        NotificationServices.CancelAllLocalNotifications();
        NotificationServices.ClearLocalNotifications();
    }

    #region INotification

    public void Dispose()
    {

    }

    #endregion
}

#endif

4. 最后是一个与上层交互的接口:

using System;
using UnityEngine;

// 本地推送的类型,注意:id不能重复
public enum NotificationType
{
    SevenDaysNoLogin = 1,               // 7日登陆
    SpecialTrain = 100,                 // 紧急特训
    SpaTime = 200,                      // 温泉
    LoginNextDay = 300,                 // 次日登陆
    PuYuanShopRefresh = 400,            // 浦原商店刷新
    WorldBossOpen = 500,                // 世界boss开启
}

public class NotificationManager : IDisposable
{
    INotification m_notification;

    #region Singleton

    static NotificationManager s_instance;

    public static NotificationManager Instance
    {
        get
        {
            if (s_instance == null)
                s_instance = new NotificationManager();
            return s_instance;
        }
    }

    #endregion

    #region DefaultNotification

    class DefaultNotification : INotification
    {
        public void Register(int id, string name, string title, string content, DateTime triggerTime, bool repeat)
        {

        }

        public void Unregister(int id)
        {

        }

        public void ClearAll()
        {

        }

        public void Dispose()
        {

        }
    }

    #endregion

    private NotificationManager()
    {
        m_notification = CreateObj();
    }

    INotification CreateObj()
    {
        INotification obj;
#if UNITY_EDITOR
        obj = new DefaultNotification();
#elif UNITY_ANDROID
        obj = new AndroidNotification();
#elif  UNITY_IPHONE
        obj = new IOSNotification();
#else
        obj = new DefaultNotification();
        Debugger.LogWarning("Local push not support this platform");
#endif

        return obj;
    }

    public void Register(int id, string content, DateTime triggerTime, bool repeat)
    {
        if (string.IsNullOrEmpty(content))
            throw new ArgumentException("content");

        string title = MLocalization.Get("194260041");      // 游戏名
        if (string.IsNullOrEmpty(title))
            throw new ArgumentException("title");

        m_notification.Register(id, content, title, content, triggerTime, repeat);

        Debug.Log(string.Format("local push, id: {0}, title: {1},  content: {2},  Time: {3}  repeat: {4}", id, title, content, triggerTime, repeat));
    }

    public void Register(NotificationType type, string content, DateTime triggerTime, bool repeat)
    {
        Register((int)type, content, triggerTime, repeat);
    }

    public void Unregister(int id)
    {
        m_notification.Unregister(id);
    }

    public void Unregister(NotificationType type)
    {
        Unregister((int)type);
    }

    public void ClearAll()
    {
        m_notification.ClearAll();
    }

    /// <summary>
    /// 登陆完成后更新本地推送
    /// </summary>
    public void UpdateWhenLoginComplete()
    {
        UpdateSevenDaysNoLogin();

        //UpdateLoginNextDay();

        UpdatePuYuanShopRefresh();

        UpdateWorldBossOpen();
    }

    #region Special notification

    void UpdateSevenDaysNoLogin()
    {
        string content = MLocalization.Get("194260031");
        var time = GetServerNow().AddDays(7);

        Unregister(NotificationType.SevenDaysNoLogin);
        Register(NotificationType.SevenDaysNoLogin, content, time, false);
    }

    public void RegisterSpecialTrain(TrainingSpecially tr)
    {
        string content = MLocalization.Get("194260021");

        Register(NotificationType.SpecialTrain, content, tr.begin_time, true);
    }

    public void UpdateSpaTime()
    {
        string content = null;

        for (int i = 0; i < ActivityInfoValue.Instance().spaStartTimeList.Count; i++)
        {
            int notiId = (int)NotificationType.SpaTime + i;
            Unregister(notiId);

            if (SystemSettingModel.Instance.NotifyHotSpring)        // 系统设置
            {
                ulong spaStartTime = ActivityInfoValue.Instance().spaStartTimeList[i];
                DateTime dateTimeStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
                DateTime dateTimeTrigger = dateTimeStart.AddSeconds(spaStartTime).ToLocalTime();

                if (content == null)
                    content = MLocalization.Get("194260011");

                Register(notiId, content, dateTimeTrigger, true);
            }
        }

    }

    public void ClearSpaTime()
    {
        if (ActivityInfoValue.Instance().spaStartTimeList == null)
            return;
        for (int i = 0; i < ActivityInfoValue.Instance().spaStartTimeList.Count; i++)
        {
            int notiId = (int)NotificationType.SpaTime + i;
            Unregister(notiId);
        }
    }

    /*
     * 当玩家首次打开客户端进入游戏时,设置一条推送,在第二天的20点进行推送
     * 当玩家第二天20点之前,登录过游戏,则取消此条推送。
     * 推送文字为“你今天还没有登录死神哦,登录即可入手斩月。“(本文字为语言包文字)
     */
    void UpdateLoginNextDay()
    {
        string prefKey = string.Format("LocalPush.{0}.{1}", PlayerInfo.Instance().roleID, NotificationType.LoginNextDay);
        int prefValue = PlayerPrefs.GetInt(prefKey);

        Unregister(NotificationType.LoginNextDay);

        if (prefValue <= 0)
        {
            DateTime serverNow = GetServerNow();
            string timeString = GameOption.Instance().NotifyBladeTime;
            DateTime time = DateTime.Parse(timeString);
            DateTime triggerTime = new DateTime(serverNow.Year, serverNow.Month, serverNow.Day, time.Hour, time.Minute, 0).AddDays(1);
            string content = MLocalization.Get("194260051");

            Register(NotificationType.LoginNextDay, content, triggerTime, false);

            PlayerPrefs.SetInt(prefKey, 1);
        }
    }

    public void UpdatePuYuanShopRefresh()
    {
        var timeStrings = GameOption.Instance().refreshShopResetTime;
        DateTime serverNow = GetServerNow();
        string content = null;

        for (int i = 0; i < timeStrings.Length; i++)
        {
            int id = (int)NotificationType.PuYuanShopRefresh + i;
            Unregister(id);

            if (SystemSettingModel.Instance.NotifyShopRefresh)
            {
                DateTime time = DateTime.Parse(timeStrings[i]);
                DateTime triggerTime = new DateTime(serverNow.Year, serverNow.Month, serverNow.Day, time.Hour, time.Minute, 0);

                if (content == null)
                    content = MLocalization.Get("194260071");

                Register(id, content, triggerTime, true);
            }
        }
    }

    public void UpdateWorldBossOpen()
    {
        Unregister(NotificationType.WorldBossOpen);

        bool isOpen = PlayerInfo.Instance().openedSystemID.Contains((uint)SystemEnum.WorldBoss);
        if (isOpen && SystemSettingModel.Instance.NotifyWorldBossOpen)
        {
            string content = MLocalization.Get("194260061");
            DateTime serverNow = GetServerNow();
            string timeString = GameOption.Instance().bossYammyNotifyTime;
            DateTime time = DateTime.Parse(timeString);
            DateTime triggerTime = new DateTime(serverNow.Year, serverNow.Month, serverNow.Day, time.Hour, time.Minute, 0);

            Register(NotificationType.WorldBossOpen, content, triggerTime, true);
        }
    }

    #endregion

    static DateTime GetServerNow()
    {
        DateTime dateTimeStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
        return dateTimeStart.AddSeconds(PlayerInfo.Instance().serverTime);
    }

    public void Dispose()
    {
        m_notification.Dispose();
    }
}
时间: 2024-10-11 18:14:27

unity3d 之本地推送的相关文章

本地推送 和 远程推送

今天看了一下远程推送,之前写的软件一直没加进这个功能,下个软件貌似要求有这个,所以问了一下度娘,也是有那么一丢丢的小麻烦吧,因为他没跳推送都必须经过苹果APNS,然后再发送给每个安装了软件的用户~~~ ///本地添加 void ,__FUNCTION__); if timeZone是UILocalNotification激发时间是否根据时区改变而改变,如果设置为nil的话,那么UILocalNotification将在一段时候后被激发,而不是某一个确切时间被激发.*/ ofType:@]; fo

ios本地推送demo

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {     // Override point for customization after application launch.     //应用图标数字     application.applicationIconBadgeNumber=6;          //申请用

Apache Web Server 本地推送命令

/*****openssl 系统命令    x509输入文件类型       -in 是参数输入文件   -inform本地文件     -out是参数  是生成文件  ***/ openssl    x509  -in  *.cer  -inform  der  -out *.pem openssl  pkcs12  -nocets  -out  *.pem  -in  *.p12 /*****   >是 表示连接   ****/ cat  *.pem  *.pem  >  *.pem 在终

本地推送通知UILocalNotification

1 - (IBAction)schedule { 2 // 1.创建本地推送通知对象 3 UILocalNotification *ln = [[UILocalNotification alloc] init]; 4 5 // 2.设置通知属性 6 // 音效文件名 7 ln.soundName = @"buyao.wav"; 8 9 // 通知的具体内容 10 ln.alertBody = @"重大新闻:xxxx xxxx被调查了...."; 11 12 // 锁

SWIFT推送之本地推送(UILocalNotification)

本地推送通知是通过实例化UILocalNotification实现的.要实现本地化推送可以在AppDelegate.swift中添加代码实现,本事例是一个当App进入后台时推送一条消息给用户. 1.首先在didFinishLaunchingWithOptions方法内添加代码,IOS8推送消息首先要获得用户的同意,在初次安装App时会提示用户是否允许程序推送消息,此方法是App第一次运行的时候被执行一次,每次从后台激活时不执行该方法. func application(application:

iOS 本地推送

在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知机制就可以告诉用户此时发生的事情. iOS中通知机制又叫消息机制,其包括两类:一类是本地通知:另一类是推送通知,也叫远程通知.两种通知在iOS中的表现一致,可以通过横幅或者弹出提醒 两种形式告诉用户,并且点击通知可以会打开应用程序,但是实现原理却完全不同.今天就和大家一块去看一下如何在iOS中实现这两种机制,并且在文章后面会 补充通知中心的内容避免初学者对两种概念的混淆. 简单些了一个关于

iOS的本地推送UILocalNotification的使用

UILocalNotification 1 第一步:接收本地推送 2 3 实现代理方法didReceiveLocalNotification 4 5 - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification*)notification{ 6 7 //在此时设置解析notification,并展示提示视图 8 9 } 10 11 第二步:创建本地推送 12 -

本地推送通知在iOS8上的不同

iOS8的不同点 你如果把上面的程序运行在iOS8上,会爆出如下错误 预习01-本地推送通知[掌握][615:7847] Attempting to schedule a local notification {fire date = Monday, July 13, 2015 at 9:02:25 AM China Standard Time, time zone = (null), repeat interval = 0, repeat count = UILocalNotification

本地推送通知小demo

本地推送通知: #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // 在iOS8之后,Apple对用户隐私要求更加严格,所