fix:1、更换sdk
This commit is contained in:
+35
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether to schedule notifications at exact time or approximately (saves power).
|
||||
/// Exact scheduling is available in Android 6 (API 23) and newer, lower versions always use inexact scheduling.
|
||||
/// Android 12 (API 31) or newer requires SCHEDULE_EXACT_ALARM permission and grant from user to use exact scheduling.
|
||||
/// Android 13 (API 33) or newer can use USE_EXACT_ALARM permission to use exactscheduling without requesting users grant.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum AndroidExactSchedulingOption
|
||||
{
|
||||
/// <summary>
|
||||
/// Use exact scheduling when possible.
|
||||
/// </summary>
|
||||
ExactWhenAvailable = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Add SCHEDULE_EXACT_ALARM permission to the manifest.
|
||||
/// </summary>
|
||||
AddScheduleExactPermission = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// Add USE_EXACT_ALARM permission to the manifest.
|
||||
/// </summary>
|
||||
AddUseExactAlarmPermission = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// Add REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission to the manifest.
|
||||
/// Required if you want to use <see cref="AndroidNotificationCenter.RequestIgnoreBatteryOptimizations()"/>.
|
||||
/// </summary>
|
||||
AddRequestIgnoreBatteryOptimizationsPermission = 1 << 3,
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5ef4f75b5ba00a4793f867958e727b2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
#if UNITY_ANDROID
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Android;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
public class AndroidNotificationPostProcessor : IPostGenerateGradleAndroidProject
|
||||
{
|
||||
const string kAndroidNamespaceURI = "http://schemas.android.com/apk/res/android";
|
||||
|
||||
public int callbackOrder { get { return 0; } }
|
||||
|
||||
public void OnPostGenerateGradleAndroidProject(string projectPath)
|
||||
{
|
||||
projectPath = Path.Combine(projectPath, "mobilenotifications.androidlib");
|
||||
if (!Directory.Exists(projectPath))
|
||||
throw new Exception("mobilenotifications module not found in gradle project");
|
||||
|
||||
CopyNotificationResources(projectPath);
|
||||
|
||||
InjectAndroidManifest(projectPath);
|
||||
}
|
||||
|
||||
private void CopyNotificationResources(string projectPath)
|
||||
{
|
||||
// Get the icons set in the UnityNotificationEditorManager and write them to the res folder, then we can use the icons as res.
|
||||
var icons = NotificationSettingsManager.Initialize().GenerateDrawableResourcesForExport();
|
||||
foreach (var icon in icons)
|
||||
{
|
||||
var fileInfo = new FileInfo(string.Format("{0}/src/main/res/{1}", projectPath, icon.Key));
|
||||
if (fileInfo.Directory != null)
|
||||
{
|
||||
fileInfo.Directory.Create();
|
||||
File.WriteAllBytes(fileInfo.FullName, icon.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal struct ManifestSettings
|
||||
{
|
||||
public bool UseCustomActivity;
|
||||
public string CustomActivity;
|
||||
public bool RescheduleOnRestart;
|
||||
public AndroidExactSchedulingOption ExactAlarm;
|
||||
}
|
||||
|
||||
private void InjectAndroidManifest(string projectPath)
|
||||
{
|
||||
var manifestPath = string.Format("{0}/src/main/AndroidManifest.xml", projectPath);
|
||||
if (!File.Exists(manifestPath))
|
||||
throw new FileNotFoundException(string.Format("'{0}' doesn't exist.", manifestPath));
|
||||
|
||||
XmlDocument manifestDoc = new XmlDocument();
|
||||
manifestDoc.Load(manifestPath);
|
||||
|
||||
var settings = NotificationSettingsManager.Initialize().AndroidNotificationSettingsFlat;
|
||||
var manifestSettings = new ManifestSettings()
|
||||
{
|
||||
UseCustomActivity = GetSetting<bool>(settings, NotificationSettings.AndroidSettings.USE_CUSTOM_ACTIVITY),
|
||||
CustomActivity = GetSetting<string>(settings, NotificationSettings.AndroidSettings.CUSTOM_ACTIVITY_CLASS),
|
||||
RescheduleOnRestart = GetSetting<bool>(settings, NotificationSettings.AndroidSettings.RESCHEDULE_ON_RESTART),
|
||||
ExactAlarm = GetSetting<AndroidExactSchedulingOption>(settings, NotificationSettings.AndroidSettings.EXACT_ALARM),
|
||||
};
|
||||
|
||||
InjectAndroidManifest(manifestPath, manifestDoc, manifestSettings);
|
||||
|
||||
manifestDoc.Save(manifestPath);
|
||||
}
|
||||
|
||||
internal static void InjectAndroidManifest(string manifestPath, XmlDocument manifestDoc, ManifestSettings settings)
|
||||
{
|
||||
if (settings.UseCustomActivity)
|
||||
AppendAndroidMetadataField(manifestPath, manifestDoc, "custom_notification_android_activity", settings.CustomActivity);
|
||||
|
||||
if (settings.RescheduleOnRestart)
|
||||
{
|
||||
AppendAndroidMetadataField(manifestPath, manifestDoc, "reschedule_notifications_on_restart", "true");
|
||||
AppendAndroidPermissionField(manifestPath, manifestDoc, "android.permission.RECEIVE_BOOT_COMPLETED");
|
||||
}
|
||||
|
||||
bool enableExact = (settings.ExactAlarm & AndroidExactSchedulingOption.ExactWhenAvailable) != 0;
|
||||
AppendAndroidMetadataField(manifestPath, manifestDoc, "com.unity.androidnotifications.exact_scheduling", enableExact ? "1" : "0");
|
||||
if (enableExact)
|
||||
{
|
||||
bool scheduleExact = (settings.ExactAlarm & AndroidExactSchedulingOption.AddScheduleExactPermission) != 0;
|
||||
bool useExact = (settings.ExactAlarm & AndroidExactSchedulingOption.AddUseExactAlarmPermission) != 0;
|
||||
// as documented here: https://developer.android.com/reference/android/Manifest.permission#USE_EXACT_ALARM
|
||||
// only one of these two attributes should be used or max sdk set so on any device it's one or the other
|
||||
if (scheduleExact)
|
||||
AppendAndroidPermissionField(manifestPath, manifestDoc, "android.permission.SCHEDULE_EXACT_ALARM", useExact ? "32" : null);
|
||||
if (useExact)
|
||||
AppendAndroidPermissionField(manifestPath, manifestDoc, "android.permission.USE_EXACT_ALARM");
|
||||
|
||||
// Battery optimizations must use "uses-permission-sdk-23", regular uses-permission does not work
|
||||
if ((settings.ExactAlarm & AndroidExactSchedulingOption.AddRequestIgnoreBatteryOptimizationsPermission) != 0)
|
||||
AppendAndroidPermissionField(manifestPath, manifestDoc, "uses-permission-sdk-23", "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS", null);
|
||||
}
|
||||
}
|
||||
|
||||
private static T GetSetting<T>(List<NotificationSetting> settings, string key)
|
||||
{
|
||||
return (T)settings.Find(i => i.Key == key).Value;
|
||||
}
|
||||
|
||||
internal static void AppendAndroidPermissionField(string manifestPath, XmlDocument xmlDoc, string name, string maxSdk = null)
|
||||
{
|
||||
AppendAndroidPermissionField(manifestPath, xmlDoc, "uses-permission", name, maxSdk);
|
||||
}
|
||||
|
||||
internal static void AppendAndroidPermissionField(string manifestPath, XmlDocument xmlDoc, string tagName, string name, string maxSdk)
|
||||
{
|
||||
var manifestNode = xmlDoc.SelectSingleNode("manifest");
|
||||
if (manifestNode == null)
|
||||
throw new ArgumentException(string.Format("Missing 'manifest' node in '{0}'.", manifestPath));
|
||||
|
||||
XmlElement metaDataNode = null;
|
||||
foreach (XmlNode node in manifestNode.ChildNodes)
|
||||
{
|
||||
if (!(node is XmlElement) || node.Name != tagName)
|
||||
continue;
|
||||
|
||||
var element = (XmlElement)node;
|
||||
var elementName = element.GetAttribute("name", kAndroidNamespaceURI);
|
||||
if (elementName == name)
|
||||
{
|
||||
if (maxSdk == null)
|
||||
return;
|
||||
var maxSdkAttr = element.GetAttribute("maxSdkVersion", kAndroidNamespaceURI);
|
||||
if (!string.IsNullOrEmpty(maxSdkAttr))
|
||||
return;
|
||||
metaDataNode = element;
|
||||
}
|
||||
}
|
||||
|
||||
if (metaDataNode == null)
|
||||
{
|
||||
metaDataNode = xmlDoc.CreateElement(tagName);
|
||||
metaDataNode.SetAttribute("name", kAndroidNamespaceURI, name);
|
||||
}
|
||||
if (maxSdk != null)
|
||||
metaDataNode.SetAttribute("maxSdkVersion", kAndroidNamespaceURI, maxSdk);
|
||||
|
||||
manifestNode.AppendChild(metaDataNode);
|
||||
}
|
||||
|
||||
internal static void AppendAndroidMetadataField(string manifestPath, XmlDocument xmlDoc, string name, string value)
|
||||
{
|
||||
var applicationNode = xmlDoc.SelectSingleNode("manifest/application");
|
||||
if (applicationNode == null)
|
||||
throw new ArgumentException(string.Format("Missing 'application' node in '{0}'.", manifestPath));
|
||||
|
||||
var nodes = xmlDoc.SelectNodes("manifest/application/meta-data");
|
||||
if (nodes != null)
|
||||
{
|
||||
// Check if there is a 'meta-data' with the same name.
|
||||
foreach (XmlNode node in nodes)
|
||||
{
|
||||
var element = node as XmlElement;
|
||||
if (element == null)
|
||||
continue;
|
||||
|
||||
var elementName = element.GetAttribute("name", kAndroidNamespaceURI);
|
||||
if (elementName == name)
|
||||
{
|
||||
element.SetAttribute("value", kAndroidNamespaceURI, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XmlElement metaDataNode = xmlDoc.CreateElement("meta-data");
|
||||
metaDataNode.SetAttribute("name", kAndroidNamespaceURI, name);
|
||||
metaDataNode.SetAttribute("value", kAndroidNamespaceURI, value);
|
||||
|
||||
applicationNode.AppendChild(metaDataNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ab62d805bcb24c96b7ef39a230d410e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Unity.Notifications.Tests")]
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3703be1dcf9d604a85439fd2feb1e0d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
[System.Serializable]
|
||||
internal class DrawableResourceData
|
||||
{
|
||||
public string Id;
|
||||
public NotificationIconType Type;
|
||||
public Texture2D Asset;
|
||||
|
||||
private bool m_IsValid = false;
|
||||
private List<string> m_Errors = null;
|
||||
private Texture2D m_PreviewTexture;
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_IsValid == false && m_Errors == null)
|
||||
Verify();
|
||||
|
||||
return m_IsValid;
|
||||
}
|
||||
}
|
||||
|
||||
public string[] Errors
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_IsValid == false && m_Errors == null)
|
||||
Verify();
|
||||
|
||||
return m_Errors.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public Texture2D GetPreviewTexture(bool update)
|
||||
{
|
||||
if (Asset == null)
|
||||
return null;
|
||||
|
||||
if (m_IsValid && (m_PreviewTexture == null || update))
|
||||
m_PreviewTexture = TextureAssetUtils.ProcessTextureForType(Asset, Type);
|
||||
|
||||
return m_PreviewTexture;
|
||||
}
|
||||
|
||||
internal bool Initialized()
|
||||
{
|
||||
return !string.IsNullOrEmpty(Id) && Asset != null;
|
||||
}
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
m_IsValid = false;
|
||||
m_Errors = null;
|
||||
m_PreviewTexture = null;
|
||||
}
|
||||
|
||||
public bool Verify()
|
||||
{
|
||||
m_IsValid = TextureAssetUtils.VerifyTextureByType(Asset, Type, out m_Errors);
|
||||
return m_IsValid;
|
||||
}
|
||||
|
||||
public string GenerateErrorString()
|
||||
{
|
||||
var errors = Errors;
|
||||
|
||||
var errorString = string.Empty;
|
||||
for (var i = 0; i < errors.Length; i++)
|
||||
{
|
||||
errorString += string.Format("{0}{1}", errors[i], i + 1 >= errors.Length ? "." : ", ");
|
||||
}
|
||||
|
||||
return errorString;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7bb3ae4e071b4f599d584ac995b185f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
#if UNITY_IOS
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEngine;
|
||||
|
||||
public class NotificationAutoConfig : IPreprocessBuildWithReport
|
||||
{
|
||||
public int callbackOrder => 0;
|
||||
|
||||
public void OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
if (report.summary.platform != BuildTarget.iOS) return;
|
||||
|
||||
// 1. 构造文件绝对路径
|
||||
string settingsPath = "ProjectSettings/NotificationsSettings.asset";
|
||||
string fullPath = Path.GetFullPath(Path.Combine(Application.dataPath, "..", settingsPath));
|
||||
|
||||
if (!File.Exists(fullPath))
|
||||
{
|
||||
Debug.LogError($"[NotificationAutoConfig] 文件不存在: {fullPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 通过反射获取 NotificationSettingsManager 类型
|
||||
Type managerType = null;
|
||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
managerType = asm.GetType("Unity.Notifications.NotificationSettingsManager");
|
||||
if (managerType != null) break;
|
||||
}
|
||||
|
||||
if (managerType == null)
|
||||
{
|
||||
Debug.LogError("[NotificationAutoConfig] 无法找到 NotificationSettingsManager 类型。");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 读取文件 JSON,创建 Manager 实例并用 JSON 覆盖数据
|
||||
string json = File.ReadAllText(fullPath);
|
||||
ScriptableObject managerInstance = ScriptableObject.CreateInstance(managerType);
|
||||
EditorJsonUtility.FromJsonOverwrite(json, managerInstance);
|
||||
|
||||
// 4. 获取 m_iOSNotificationSettingsValues 字段(NotificationSettingsCollection)
|
||||
FieldInfo settingsField = managerType.GetField("m_iOSNotificationSettingsValues",
|
||||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (settingsField == null)
|
||||
{
|
||||
Debug.LogError("[NotificationAutoConfig] 找不到 m_iOSNotificationSettingsValues 字段。");
|
||||
ScriptableObject.DestroyImmediate(managerInstance);
|
||||
return;
|
||||
}
|
||||
|
||||
object iOSSettings = settingsField.GetValue(managerInstance);
|
||||
if (iOSSettings == null)
|
||||
{
|
||||
Debug.LogError("[NotificationAutoConfig] m_iOSNotificationSettingsValues 为 null。");
|
||||
ScriptableObject.DestroyImmediate(managerInstance);
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. 获取索引器(this[string key])
|
||||
Type collectionType = iOSSettings.GetType();
|
||||
PropertyInfo indexer = collectionType.GetProperty("Item", BindingFlags.Public | BindingFlags.Instance);
|
||||
if (indexer == null)
|
||||
{
|
||||
Debug.LogError("[NotificationAutoConfig] 无法找到 NotificationSettingsCollection 的索引器。");
|
||||
ScriptableObject.DestroyImmediate(managerInstance);
|
||||
return;
|
||||
}
|
||||
|
||||
// 6. 修改目标键的值
|
||||
bool changed = false;
|
||||
changed |= SetSettingValue(indexer, iOSSettings, "UnityNotificationRequestAuthorizationOnAppLaunch", false);
|
||||
changed |= SetSettingValue(indexer, iOSSettings, "UnityAddRemoteNotificationCapability", true);
|
||||
changed |= SetSettingValue(indexer, iOSSettings, "UnityUseAPSReleaseEnvironment", true);
|
||||
|
||||
// 7. 写回文件并刷新
|
||||
if (changed)
|
||||
{
|
||||
string newJson = EditorJsonUtility.ToJson(managerInstance, true);
|
||||
File.WriteAllText(fullPath, newJson);
|
||||
AssetDatabase.Refresh();
|
||||
Debug.Log("[NotificationAutoConfig] iOS 通知配置已成功更新。");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("[NotificationAutoConfig] 配置已是预期状态,无需修改。");
|
||||
}
|
||||
|
||||
ScriptableObject.DestroyImmediate(managerInstance);
|
||||
}
|
||||
|
||||
private bool SetSettingValue(PropertyInfo indexer, object collection, string key, bool value)
|
||||
{
|
||||
object current = indexer.GetValue(collection, new object[] { key });
|
||||
if (current is bool b && b == value)
|
||||
return false;
|
||||
|
||||
indexer.SetValue(collection, value, new object[] { key });
|
||||
Debug.Log($"[NotificationAutoConfig] 修改 {key} = {value}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c4777ae7b66247243bd33ff202f7f4b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
/// <summary>
|
||||
/// Notification icon type.
|
||||
/// </summary>
|
||||
public enum NotificationIconType
|
||||
{
|
||||
/// <summary>
|
||||
/// Denotes small icon.
|
||||
/// </summary>
|
||||
Small = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Denotes large icon
|
||||
/// </summary>
|
||||
Large = 1,
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4598419a0a7a742fea832062d225b4b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Assets/TCJPLYRM1xJTSDK/ThirdParty/com.unity.mobile.notifications@2.3.2/Editor/NotificationSetting.cs
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
internal class NotificationSetting
|
||||
{
|
||||
public string Key;
|
||||
public string Label;
|
||||
public string Tooltip;
|
||||
public object Value;
|
||||
public bool WriteToPlist;
|
||||
|
||||
public List<NotificationSetting> Dependencies;
|
||||
|
||||
public NotificationSetting(string key, string label, string tooltip, object value, bool writeToPlist = true,
|
||||
List<NotificationSetting> dependencies = null)
|
||||
{
|
||||
this.Key = key;
|
||||
this.Label = label;
|
||||
this.Tooltip = tooltip;
|
||||
this.Value = value;
|
||||
this.WriteToPlist = writeToPlist;
|
||||
this.Dependencies = dependencies;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb2bc06c3d6c8474cb3af9bf67470a71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+300
@@ -0,0 +1,300 @@
|
||||
using Unity.Notifications.iOS;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
/// <summary>
|
||||
/// Class used to access notification settings for a specific platform.
|
||||
/// </summary>
|
||||
public class NotificationSettings
|
||||
{
|
||||
private static NotificationSetting GetSetting(BuildTargetGroup target, string key)
|
||||
{
|
||||
var manager = NotificationSettingsManager.Initialize();
|
||||
|
||||
NotificationSetting setting = null;
|
||||
if (target == BuildTargetGroup.Android)
|
||||
{
|
||||
setting = manager.AndroidNotificationSettingsFlat.Find(i => i.Key == key);
|
||||
}
|
||||
else if (target == BuildTargetGroup.iOS)
|
||||
{
|
||||
setting = manager.iOSNotificationSettingsFlat.Find(i => i.Key == key);
|
||||
}
|
||||
|
||||
return setting;
|
||||
}
|
||||
|
||||
private static void SetSettingValue<T>(BuildTargetGroup target, string key, T value)
|
||||
{
|
||||
var manager = NotificationSettingsManager.Initialize();
|
||||
|
||||
NotificationSetting setting = GetSetting(target, key);
|
||||
if (setting != null)
|
||||
{
|
||||
setting.Value = value;
|
||||
manager.SaveSetting(setting, target);
|
||||
}
|
||||
}
|
||||
|
||||
private static T GetSettingValue<T>(BuildTargetGroup target, string key)
|
||||
{
|
||||
var setting = GetSetting(target, key);
|
||||
return (T)setting.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class used to access Android-specific notification settings.
|
||||
/// </summary>
|
||||
public static class AndroidSettings
|
||||
{
|
||||
internal static readonly string RESCHEDULE_ON_RESTART = "UnityNotificationAndroidRescheduleOnDeviceRestart";
|
||||
internal static readonly string EXACT_ALARM = "UnityNotificationAndroidScheduleExactAlarms";
|
||||
internal static readonly string USE_CUSTOM_ACTIVITY = "UnityNotificationAndroidUseCustomActivity";
|
||||
internal static readonly string CUSTOM_ACTIVITY_CLASS = "UnityNotificationAndroidCustomActivityString";
|
||||
|
||||
/// <summary>
|
||||
/// By default AndroidSettings removes all scheduled notifications when the device is restarted. Enable this to automatically reschedule all non expired notifications when the device is turned back on.
|
||||
/// </summary>
|
||||
public static bool RescheduleOnDeviceRestart
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<bool>(BuildTargetGroup.Android, RESCHEDULE_ON_RESTART);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<bool>(BuildTargetGroup.Android, RESCHEDULE_ON_RESTART, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable this if you want to override the activity which will opened when the user click on the notification. By default activity assigned to `com.unity3d.player.UnityPlayer.currentActivity` will be used.
|
||||
/// </summary>
|
||||
public static bool UseCustomActivity
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<bool>(BuildTargetGroup.Android, USE_CUSTOM_ACTIVITY);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<bool>(BuildTargetGroup.Android, USE_CUSTOM_ACTIVITY, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The full class name of the activity that you wish to be assigned to the notification.
|
||||
/// </summary>
|
||||
public static string CustomActivityString
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<string>(BuildTargetGroup.Android, CUSTOM_ACTIVITY_CLASS);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<string>(BuildTargetGroup.Android, CUSTOM_ACTIVITY_CLASS, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A set of flags indicating whether to use exact scheduling and add supporting permissions.
|
||||
/// </summary>
|
||||
public static AndroidExactSchedulingOption ExactSchedulingOption
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<AndroidExactSchedulingOption>(BuildTargetGroup.Android, EXACT_ALARM);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<AndroidExactSchedulingOption>(BuildTargetGroup.Android, EXACT_ALARM, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add image to notification settings.
|
||||
/// </summary>
|
||||
/// <param name="id">Image identifier</param>
|
||||
/// <param name="image">Image texture, must be obtained from asset database</param>
|
||||
/// <param name="type">Image type</param>
|
||||
public static void AddDrawableResource(string id, Texture2D image, NotificationIconType type)
|
||||
{
|
||||
var manager = NotificationSettingsManager.Initialize();
|
||||
manager.AddDrawableResource(id, image, type);
|
||||
SettingsService.RepaintAllSettingsWindow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove icon at given index from notification settings.
|
||||
/// </summary>
|
||||
/// <param name="index">Index of image to remove</param>
|
||||
public static void RemoveDrawableResource(int index)
|
||||
{
|
||||
var manager = NotificationSettingsManager.Initialize();
|
||||
manager.RemoveDrawableResourceByIndex(index);
|
||||
SettingsService.RepaintAllSettingsWindow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove icon with given identifier from notification settings.
|
||||
/// </summary>
|
||||
/// <param name="id">ID of the image to remove</param>
|
||||
public static void RemoveDrawableResource(string id)
|
||||
{
|
||||
var manager = NotificationSettingsManager.Initialize();
|
||||
manager.RemoveDrawableResourceById(id);
|
||||
SettingsService.RepaintAllSettingsWindow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all images from notification settings.
|
||||
/// </summary>
|
||||
public static void ClearDrawableResources()
|
||||
{
|
||||
var manager = NotificationSettingsManager.Initialize();
|
||||
manager.ClearDrawableResources();
|
||||
SettingsService.RepaintAllSettingsWindow();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class used to access iOS-specific notification settings.
|
||||
/// </summary>
|
||||
public static class iOSSettings
|
||||
{
|
||||
internal static readonly string REQUEST_AUTH_ON_LAUNCH = "UnityNotificationRequestAuthorizationOnAppLaunch";
|
||||
internal static readonly string DEFAULT_AUTH_OPTS = "UnityNotificationDefaultAuthorizationOptions";
|
||||
internal static readonly string ADD_PUSH_CAPABILITY = "UnityAddRemoteNotificationCapability";
|
||||
internal static readonly string REQUEST_PUSH_AUTH_ON_LAUNCH = "UnityNotificationRequestAuthorizationForRemoteNotificationsOnAppLaunch";
|
||||
internal static readonly string PUSH_NOTIFICATION_PRESENTATION = "UnityRemoteNotificationForegroundPresentationOptions";
|
||||
internal static readonly string USE_APS_RELEASE = "UnityUseAPSReleaseEnvironment";
|
||||
internal static readonly string USE_LOCATION_TRIGGER = "UnityUseLocationNotificationTrigger";
|
||||
internal static readonly string ADD_TIME_SENSITIVE_ENTITLEMENT = "UnityAddTimeSensitiveEntitlement";
|
||||
|
||||
/// <summary>
|
||||
/// It's recommended to make the authorization request during the app's launch cycle. If this is enabled the user will be shown the authorization pop-up immediately when the app launches. If it’s unchecked you’ll need to manually create an AuthorizationRequest before your app can send or receive notifications.
|
||||
/// </summary>
|
||||
public static bool RequestAuthorizationOnAppLaunch
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<bool>(BuildTargetGroup.iOS, REQUEST_AUTH_ON_LAUNCH);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<bool>(BuildTargetGroup.iOS, REQUEST_AUTH_ON_LAUNCH, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure the notification interaction types your app will include in the authorisation request if RequestAuthorizationOnAppLaunch is enabled. Alternatively you can specify them when creating a `AuthorizationRequest` from a script.
|
||||
/// </summary>
|
||||
public static AuthorizationOption DefaultAuthorizationOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<AuthorizationOption>(BuildTargetGroup.iOS, DEFAULT_AUTH_OPTS);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<AuthorizationOption>(BuildTargetGroup.iOS, DEFAULT_AUTH_OPTS, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable this to add the push notification capability to you Xcode project.
|
||||
/// </summary>
|
||||
public static bool AddRemoteNotificationCapability
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<bool>(BuildTargetGroup.iOS, ADD_PUSH_CAPABILITY);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<bool>(BuildTargetGroup.iOS, ADD_PUSH_CAPABILITY, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this is enabled the app will automatically register your app with APNs after the launch which would enable it to receive remote notifications. You’ll have to manually create a AuthorizationRequest to get the device token.
|
||||
/// </summary>
|
||||
public static bool NotificationRequestAuthorizationForRemoteNotificationsOnAppLaunch
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<bool>(BuildTargetGroup.iOS, REQUEST_PUSH_AUTH_ON_LAUNCH);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<bool>(BuildTargetGroup.iOS, REQUEST_PUSH_AUTH_ON_LAUNCH, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The default presentation options for received remote notifications. In order for the specified presentation options to be used your app must had received the authorization to use them (the user might change it at any time).
|
||||
/// </summary>
|
||||
public static PresentationOption RemoteNotificationForegroundPresentationOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<PresentationOption>(BuildTargetGroup.iOS, PUSH_NOTIFICATION_PRESENTATION);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<PresentationOption>(BuildTargetGroup.iOS, PUSH_NOTIFICATION_PRESENTATION, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable this when signing the app with a production certificate.
|
||||
/// </summary>
|
||||
public static bool UseAPSReleaseEnvironment
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<bool>(BuildTargetGroup.iOS, USE_APS_RELEASE);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<bool>(BuildTargetGroup.iOS, USE_APS_RELEASE, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If you intend to use the iOSNotificationLocationTrigger in your notifications you must include the CoreLocation framework in your project.
|
||||
/// </summary>
|
||||
public static bool UseLocationNotificationTrigger
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<bool>(BuildTargetGroup.iOS, USE_LOCATION_TRIGGER);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<bool>(BuildTargetGroup.iOS, USE_LOCATION_TRIGGER, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add entitlement to enable notifications with time-sensitive interruption level.
|
||||
/// </summary>
|
||||
public static bool AddTimeSensitiveEntitlement
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetSettingValue<bool>(BuildTargetGroup.iOS, ADD_TIME_SENSITIVE_ENTITLEMENT);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetSettingValue<bool>(BuildTargetGroup.iOS, ADD_TIME_SENSITIVE_ENTITLEMENT, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af42dd3f8d8d54934ab3f4bdc740f0f1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
[Serializable]
|
||||
internal class NotificationSettingsCollection
|
||||
{
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("keys")]
|
||||
List<string> m_Keys;
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("values")]
|
||||
List<string> m_Values;
|
||||
|
||||
public NotificationSettingsCollection()
|
||||
{
|
||||
m_Keys = new List<string>();
|
||||
m_Values = new List<string>();
|
||||
}
|
||||
|
||||
public bool Contains(string key)
|
||||
{
|
||||
return m_Keys.Contains(key);
|
||||
}
|
||||
|
||||
public object this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
var index = m_Keys.IndexOf(key);
|
||||
if (index == -1 || m_Values.Count <= index)
|
||||
return null;
|
||||
|
||||
int intValue;
|
||||
if (int.TryParse(m_Values[index], out intValue))
|
||||
{
|
||||
return intValue;
|
||||
}
|
||||
|
||||
bool boolValue;
|
||||
if (bool.TryParse(m_Values[index], out boolValue))
|
||||
{
|
||||
return boolValue;
|
||||
}
|
||||
|
||||
return m_Values[index];
|
||||
}
|
||||
set
|
||||
{
|
||||
string strValue;
|
||||
|
||||
if (value is Enum)
|
||||
{
|
||||
strValue = ((int)value).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
strValue = value.ToString();
|
||||
}
|
||||
|
||||
var index = m_Keys.IndexOf(key);
|
||||
if (index == -1)
|
||||
{
|
||||
m_Keys.Add(key);
|
||||
m_Values.Add(strValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Values[index] = strValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 962a150b07e814ff0a531dd29ee67940
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+358
@@ -0,0 +1,358 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
using Unity.Notifications.iOS;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
[HelpURL("Packages/com.unity.mobile.notifications/documentation.html")]
|
||||
internal class NotificationSettingsManager : ScriptableObject
|
||||
{
|
||||
internal static readonly string k_SettingsPath = "ProjectSettings/NotificationsSettings.asset";
|
||||
|
||||
private static NotificationSettingsManager s_SettingsManager;
|
||||
|
||||
[FormerlySerializedAs("toolbarInt")]
|
||||
public int ToolbarIndex = 0;
|
||||
|
||||
public List<NotificationSetting> iOSNotificationSettings;
|
||||
public List<NotificationSetting> AndroidNotificationSettings;
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("iOSNotificationEditorSettingsValues")]
|
||||
private NotificationSettingsCollection m_iOSNotificationSettingsValues;
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("AndroidNotificationEditorSettingsValues")]
|
||||
private NotificationSettingsCollection m_AndroidNotificationSettingsValues;
|
||||
|
||||
[FormerlySerializedAs("TrackedResourceAssets")]
|
||||
public List<DrawableResourceData> DrawableResources = new List<DrawableResourceData>();
|
||||
|
||||
public List<NotificationSetting> iOSNotificationSettingsFlat
|
||||
{
|
||||
get
|
||||
{
|
||||
var target = new List<NotificationSetting>();
|
||||
FlattenList(iOSNotificationSettings, target);
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
public List<NotificationSetting> AndroidNotificationSettingsFlat
|
||||
{
|
||||
get
|
||||
{
|
||||
var target = new List<NotificationSetting>();
|
||||
FlattenList(AndroidNotificationSettings, target);
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
private void FlattenList(List<NotificationSetting> source, List<NotificationSetting> target)
|
||||
{
|
||||
foreach (var setting in source)
|
||||
{
|
||||
target.Add(setting);
|
||||
|
||||
if (setting.Dependencies != null)
|
||||
{
|
||||
FlattenList(setting.Dependencies, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static NotificationSettingsManager Initialize()
|
||||
{
|
||||
if (s_SettingsManager != null)
|
||||
return s_SettingsManager;
|
||||
|
||||
var settingsManager = CreateInstance<NotificationSettingsManager>();
|
||||
bool dirty = false;
|
||||
|
||||
if (File.Exists(k_SettingsPath))
|
||||
{
|
||||
var settingsJson = File.ReadAllText(k_SettingsPath);
|
||||
if (!string.IsNullOrEmpty(settingsJson))
|
||||
EditorJsonUtility.FromJsonOverwrite(settingsJson, settingsManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only migrate if there is no new settings asset under k_SettingsPath.
|
||||
dirty = MigrateFromLegacySettings(settingsManager);
|
||||
}
|
||||
|
||||
if (settingsManager.m_iOSNotificationSettingsValues == null)
|
||||
{
|
||||
settingsManager.m_iOSNotificationSettingsValues = new NotificationSettingsCollection();
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if (settingsManager.m_AndroidNotificationSettingsValues == null)
|
||||
{
|
||||
settingsManager.m_AndroidNotificationSettingsValues = new NotificationSettingsCollection();
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
// Create the settings for iOS.
|
||||
settingsManager.iOSNotificationSettings = new List<NotificationSetting>()
|
||||
{
|
||||
new NotificationSetting(
|
||||
NotificationSettings.iOSSettings.REQUEST_AUTH_ON_LAUNCH,
|
||||
"Request Authorization on App Launch",
|
||||
"It's recommended to make the authorization request during the app's launch cycle. If this is enabled the authorization pop-up will show up immediately during launching. Otherwise you need to manually create an AuthorizationRequest before sending or receiving notifications.",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.iOSSettings.REQUEST_AUTH_ON_LAUNCH, true, false),
|
||||
dependencies: new List<NotificationSetting>()
|
||||
{
|
||||
new NotificationSetting(
|
||||
NotificationSettings.iOSSettings.DEFAULT_AUTH_OPTS,
|
||||
"Default Notification Authorization Options",
|
||||
"Configure the notification interaction types which will be included in the authorization request if \"Request Authorization on App Launch\" is enabled.",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.iOSSettings.DEFAULT_AUTH_OPTS,
|
||||
AuthorizationOption.Alert | AuthorizationOption.Badge | AuthorizationOption.Sound, false)),
|
||||
}),
|
||||
new NotificationSetting(
|
||||
NotificationSettings.iOSSettings.ADD_PUSH_CAPABILITY,
|
||||
"Enable Push Notifications",
|
||||
"Enable this to add the push notification capability to the Xcode project, also to retrieve the device token from an AuthorizationRequest.",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.iOSSettings.ADD_PUSH_CAPABILITY, false, false),
|
||||
false,
|
||||
new List<NotificationSetting>()
|
||||
{
|
||||
new NotificationSetting(
|
||||
NotificationSettings.iOSSettings.REQUEST_PUSH_AUTH_ON_LAUNCH,
|
||||
"Register for Push Notifications on App Launch",
|
||||
"Enable this to automatically register your app with APNs after launching to receive remote notifications. You need to manually create an AuthorizationRequest to get the device token.",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.iOSSettings.REQUEST_PUSH_AUTH_ON_LAUNCH, false, false)),
|
||||
new NotificationSetting(
|
||||
NotificationSettings.iOSSettings.PUSH_NOTIFICATION_PRESENTATION,
|
||||
"Remote Notification Foreground Presentation Options",
|
||||
"Configure the default presentation options for received remote notifications. In order to use the specified presentation options, your app must have received the authorization (the user might change it at any time).",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.iOSSettings.PUSH_NOTIFICATION_PRESENTATION, (PresentationOption)iOSPresentationOption.All, false)),
|
||||
new NotificationSetting(NotificationSettings.iOSSettings.USE_APS_RELEASE,
|
||||
"Enable Release Environment for APS",
|
||||
"Enable this when signing the app with a production certificate.",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.iOSSettings.USE_APS_RELEASE, false, false),
|
||||
false),
|
||||
}),
|
||||
new NotificationSetting(NotificationSettings.iOSSettings.USE_LOCATION_TRIGGER,
|
||||
"Include CoreLocation Framework",
|
||||
"Include the CoreLocation framework to use the iOSNotificationLocationTrigger in your project.",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.iOSSettings.USE_LOCATION_TRIGGER, false, false),
|
||||
false),
|
||||
new NotificationSetting(NotificationSettings.iOSSettings.ADD_TIME_SENSITIVE_ENTITLEMENT,
|
||||
"Enable time sensitive notifications",
|
||||
"Enable to add entitlement for notifications with time sensitive interruption level",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.iOSSettings.ADD_TIME_SENSITIVE_ENTITLEMENT, false, false),
|
||||
false),
|
||||
};
|
||||
|
||||
// Create the settings for Android.
|
||||
settingsManager.AndroidNotificationSettings = new List<NotificationSetting>()
|
||||
{
|
||||
new NotificationSetting(
|
||||
NotificationSettings.AndroidSettings.RESCHEDULE_ON_RESTART,
|
||||
"Reschedule on Device Restart",
|
||||
"Enable this to automatically reschedule all non-expired notifications after device restart. By default AndroidSettings removes all scheduled notifications after restarting.",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.AndroidSettings.RESCHEDULE_ON_RESTART, false, true)),
|
||||
new NotificationSetting(
|
||||
NotificationSettings.AndroidSettings.EXACT_ALARM,
|
||||
"Schedule at exact time",
|
||||
"Whether notifications should appear at exact time or approximate",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.AndroidSettings.EXACT_ALARM, (AndroidExactSchedulingOption)0, true)),
|
||||
new NotificationSetting(
|
||||
NotificationSettings.AndroidSettings.USE_CUSTOM_ACTIVITY,
|
||||
"Use Custom Activity",
|
||||
"Enable this to override the activity which will be opened when the user taps the notification.",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.AndroidSettings.USE_CUSTOM_ACTIVITY, false, true),
|
||||
dependencies: new List<NotificationSetting>()
|
||||
{
|
||||
new NotificationSetting(
|
||||
NotificationSettings.AndroidSettings.CUSTOM_ACTIVITY_CLASS,
|
||||
"Custom Activity Name",
|
||||
"The full class name of the activity which will be assigned to the notification.",
|
||||
settingsManager.GetOrAddNotificationSettingValue(NotificationSettings.AndroidSettings.CUSTOM_ACTIVITY_CLASS, "com.unity3d.player.UnityPlayerActivity", true))
|
||||
})
|
||||
};
|
||||
|
||||
settingsManager.SaveSettings(dirty);
|
||||
|
||||
s_SettingsManager = settingsManager;
|
||||
return s_SettingsManager;
|
||||
}
|
||||
|
||||
private static bool MigrateFromLegacySettings(NotificationSettingsManager settingsManager)
|
||||
{
|
||||
const string k_LegacyAssetPath = "Assets/Editor/com.unity.mobile.notifications/NotificationSettings.asset";
|
||||
if (!File.Exists(k_LegacyAssetPath))
|
||||
return false;
|
||||
|
||||
var settingsManagerLegacy = AssetDatabase.LoadAssetAtPath<NotificationSettingsManager>(k_LegacyAssetPath);
|
||||
if (settingsManagerLegacy == null)
|
||||
return false;
|
||||
|
||||
settingsManager.ToolbarIndex = settingsManagerLegacy.ToolbarIndex;
|
||||
settingsManager.m_iOSNotificationSettingsValues = settingsManagerLegacy.m_iOSNotificationSettingsValues;
|
||||
settingsManager.m_AndroidNotificationSettingsValues = settingsManagerLegacy.m_AndroidNotificationSettingsValues;
|
||||
settingsManager.DrawableResources = settingsManagerLegacy.DrawableResources;
|
||||
|
||||
AssetDatabase.DeleteAsset(k_LegacyAssetPath);
|
||||
DeleteEmptyDirectoryAsset("Assets/Editor/com.unity.mobile.notifications");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void DeleteEmptyDirectoryAsset(string directory)
|
||||
{
|
||||
var directoryInfo = new DirectoryInfo(directory);
|
||||
if (!directoryInfo.Exists || directoryInfo.GetDirectories().Length > 0 || directoryInfo.GetFiles().Length > 0)
|
||||
return;
|
||||
|
||||
AssetDatabase.DeleteAsset(directory);
|
||||
}
|
||||
|
||||
private T GetOrAddNotificationSettingValue<T>(string key, T defaultValue, bool isAndroid)
|
||||
{
|
||||
var collection = isAndroid ? m_AndroidNotificationSettingsValues : m_iOSNotificationSettingsValues;
|
||||
|
||||
try
|
||||
{
|
||||
var value = collection[key];
|
||||
if (value != null)
|
||||
return (T)value;
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
Debug.LogWarning("Failed loading : " + key + " for type:" + defaultValue.GetType() + " Expected : " + collection[key].GetType());
|
||||
//Just return default value if it's a new setting that was not yet serialized.
|
||||
}
|
||||
|
||||
collection[key] = defaultValue;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void SaveSetting(NotificationSetting setting, BuildTargetGroup target)
|
||||
{
|
||||
var collection = (target == BuildTargetGroup.Android) ? m_AndroidNotificationSettingsValues : m_iOSNotificationSettingsValues;
|
||||
|
||||
if (!collection.Contains(setting.Key) || collection[setting.Key].ToString() != setting.Value.ToString())
|
||||
{
|
||||
collection[setting.Key] = setting.Value;
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveSettings(bool forceSave = true)
|
||||
{
|
||||
if (!forceSave && File.Exists(k_SettingsPath))
|
||||
return;
|
||||
|
||||
if (AssetDatabase.MakeEditable(k_SettingsPath))
|
||||
File.WriteAllText(k_SettingsPath, EditorJsonUtility.ToJson(this, true));
|
||||
else
|
||||
Debug.LogError($"Failed to make file {k_SettingsPath} editable");
|
||||
}
|
||||
|
||||
public void AddDrawableResource(string id, Texture2D image, NotificationIconType type)
|
||||
{
|
||||
/* commenting out for now, since you can have same Id's in editor
|
||||
foreach (var drawable in DrawableResources)
|
||||
{
|
||||
if (drawable.Id == id)
|
||||
{
|
||||
Debug.LogWarning("Drawable with Id"+id+" already exists, please assign another Id");
|
||||
return;
|
||||
}
|
||||
} */
|
||||
var drawableResource = new DrawableResourceData();
|
||||
drawableResource.Id = id;
|
||||
drawableResource.Type = type;
|
||||
drawableResource.Asset = image;
|
||||
|
||||
DrawableResources.Add(drawableResource);
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
public void RemoveDrawableResourceByIndex(int index)
|
||||
{
|
||||
if (index < DrawableResources.Count && index >= 0)
|
||||
{
|
||||
DrawableResources.RemoveAt(index);
|
||||
SaveSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Invalid drawable index provided, drawable not removed.");
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveDrawableResourceById(string id)
|
||||
{
|
||||
DrawableResourceData DrawableRes = null;
|
||||
foreach (var drawable in DrawableResources)
|
||||
{
|
||||
if (drawable.Id == id)
|
||||
{
|
||||
DrawableRes = drawable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (DrawableRes == null)
|
||||
{
|
||||
Debug.LogWarning("Drawable with Id " + id + " not found. Drawable not removed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawableResources.Remove(DrawableRes);
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearDrawableResources()
|
||||
{
|
||||
DrawableResources.Clear();
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
public Dictionary<string, byte[]> GenerateDrawableResourcesForExport()
|
||||
{
|
||||
var icons = new Dictionary<string, byte[]>();
|
||||
foreach (var drawableResource in DrawableResources)
|
||||
{
|
||||
if (!drawableResource.Verify())
|
||||
{
|
||||
Debug.LogWarning(string.Format("Failed exporting: '{0}' AndroidSettings notification icon because:\n {1} ",
|
||||
drawableResource.Id,
|
||||
drawableResource.GenerateErrorString()));
|
||||
continue;
|
||||
}
|
||||
|
||||
var texture = TextureAssetUtils.ProcessTextureForType(drawableResource.Asset, drawableResource.Type);
|
||||
|
||||
var scale = drawableResource.Type == NotificationIconType.Small ? 0.375f : 1;
|
||||
|
||||
var textXhdpi = TextureAssetUtils.ScaleTexture(texture, (int)(128 * scale), (int)(128 * scale));
|
||||
var textHdpi = TextureAssetUtils.ScaleTexture(texture, (int)(96 * scale), (int)(96 * scale));
|
||||
var textMdpi = TextureAssetUtils.ScaleTexture(texture, (int)(64 * scale), (int)(64 * scale));
|
||||
var textLdpi = TextureAssetUtils.ScaleTexture(texture, (int)(48 * scale), (int)(48 * scale));
|
||||
|
||||
icons[string.Format("drawable-xhdpi-v11/{0}.png", drawableResource.Id)] = textXhdpi.EncodeToPNG();
|
||||
icons[string.Format("drawable-hdpi-v11/{0}.png", drawableResource.Id)] = textHdpi.EncodeToPNG();
|
||||
icons[string.Format("drawable-mdpi-v11/{0}.png", drawableResource.Id)] = textMdpi.EncodeToPNG();
|
||||
icons[string.Format("drawable-ldpi-v11/{0}.png", drawableResource.Id)] = textLdpi.EncodeToPNG();
|
||||
|
||||
if (drawableResource.Type == NotificationIconType.Large)
|
||||
{
|
||||
var textXxhdpi = TextureAssetUtils.ScaleTexture(texture, (int)(192 * scale), (int)(192 * scale));
|
||||
icons[string.Format("drawable-xxhdpi-v11/{0}.png", drawableResource.Id)] = textXxhdpi.EncodeToPNG();
|
||||
}
|
||||
}
|
||||
|
||||
return icons;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0863bf92b4fcc45b0b9267325249bf0f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using Unity.Notifications.iOS;
|
||||
using UnityEngine.Assertions;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
internal class NotificationSettingsProvider : SettingsProvider
|
||||
{
|
||||
private const int k_SlotSize = 64;
|
||||
private const int k_IconSpacing = 8;
|
||||
private const float k_Padding = 12f;
|
||||
private const float k_ToolbarHeight = 20f;
|
||||
private const int k_VerticalSeparator = 2;
|
||||
private const int k_LabelLineHeight = 18;
|
||||
|
||||
private readonly GUIContent k_IdentifierLabelText = new GUIContent("Identifier");
|
||||
private readonly GUIContent k_TypeLabelText = new GUIContent("Type");
|
||||
|
||||
private readonly string[] k_ToolbarStrings = { "Android", "iOS" };
|
||||
private const string k_InfoStringAndroid =
|
||||
"Only icons added to this list or manually added to the 'res/drawable' folder can be used for notifications.\n" +
|
||||
"Note, that not all devices support colored icons.\n\n" +
|
||||
"Small icons must be at least 48x48px and only composed of white pixels on a transparent background.\n" +
|
||||
"Large icons must be no smaller than 192x192px and may contain colors.";
|
||||
|
||||
private NotificationSettingsManager m_SettingsManager;
|
||||
|
||||
private SerializedObject m_SettingsManagerObject;
|
||||
private SerializedProperty m_DrawableResources;
|
||||
|
||||
private Vector2 m_ScrollViewStart;
|
||||
private ReorderableList m_ReorderableList;
|
||||
|
||||
private NotificationSettingsProvider(string path, SettingsScope scopes)
|
||||
: base(path, scopes)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
[SettingsProvider]
|
||||
static SettingsProvider CreateMobileNotificationsSettingsProvider()
|
||||
{
|
||||
return new NotificationSettingsProvider("Project/Mobile Notifications", SettingsScope.Project);
|
||||
}
|
||||
|
||||
public override void OnActivate(string searchContext, VisualElement rootElement)
|
||||
{
|
||||
base.OnActivate(searchContext, rootElement);
|
||||
// in case of domain reload (enter-exit play mode, this gets lost)
|
||||
if (m_SettingsManager == null)
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public override void OnDeactivate()
|
||||
{
|
||||
base.OnDeactivate();
|
||||
m_SettingsManager.SaveSettings(false);
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
label = "Mobile Notifications";
|
||||
m_SettingsManager = NotificationSettingsManager.Initialize();
|
||||
|
||||
// These two are for ReorderableList.
|
||||
m_SettingsManagerObject = new SerializedObject(m_SettingsManager);
|
||||
m_DrawableResources = m_SettingsManagerObject.FindProperty("DrawableResources");
|
||||
|
||||
// ReorderableList is only used to draw the drawable resources for Android settings.
|
||||
InitReorderableList();
|
||||
|
||||
Undo.undoRedoPerformed += () =>
|
||||
{
|
||||
m_SettingsManagerObject.UpdateIfRequiredOrScript();
|
||||
Repaint();
|
||||
};
|
||||
}
|
||||
|
||||
private void InitReorderableList()
|
||||
{
|
||||
m_ReorderableList = new ReorderableList(m_SettingsManagerObject, m_DrawableResources, false, false, true, true);
|
||||
m_ReorderableList.elementHeight = k_SlotSize + k_IconSpacing;
|
||||
m_ReorderableList.showDefaultBackground = true;
|
||||
m_ReorderableList.headerHeight = 1;
|
||||
|
||||
// Register all the necessary callbacks on ReorderableList.
|
||||
m_ReorderableList.onAddCallback = (list) =>
|
||||
{
|
||||
Undo.RegisterCompleteObjectUndo(m_SettingsManager, "Add a new icon element");
|
||||
m_SettingsManager.AddDrawableResource(string.Format("icon_{0}", m_SettingsManager.DrawableResources.Count), null, NotificationIconType.Small);
|
||||
};
|
||||
|
||||
m_ReorderableList.onRemoveCallback = (list) =>
|
||||
{
|
||||
m_SettingsManager.RemoveDrawableResourceByIndex(list.index);
|
||||
};
|
||||
|
||||
m_ReorderableList.onCanAddCallback = (list) =>
|
||||
{
|
||||
var trackedAssets = m_SettingsManager.DrawableResources;
|
||||
if (trackedAssets.Count <= 0)
|
||||
return true;
|
||||
|
||||
return trackedAssets.All(asset => asset.Initialized());
|
||||
};
|
||||
|
||||
m_ReorderableList.drawElementCallback = (rect, index, active, focused) => DrawIconDataElement(rect, index, active, focused);
|
||||
|
||||
m_ReorderableList.drawElementBackgroundCallback = (rect, index, active, focused) =>
|
||||
{
|
||||
if (Event.current.type != EventType.Repaint)
|
||||
return;
|
||||
|
||||
var background = index % 2 == 0 ? NotificationStyles.k_EvenRow : NotificationStyles.k_OddRow;
|
||||
background.Draw(rect, false, false, false, false);
|
||||
|
||||
ReorderableList.defaultBehaviours.DrawElementBackground(rect, index, active, focused, true);
|
||||
};
|
||||
|
||||
m_ReorderableList.elementHeightCallback = (index) =>
|
||||
{
|
||||
var data = GetDrawableResource(index);
|
||||
if (data == null)
|
||||
return k_SlotSize;
|
||||
|
||||
return m_ReorderableList.elementHeight + (data.Asset != null && !data.IsValid ? k_SlotSize : 0);
|
||||
};
|
||||
}
|
||||
|
||||
private void DrawIconDataElement(Rect rect, int index, bool active, bool focused)
|
||||
{
|
||||
var drawableResource = GetDrawableResource(index);
|
||||
if (drawableResource == null)
|
||||
return;
|
||||
|
||||
var elementRect = AddPadding(rect, k_Padding, k_Padding / 2);
|
||||
|
||||
// Calculate and draw id and type.
|
||||
var idLabelRect = new Rect(elementRect.x, elementRect.y, k_SlotSize, k_ToolbarHeight);
|
||||
var idTextFieldRect = new Rect(idLabelRect.x + k_SlotSize, idLabelRect.y, k_SlotSize, k_ToolbarHeight);
|
||||
|
||||
var typeLabelRect = new Rect(elementRect.x, elementRect.y + 25, k_SlotSize, k_ToolbarHeight);
|
||||
var typeEnumPopupRect = new Rect(typeLabelRect.x + k_SlotSize, typeLabelRect.y, k_SlotSize, k_ToolbarHeight);
|
||||
|
||||
EditorGUI.LabelField(idLabelRect, k_IdentifierLabelText);
|
||||
var newId = EditorGUI.TextField(idTextFieldRect, drawableResource.Id);
|
||||
|
||||
EditorGUI.LabelField(typeLabelRect, k_TypeLabelText);
|
||||
var newType = (NotificationIconType)EditorGUI.EnumPopup(typeEnumPopupRect, drawableResource.Type);
|
||||
|
||||
// Calculate and draw texture and preview.
|
||||
var textureX = Mathf.Max(elementRect.width - (k_SlotSize * 2 - k_IconSpacing * 5), k_SlotSize * 3);
|
||||
var textureRect = new Rect(textureX, elementRect.y, k_SlotSize, k_SlotSize);
|
||||
var previewTextureRect = new Rect(textureRect.x + k_SlotSize, textureRect.y - 6, k_SlotSize, k_SlotSize);
|
||||
|
||||
var newAsset = (Texture2D)EditorGUI.ObjectField(textureRect, drawableResource.Asset, typeof(Texture2D), false);
|
||||
|
||||
// Check if the texture has been updated.
|
||||
bool updatePreviewTexture = (newId != drawableResource.Id || newType != drawableResource.Type || newAsset != drawableResource.Asset);
|
||||
if (updatePreviewTexture)
|
||||
{
|
||||
Undo.RegisterCompleteObjectUndo(m_SettingsManager, "Update icon data");
|
||||
drawableResource.Id = newId;
|
||||
drawableResource.Type = newType;
|
||||
drawableResource.Asset = newAsset;
|
||||
drawableResource.Clean();
|
||||
drawableResource.Verify();
|
||||
m_SettingsManager.SaveSettings();
|
||||
}
|
||||
|
||||
if (drawableResource.Asset != null && !drawableResource.Verify())
|
||||
{
|
||||
var errorMsgWidth = rect.width - k_Padding * 2;
|
||||
var errorRect = AddPadding(new Rect(elementRect.x, elementRect.y + k_SlotSize, errorMsgWidth, k_LabelLineHeight * 3), 4, 4);
|
||||
|
||||
var errorMsg = "Specified texture can't be used because: \n" + drawableResource.GenerateErrorString();
|
||||
EditorGUI.HelpBox(errorRect, errorMsg, MessageType.Error);
|
||||
|
||||
GUI.Box(previewTextureRect, "Preview not available", NotificationStyles.k_PreviewMessageTextStyle);
|
||||
}
|
||||
else
|
||||
{
|
||||
var previewTexture = drawableResource.GetPreviewTexture(updatePreviewTexture);
|
||||
if (previewTexture != null)
|
||||
{
|
||||
previewTexture.alphaIsTransparency = false;
|
||||
|
||||
EditorGUI.LabelField(previewTextureRect, "Preview", NotificationStyles.k_PreviewLabelTextStyle);
|
||||
|
||||
var previewTextureRectPadded = AddPadding(previewTextureRect, 6f, 6f);
|
||||
previewTextureRectPadded.y += 8;
|
||||
GUI.DrawTexture(previewTextureRectPadded, previewTexture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DrawableResourceData GetDrawableResource(int index)
|
||||
{
|
||||
var resourceAssets = m_SettingsManager.DrawableResources;
|
||||
if (index < resourceAssets.Count)
|
||||
return resourceAssets[index];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Rect AddPadding(Rect rect, float horizontal, float vertical)
|
||||
{
|
||||
Rect paddingRect = rect;
|
||||
paddingRect.xMin += horizontal;
|
||||
paddingRect.xMax -= horizontal;
|
||||
paddingRect.yMin += vertical;
|
||||
paddingRect.yMax -= vertical;
|
||||
|
||||
return paddingRect;
|
||||
}
|
||||
|
||||
public override void OnGUI(string searchContext)
|
||||
{
|
||||
if (m_SettingsManager == null)
|
||||
Initialize();
|
||||
|
||||
// This has to be called to sync all the changes between m_SettingsManager and m_SettingsManagerObject.
|
||||
if (m_SettingsManagerObject.targetObject != null)
|
||||
m_SettingsManagerObject.Update();
|
||||
|
||||
var noHeightRect = GUILayoutUtility.GetRect(GUIContent.none, EditorStyles.label, GUILayout.ExpandWidth(true), GUILayout.Height(0));
|
||||
var width = noHeightRect.width;
|
||||
|
||||
var totalRect = new Rect(k_Padding, 0f, width - k_Padding, Screen.height);
|
||||
|
||||
// Draw the toolbar for Android/iOS.
|
||||
var toolBarRect = new Rect(totalRect.x, totalRect.y, totalRect.width, k_ToolbarHeight);
|
||||
var toolbarIndex = GUI.Toolbar(toolBarRect, m_SettingsManager.ToolbarIndex, k_ToolbarStrings);
|
||||
if (toolbarIndex != m_SettingsManager.ToolbarIndex)
|
||||
{
|
||||
m_SettingsManager.ToolbarIndex = toolbarIndex;
|
||||
m_SettingsManager.SaveSettings();
|
||||
}
|
||||
|
||||
var notificationSettingsRect = new Rect(totalRect.x, k_ToolbarHeight + 2, totalRect.width, totalRect.height - k_ToolbarHeight - k_Padding);
|
||||
|
||||
// Draw the notification settings.
|
||||
int drawnSettingsCount = DrawNotificationSettings(notificationSettingsRect, m_SettingsManager.ToolbarIndex);
|
||||
if (drawnSettingsCount <= 0)
|
||||
return;
|
||||
|
||||
float heightPlaceHolder = k_SlotSize;
|
||||
|
||||
// Draw drawable resources list for Android.
|
||||
if (m_SettingsManager.ToolbarIndex == 0)
|
||||
{
|
||||
var iconListlabelRect = new Rect(notificationSettingsRect.x, notificationSettingsRect.y + 85, 180, k_LabelLineHeight);
|
||||
GUI.Label(iconListlabelRect, "Notification Icons", EditorStyles.label);
|
||||
|
||||
// Draw the help message for setting the icons.
|
||||
float labelHeight;
|
||||
if (notificationSettingsRect.width > 510)
|
||||
labelHeight = k_LabelLineHeight * 4;
|
||||
else if (notificationSettingsRect.width > 500)
|
||||
labelHeight = k_LabelLineHeight * 5;
|
||||
else
|
||||
labelHeight = k_LabelLineHeight * 6;
|
||||
var iconListMsgRect = new Rect(iconListlabelRect.x, iconListlabelRect.y + iconListlabelRect.height + k_VerticalSeparator, notificationSettingsRect.width, labelHeight);
|
||||
EditorGUI.SelectableLabel(iconListMsgRect, k_InfoStringAndroid, NotificationStyles.k_IconHelpMessageStyle);
|
||||
|
||||
// Draw the reorderable list for the icon list.
|
||||
var iconListRect = new Rect(iconListMsgRect.x, iconListMsgRect.y + iconListMsgRect.height + k_VerticalSeparator, iconListMsgRect.width, notificationSettingsRect.height - 55f);
|
||||
m_ReorderableList.DoList(iconListRect);
|
||||
|
||||
heightPlaceHolder += iconListMsgRect.height + m_ReorderableList.GetHeight();
|
||||
}
|
||||
|
||||
// We have to do this to occupy the space that ScrollView can set the scrollbars correctly.
|
||||
EditorGUILayout.GetControlRect(true, heightPlaceHolder, GUILayout.MinWidth(width));
|
||||
}
|
||||
|
||||
private int DrawNotificationSettings(Rect rect, int toolbarIndex)
|
||||
{
|
||||
Assert.IsTrue(toolbarIndex == 0 || toolbarIndex == 1);
|
||||
|
||||
List<NotificationSetting> settings;
|
||||
BuildTargetGroup buildTarget;
|
||||
int labelWidthMultiplier;
|
||||
if (toolbarIndex == 0)
|
||||
{
|
||||
settings = m_SettingsManager.AndroidNotificationSettings;
|
||||
buildTarget = BuildTargetGroup.Android;
|
||||
labelWidthMultiplier = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
settings = m_SettingsManager.iOSNotificationSettings;
|
||||
buildTarget = BuildTargetGroup.iOS;
|
||||
labelWidthMultiplier = 5;
|
||||
}
|
||||
|
||||
if (settings == null)
|
||||
return 0;
|
||||
|
||||
GUI.BeginGroup(rect);
|
||||
var drawnSettingsCount = DrawSettingElements(rect, buildTarget, settings, false, 0, labelWidthMultiplier);
|
||||
GUI.EndGroup();
|
||||
|
||||
return drawnSettingsCount;
|
||||
}
|
||||
|
||||
private int DrawSettingElements(Rect rect, BuildTargetGroup buildTarget, List<NotificationSetting> settings, bool disabled, int layer, int labelWidthMultiplier)
|
||||
{
|
||||
var spaceOffset = layer * 13;
|
||||
|
||||
var labelStyle = new GUIStyle(NotificationStyles.k_LabelStyle);
|
||||
labelStyle.fixedWidth = k_SlotSize * labelWidthMultiplier - spaceOffset;
|
||||
|
||||
var toggleStyle = NotificationStyles.k_ToggleStyle;
|
||||
var dropdownStyle = NotificationStyles.k_DropwDownStyle;
|
||||
|
||||
int elementCount = settings.Count;
|
||||
foreach (var setting in settings)
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(disabled);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Space(spaceOffset);
|
||||
|
||||
GUILayout.Label(new GUIContent(setting.Label, setting.Tooltip), labelStyle);
|
||||
|
||||
bool dependenciesDisabled = false;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
if (setting.Value.GetType() == typeof(bool))
|
||||
{
|
||||
setting.Value = EditorGUILayout.Toggle((bool)setting.Value, toggleStyle);
|
||||
dependenciesDisabled = !(bool)setting.Value;
|
||||
}
|
||||
else if (setting.Value.GetType() == typeof(string))
|
||||
{
|
||||
setting.Value = EditorGUILayout.TextField((string)setting.Value);
|
||||
}
|
||||
else if (setting.Value.GetType() == typeof(PresentationOption))
|
||||
{
|
||||
setting.Value = (PresentationOption)EditorGUILayout.EnumFlagsField((iOSPresentationOption)setting.Value, dropdownStyle);
|
||||
}
|
||||
else if (setting.Value.GetType() == typeof(AuthorizationOption))
|
||||
{
|
||||
setting.Value = (AuthorizationOption)EditorGUILayout.EnumFlagsField((iOSAuthorizationOption)setting.Value, dropdownStyle);
|
||||
if ((iOSAuthorizationOption)setting.Value == 0)
|
||||
setting.Value = (AuthorizationOption)(iOSAuthorizationOption.Badge | iOSAuthorizationOption.Sound | iOSAuthorizationOption.Alert);
|
||||
}
|
||||
else if (setting.Value.GetType() == typeof(AndroidExactSchedulingOption))
|
||||
{
|
||||
setting.Value = (AndroidExactSchedulingOption)EditorGUILayout.EnumFlagsField((AndroidExactSchedulingOption)setting.Value, dropdownStyle);
|
||||
}
|
||||
else
|
||||
Debug.LogError("Unsupported setting type: " + setting.Value.GetType());
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
m_SettingsManager.SaveSetting(setting, buildTarget);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
if (setting.Dependencies != null)
|
||||
{
|
||||
elementCount += DrawSettingElements(rect, buildTarget, setting.Dependencies, dependenciesDisabled, layer + 1, labelWidthMultiplier);
|
||||
}
|
||||
}
|
||||
|
||||
return elementCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8f51a1ea13c0461f8868c187d4ca482
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
internal class NotificationStyles
|
||||
{
|
||||
public static readonly GUIStyle k_EvenRow = new GUIStyle("CN EntryBackEven");
|
||||
public static readonly GUIStyle k_OddRow = new GUIStyle("CN EntryBackOdd");
|
||||
public static readonly GUIStyle k_PreviewMessageTextStyle = new GUIStyle(GUI.skin.label) { fontSize = 8, wordWrap = true, alignment = TextAnchor.MiddleCenter };
|
||||
public static readonly GUIStyle k_PreviewLabelTextStyle = new GUIStyle(GUI.skin.label) { fontSize = 8, wordWrap = true, alignment = TextAnchor.UpperCenter };
|
||||
public static readonly GUIStyle k_IconHelpMessageStyle = new GUIStyle(GUI.skin.GetStyle("HelpBox")) { fontSize = 10, wordWrap = true, alignment = TextAnchor.UpperLeft };
|
||||
public static readonly GUIStyle k_ToggleStyle = new GUIStyle(GUI.skin.GetStyle("Toggle")) { alignment = TextAnchor.MiddleRight };
|
||||
public static readonly GUIStyle k_DropwDownStyle = new GUIStyle(GUI.skin.GetStyle("Button")) { alignment = TextAnchor.MiddleLeft };
|
||||
public static readonly GUIStyle k_LabelStyle = new GUIStyle(GUI.skin.GetStyle("Label")) { wordWrap = true };
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d20e68231df79a46be46dfc6d6e8580
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Vendored
+118
@@ -0,0 +1,118 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
internal static class TextureAssetUtils
|
||||
{
|
||||
public static bool VerifyTextureByType(Texture2D texture, NotificationIconType type, out List<string> errors)
|
||||
{
|
||||
errors = new List<string>();
|
||||
|
||||
if (texture == null)
|
||||
{
|
||||
errors.Add("Texture is invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
var needsAlpha = true;
|
||||
var minSize = 48;
|
||||
|
||||
if (type == NotificationIconType.Large)
|
||||
{
|
||||
needsAlpha = false;
|
||||
minSize = 192;
|
||||
}
|
||||
|
||||
var isSquare = texture.width == texture.height;
|
||||
var isLargeEnough = texture.width >= minSize;
|
||||
var hasAlpha = true;// TODO: texture.format == TextureFormat.Alpha8;
|
||||
|
||||
var isReadable = texture.isReadable;
|
||||
|
||||
if (!isReadable)
|
||||
{
|
||||
errors.Add("Read/Write is not enabled in the texture importer");
|
||||
}
|
||||
|
||||
if (!isLargeEnough)
|
||||
errors.Add(string.Format("Texture must be at least {0}x{1} pixels (while it's {2}x{3})",
|
||||
minSize,
|
||||
minSize,
|
||||
texture.width,
|
||||
texture.height
|
||||
));
|
||||
|
||||
if (!isSquare)
|
||||
errors.Add(string.Format("Texture must have the same width and height (while it's {0}x{1})",
|
||||
texture.width,
|
||||
texture.height
|
||||
));
|
||||
|
||||
if (!hasAlpha && needsAlpha)
|
||||
errors.Add(string.Format("Texture must contain an alpha channel"));
|
||||
|
||||
return isReadable && isSquare && isLargeEnough && (!needsAlpha || hasAlpha);
|
||||
}
|
||||
|
||||
public static Texture2D ProcessTextureForType(Texture2D sourceTexture, NotificationIconType type)
|
||||
{
|
||||
if (sourceTexture == null)
|
||||
return null;
|
||||
|
||||
string assetPath = AssetDatabase.GetAssetPath(sourceTexture);
|
||||
var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
|
||||
|
||||
if (importer == null || !importer.isReadable)
|
||||
return null;
|
||||
|
||||
Texture2D texture;
|
||||
if (type == NotificationIconType.Small)
|
||||
{
|
||||
texture = new Texture2D(sourceTexture.width, sourceTexture.height, TextureFormat.RGBA32, true, false);
|
||||
for (var i = 0; i < sourceTexture.mipmapCount; i++)
|
||||
{
|
||||
var c_0 = sourceTexture.GetPixels(i);
|
||||
var c_1 = texture.GetPixels(i);
|
||||
for (var i1 = 0; i1 < c_0.Length; i1++)
|
||||
{
|
||||
var a = c_0[i1].r + c_0[i1].g + c_0[i1].b;
|
||||
c_1[i1].r = c_1[i1].g = c_1[i1].b = a > 127 ? 0 : 1;
|
||||
c_1[i1].a = c_0[i1].a;
|
||||
}
|
||||
texture.SetPixels(c_1, i);
|
||||
}
|
||||
texture.Apply();
|
||||
}
|
||||
else
|
||||
{
|
||||
texture = new Texture2D(sourceTexture.width, sourceTexture.height, TextureFormat.RGBA32, true);
|
||||
texture.SetPixels(sourceTexture.GetPixels());
|
||||
texture.Apply();
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
public static Texture2D ScaleTexture(Texture2D sourceTexture, int width, int height)
|
||||
{
|
||||
if (sourceTexture.width == width && sourceTexture.height == height)
|
||||
return sourceTexture;
|
||||
|
||||
var result = new Texture2D(width, height, TextureFormat.ARGB32, false);
|
||||
|
||||
var destPixels = new Color[width * height];
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
for (int x = 0; x < width; ++x)
|
||||
{
|
||||
destPixels[y * width + x] = sourceTexture.GetPixelBilinear((float)x / (float)width, (float)y / (float)height);
|
||||
}
|
||||
}
|
||||
result.SetPixels(destPixels);
|
||||
result.Apply();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b9bfb8ad48d04ce5af3878b61cb8904
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Unity.Notifications",
|
||||
"references": [
|
||||
"Unity.Notifications.iOS",
|
||||
"Unity.Notifications.Android"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85a7f7b2e1fe24ff2b4c8b5d1a746334
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
[Flags]
|
||||
internal enum iOSAuthorizationOption
|
||||
{
|
||||
Default = 0,
|
||||
Badge = 1 << 0,
|
||||
Sound = 1 << 1,
|
||||
Alert = 1 << 2,
|
||||
CarPlay = 1 << 3,
|
||||
CriticalAlert = 1 << 4,
|
||||
ProvidesAppNotificationSettings = 1 << 5,
|
||||
Provisional = 1 << 6,
|
||||
All = ~0,
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 396d27f7ef9dc419ab240e8ea0135a26
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
#if UNITY_IOS
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Callbacks;
|
||||
using UnityEditor.iOS.Xcode;
|
||||
using UnityEngine;
|
||||
using Unity.Notifications;
|
||||
using Unity.Notifications.iOS;
|
||||
|
||||
public class iOSNotificationPostProcessor : MonoBehaviour
|
||||
{
|
||||
[PostProcessBuild]
|
||||
public static void OnPostprocessBuild(BuildTarget buildTarget, string path)
|
||||
{
|
||||
if (buildTarget != BuildTarget.iOS)
|
||||
return;
|
||||
|
||||
// Check if we have the minimal iOS version set.
|
||||
bool hasMinOSVersion;
|
||||
try
|
||||
{
|
||||
var requiredVersion = new Version(10, 0);
|
||||
var currentVersion = new Version(PlayerSettings.iOS.targetOSVersionString);
|
||||
hasMinOSVersion = currentVersion >= requiredVersion;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
hasMinOSVersion = false;
|
||||
}
|
||||
|
||||
if (!hasMinOSVersion)
|
||||
Debug.Log("UserNotifications framework is only available on iOS 10.0+, please make sure that you set a correct `Target minimum iOS Version` in Player Settings.");
|
||||
|
||||
var settings = NotificationSettingsManager.Initialize().iOSNotificationSettingsFlat;
|
||||
|
||||
var needLocationFramework = (bool)settings.Find(i => i.Key == NotificationSettings.iOSSettings.USE_LOCATION_TRIGGER).Value;
|
||||
var addPushNotificationCapability = (bool)settings.Find(i => i.Key == NotificationSettings.iOSSettings.ADD_PUSH_CAPABILITY).Value;
|
||||
var addTimeSensitiveEntitlement = (bool)settings.Find(i => i.Key == NotificationSettings.iOSSettings.ADD_TIME_SENSITIVE_ENTITLEMENT).Value;
|
||||
|
||||
var useReleaseAPSEnv = false;
|
||||
if (addPushNotificationCapability)
|
||||
{
|
||||
var useReleaseAPSEnvSetting = settings.Find(i => i.Key == NotificationSettings.iOSSettings.USE_APS_RELEASE);
|
||||
if (useReleaseAPSEnvSetting != null)
|
||||
useReleaseAPSEnv = (bool)useReleaseAPSEnvSetting.Value;
|
||||
}
|
||||
|
||||
PatchPBXProject(path, needLocationFramework, addPushNotificationCapability, useReleaseAPSEnv, addTimeSensitiveEntitlement);
|
||||
PatchPlist(path, settings, addPushNotificationCapability);
|
||||
PatchPreprocessor(path, needLocationFramework, addPushNotificationCapability);
|
||||
}
|
||||
|
||||
private static void PatchPBXProject(string path, bool needLocationFramework, bool addPushNotificationCapability, bool useReleaseAPSEnv, bool addTimeSensitiveEntitlement)
|
||||
{
|
||||
var pbxProjectPath = PBXProject.GetPBXProjectPath(path);
|
||||
|
||||
var needsToWriteChanges = false;
|
||||
|
||||
var pbxProject = new PBXProject();
|
||||
pbxProject.ReadFromString(File.ReadAllText(pbxProjectPath));
|
||||
|
||||
string mainTarget;
|
||||
string unityFrameworkTarget;
|
||||
|
||||
var unityMainTargetGuidMethod = pbxProject.GetType().GetMethod("GetUnityMainTargetGuid");
|
||||
var unityFrameworkTargetGuidMethod = pbxProject.GetType().GetMethod("GetUnityFrameworkTargetGuid");
|
||||
|
||||
if (unityMainTargetGuidMethod != null && unityFrameworkTargetGuidMethod != null)
|
||||
{
|
||||
mainTarget = (string)unityMainTargetGuidMethod.Invoke(pbxProject, null);
|
||||
unityFrameworkTarget = (string)unityFrameworkTargetGuidMethod.Invoke(pbxProject, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
mainTarget = pbxProject.TargetGuidByName("Unity-iPhone");
|
||||
unityFrameworkTarget = mainTarget;
|
||||
}
|
||||
|
||||
// Add necessary frameworks.
|
||||
if (!pbxProject.ContainsFramework(unityFrameworkTarget, "UserNotifications.framework"))
|
||||
{
|
||||
pbxProject.AddFrameworkToProject(unityFrameworkTarget, "UserNotifications.framework", true);
|
||||
needsToWriteChanges = true;
|
||||
}
|
||||
if (needLocationFramework && !pbxProject.ContainsFramework(unityFrameworkTarget, "CoreLocation.framework"))
|
||||
{
|
||||
pbxProject.AddFrameworkToProject(unityFrameworkTarget, "CoreLocation.framework", false);
|
||||
needsToWriteChanges = true;
|
||||
}
|
||||
|
||||
if (needsToWriteChanges)
|
||||
File.WriteAllText(pbxProjectPath, pbxProject.WriteToString());
|
||||
|
||||
var entitlementsFileName = pbxProject.GetBuildPropertyForAnyConfig(mainTarget, "CODE_SIGN_ENTITLEMENTS");
|
||||
if (entitlementsFileName == null)
|
||||
{
|
||||
var bundleIdentifier = PlayerSettings.GetApplicationIdentifier(BuildTargetGroup.iOS);
|
||||
entitlementsFileName = string.Format("{0}.entitlements", bundleIdentifier.Substring(bundleIdentifier.LastIndexOf(".") + 1));
|
||||
}
|
||||
|
||||
// Update the entitlements file.
|
||||
if (addPushNotificationCapability)
|
||||
{
|
||||
var capManager = new ProjectCapabilityManager(pbxProjectPath, entitlementsFileName, "Unity-iPhone");
|
||||
capManager.AddPushNotifications(!useReleaseAPSEnv);
|
||||
capManager.WriteToFile();
|
||||
}
|
||||
|
||||
if (addTimeSensitiveEntitlement)
|
||||
{
|
||||
var entitlementsFile = new PlistDocument();
|
||||
var entitlementsFilePath = Path.Combine(path, entitlementsFileName);
|
||||
if (File.Exists(entitlementsFilePath))
|
||||
entitlementsFile.ReadFromFile(entitlementsFilePath);
|
||||
var entitlement = entitlementsFile.root["com.apple.developer.usernotifications.time-sensitive"] as PlistElementBoolean;
|
||||
if (entitlement == null || entitlement.AsBoolean() == false)
|
||||
{
|
||||
entitlementsFile.root["com.apple.developer.usernotifications.time-sensitive"] = new PlistElementBoolean(true);
|
||||
entitlementsFile.WriteToFile(entitlementsFilePath);
|
||||
}
|
||||
if (pbxProject.GetBuildPropertyForAnyConfig(mainTarget, "CODE_SIGN_ENTITLEMENTS") == null)
|
||||
{
|
||||
pbxProject.AddBuildProperty(mainTarget, "CODE_SIGN_ENTITLEMENTS", entitlementsFileName);
|
||||
pbxProject.WriteToFile(pbxProjectPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void PatchPlist(string path, List<Unity.Notifications.NotificationSetting> settings, bool addPushNotificationCapability)
|
||||
{
|
||||
var plistPath = path + "/Info.plist";
|
||||
var plist = new PlistDocument();
|
||||
plist.ReadFromString(File.ReadAllText(plistPath));
|
||||
|
||||
var rootDict = plist.root;
|
||||
var needsToWriteChanges = false;
|
||||
|
||||
// Add all the settings to the plist.
|
||||
foreach (var setting in settings)
|
||||
{
|
||||
if (ShouldAddSettingToPlist(setting, rootDict))
|
||||
{
|
||||
needsToWriteChanges = true;
|
||||
if (setting.Value.GetType() == typeof(bool))
|
||||
{
|
||||
rootDict.SetBoolean(setting.Key, (bool)setting.Value);
|
||||
}
|
||||
else if (setting.Value.GetType() == typeof(PresentationOption) ||
|
||||
setting.Value.GetType() == typeof(AuthorizationOption))
|
||||
{
|
||||
rootDict.SetInteger(setting.Key, (int)setting.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add "remote-notification" to the list of supported UIBackgroundModes.
|
||||
if (addPushNotificationCapability)
|
||||
{
|
||||
PlistElementArray currentBackgroundModes = (PlistElementArray)rootDict["UIBackgroundModes"];
|
||||
if (currentBackgroundModes == null)
|
||||
currentBackgroundModes = rootDict.CreateArray("UIBackgroundModes");
|
||||
|
||||
var remoteNotificationElement = new PlistElementString("remote-notification");
|
||||
if (!currentBackgroundModes.values.Contains(remoteNotificationElement))
|
||||
{
|
||||
currentBackgroundModes.values.Add(remoteNotificationElement);
|
||||
needsToWriteChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsToWriteChanges)
|
||||
File.WriteAllText(plistPath, plist.WriteToString());
|
||||
}
|
||||
|
||||
// If the plist doesn't contain the key, or it's value is different, we should add/overwrite it.
|
||||
private static bool ShouldAddSettingToPlist(Unity.Notifications.NotificationSetting setting,
|
||||
PlistElementDict rootDict)
|
||||
{
|
||||
if (!rootDict.values.ContainsKey(setting.Key))
|
||||
return true;
|
||||
else if (setting.Value.GetType() == typeof(bool))
|
||||
return !rootDict.values[setting.Key].AsBoolean().Equals((bool)setting.Value);
|
||||
else if (setting.Value.GetType() == typeof(PresentationOption) || setting.Value.GetType() == typeof(AuthorizationOption))
|
||||
return !rootDict.values[setting.Key].AsInteger().Equals((int)setting.Value);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void PatchPreprocessor(string path, bool needLocationFramework, bool addPushNotificationCapability)
|
||||
{
|
||||
var preprocessorPath = path + "/Classes/Preprocessor.h";
|
||||
var preprocessor = File.ReadAllText(preprocessorPath);
|
||||
var needsToWriteChanges = false;
|
||||
|
||||
if (needLocationFramework && preprocessor.Contains("UNITY_USES_LOCATION"))
|
||||
{
|
||||
preprocessor = preprocessor.Replace("UNITY_USES_LOCATION 0", "UNITY_USES_LOCATION 1");
|
||||
needsToWriteChanges = true;
|
||||
}
|
||||
|
||||
if (addPushNotificationCapability && preprocessor.Contains("UNITY_USES_REMOTE_NOTIFICATIONS"))
|
||||
{
|
||||
preprocessor =
|
||||
preprocessor.Replace("UNITY_USES_REMOTE_NOTIFICATIONS 0", "UNITY_USES_REMOTE_NOTIFICATIONS 1");
|
||||
needsToWriteChanges = true;
|
||||
}
|
||||
|
||||
if (needsToWriteChanges)
|
||||
File.WriteAllText(preprocessorPath, preprocessor);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53cc9fd7c6f7b49f89ceebacdbc87512
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.Notifications
|
||||
{
|
||||
[Flags]
|
||||
internal enum iOSPresentationOption
|
||||
{
|
||||
Badge = 1 << 0,
|
||||
Sound = 1 << 1,
|
||||
Alert = 1 << 2,
|
||||
List = 1 << 3,
|
||||
Banner = 1 << 4,
|
||||
All = ~0,
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5fe6a884940b415f94f2b501eff5ce9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user