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

原文地址:https://www.cnblogs.com/jietian331/p/5025561.html