zoukankan      html  css  js  c++  java
  • unity3d 之本地推送

    参考:http://blog.csdn.net/azhou_hui/article/details/50790870

    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();
    }
    INotification

    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
    AndroidNotification

    其中 "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;
        }
    }
    AlarmReceiver

    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>
          <!-- ] -->
    Manifest

    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()
            {
                alertBody = content,
                hasAction = false,
                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
    IOSNotification

    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 = PlayerInfo.Instance().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;
    
            // spaTime just notify once
            //for (int i = 0; i < ActivityInfoValue.Instance().spaStartTimeList.Count; i++)
            //{
                int notiId = (int)NotificationType.SpaTime + 0;
                Unregister(notiId);
    
                if (SystemSettingModel.Instance.NotifyHotSpring)        // 系统设置
                {
                    ulong spaStartTime = ActivityInfoValue.Instance().spaStartTimeList[0];
                    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 = PlayerInfo.Instance().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()
        {
            Unregister(NotificationType.PuYuanShopRefresh);
    
            if (SystemSettingModel.Instance.NotifyShopRefresh)
            {
                DateTime time = DateTime.Parse(GameOption.Instance().refreshShopResetTime[0]);      // 只需要每天9点推送
                DateTime serverNow = PlayerInfo.Instance().GetServerNow();
                DateTime triggerTime = new DateTime(serverNow.Year, serverNow.Month, serverNow.Day, time.Hour, time.Minute, 0);
                string content = MLocalization.Get("194260071");
    
                Register(NotificationType.PuYuanShopRefresh, content, triggerTime, true);
            }
        }
    
        // 世界 boss 开启
        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 = PlayerInfo.Instance().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
    
        public void Dispose()
        {
            m_notification.Dispose();
        }
    }
    NotificationManager

    转载请注明出处:http://www.cnblogs.com/jietian331/p/5025561.html

  • 相关阅读:
    TPCx-BB官宣最新世界纪录,阿里巴巴计算力持续突破
    Java 编程技巧之数据结构
    从零开始入门 K8s | Kubernetes 网络概念及策略控制
    从零开始入门 K8s | 可观测性:监控与日志
    如何在 Knative 中部署 WebSocket 和 gRPC 服务?
    全球首个开放应用模型 OAM 开源
    开放应用模型(OAM):全球首个云原生应用标准定义与架构模型
    一文读懂分布式架构知识体系(内含超全核心知识大图)
    更强大的实时数仓构建能力!分析型数据库PostgreSQL 6.0新特性解读
    数论练习(1)——取余运算(快速幂)
  • 原文地址:https://www.cnblogs.com/jietian331/p/5025561.html
Copyright © 2011-2022 走看看