@ammarahmed/notifee-react-native 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/.gitattributes +3 -0
  2. package/LICENSE +44 -0
  3. package/README.md +131 -0
  4. package/RNNotifee.podspec +39 -0
  5. package/RNNotifeeCore.podspec +33 -0
  6. package/android/build.gradle +116 -0
  7. package/android/gradle.properties +1 -0
  8. package/android/libs/app/notifee/core/202108261756/core-202108261756.aar +0 -0
  9. package/android/libs/app/notifee/core/202108261756/core-202108261756.aar.md5 +1 -0
  10. package/android/libs/app/notifee/core/202108261756/core-202108261756.aar.sha1 +1 -0
  11. package/android/libs/app/notifee/core/202108261756/core-202108261756.aar.sha256 +1 -0
  12. package/android/libs/app/notifee/core/202108261756/core-202108261756.aar.sha512 +1 -0
  13. package/android/libs/app/notifee/core/202108261756/core-202108261756.pom +9 -0
  14. package/android/libs/app/notifee/core/202108261756/core-202108261756.pom.md5 +1 -0
  15. package/android/libs/app/notifee/core/202108261756/core-202108261756.pom.sha1 +1 -0
  16. package/android/libs/app/notifee/core/202108261756/core-202108261756.pom.sha256 +1 -0
  17. package/android/libs/app/notifee/core/202108261756/core-202108261756.pom.sha512 +1 -0
  18. package/android/libs/app/notifee/core/maven-metadata.xml +13 -0
  19. package/android/libs/app/notifee/core/maven-metadata.xml.md5 +1 -0
  20. package/android/libs/app/notifee/core/maven-metadata.xml.sha1 +1 -0
  21. package/android/libs/app/notifee/core/maven-metadata.xml.sha256 +1 -0
  22. package/android/libs/app/notifee/core/maven-metadata.xml.sha512 +1 -0
  23. package/android/lint.xml +5 -0
  24. package/android/proguard-rules.pro +74 -0
  25. package/android/settings.gradle +1 -0
  26. package/android/src/main/AndroidManifest.xml +12 -0
  27. package/android/src/main/java/io/invertase/notifee/NotifeeApiModule.java +349 -0
  28. package/android/src/main/java/io/invertase/notifee/NotifeeEventSubscriber.java +118 -0
  29. package/android/src/main/java/io/invertase/notifee/NotifeeInitProvider.java +55 -0
  30. package/android/src/main/java/io/invertase/notifee/NotifeePackage.java +30 -0
  31. package/android/src/main/java/io/invertase/notifee/NotifeeReactUtils.java +244 -0
  32. package/app.plugin.js +1 -0
  33. package/dist/NotifeeApiModule.d.ts +53 -0
  34. package/dist/NotifeeApiModule.js +607 -0
  35. package/dist/NotifeeApiModule.js.map +1 -0
  36. package/dist/NotifeeJSEventEmitter.d.ts +3 -0
  37. package/dist/NotifeeJSEventEmitter.js +14 -0
  38. package/dist/NotifeeJSEventEmitter.js.map +1 -0
  39. package/dist/NotifeeNativeError.d.ts +15 -0
  40. package/dist/NotifeeNativeError.js +61 -0
  41. package/dist/NotifeeNativeError.js.map +1 -0
  42. package/dist/NotifeeNativeModule.d.ts +14 -0
  43. package/dist/NotifeeNativeModule.js +43 -0
  44. package/dist/NotifeeNativeModule.js.map +1 -0
  45. package/dist/NotifeeNativeModule.web.d.ts +12 -0
  46. package/dist/NotifeeNativeModule.web.js +19 -0
  47. package/dist/NotifeeNativeModule.web.js.map +1 -0
  48. package/dist/index.d.ts +8 -0
  49. package/dist/index.js +43 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/types/Library.d.ts +21 -0
  52. package/dist/types/Library.js +6 -0
  53. package/dist/types/Library.js.map +1 -0
  54. package/dist/types/Module.d.ts +572 -0
  55. package/dist/types/Module.js +6 -0
  56. package/dist/types/Module.js.map +1 -0
  57. package/dist/types/Notification.d.ts +450 -0
  58. package/dist/types/Notification.js +105 -0
  59. package/dist/types/Notification.js.map +1 -0
  60. package/dist/types/NotificationAndroid.d.ts +1276 -0
  61. package/dist/types/NotificationAndroid.js +380 -0
  62. package/dist/types/NotificationAndroid.js.map +1 -0
  63. package/dist/types/NotificationIOS.d.ts +537 -0
  64. package/dist/types/NotificationIOS.js +92 -0
  65. package/dist/types/NotificationIOS.js.map +1 -0
  66. package/dist/types/NotificationWeb.d.ts +5 -0
  67. package/dist/types/NotificationWeb.js +3 -0
  68. package/dist/types/NotificationWeb.js.map +1 -0
  69. package/dist/types/PowerManagerInfo.d.ts +36 -0
  70. package/dist/types/PowerManagerInfo.js +6 -0
  71. package/dist/types/PowerManagerInfo.js.map +1 -0
  72. package/dist/types/Trigger.d.ts +108 -0
  73. package/dist/types/Trigger.js +39 -0
  74. package/dist/types/Trigger.js.map +1 -0
  75. package/dist/utils/id.d.ts +1 -0
  76. package/dist/utils/id.js +16 -0
  77. package/dist/utils/id.js.map +1 -0
  78. package/dist/utils/index.d.ts +16 -0
  79. package/dist/utils/index.js +52 -0
  80. package/dist/utils/index.js.map +1 -0
  81. package/dist/utils/validate.d.ts +15 -0
  82. package/dist/utils/validate.js +93 -0
  83. package/dist/utils/validate.js.map +1 -0
  84. package/dist/validators/iosCommunicationInfo/validateIOSCommunicationInfo.d.ts +2 -0
  85. package/dist/validators/iosCommunicationInfo/validateIOSCommunicationInfo.js +39 -0
  86. package/dist/validators/iosCommunicationInfo/validateIOSCommunicationInfo.js.map +1 -0
  87. package/dist/validators/iosCommunicationInfo/validateIOSCommunicationInfoPerson.d.ts +2 -0
  88. package/dist/validators/iosCommunicationInfo/validateIOSCommunicationInfoPerson.js +27 -0
  89. package/dist/validators/iosCommunicationInfo/validateIOSCommunicationInfoPerson.js.map +1 -0
  90. package/dist/validators/validate.d.ts +25 -0
  91. package/dist/validators/validate.js +75 -0
  92. package/dist/validators/validate.js.map +1 -0
  93. package/dist/validators/validateAndroidAction.d.ts +2 -0
  94. package/dist/validators/validateAndroidAction.js +52 -0
  95. package/dist/validators/validateAndroidAction.js.map +1 -0
  96. package/dist/validators/validateAndroidChannel.d.ts +2 -0
  97. package/dist/validators/validateAndroidChannel.js +155 -0
  98. package/dist/validators/validateAndroidChannel.js.map +1 -0
  99. package/dist/validators/validateAndroidChannelGroup.d.ts +2 -0
  100. package/dist/validators/validateAndroidChannelGroup.js +42 -0
  101. package/dist/validators/validateAndroidChannelGroup.js.map +1 -0
  102. package/dist/validators/validateAndroidFullScreenAction.d.ts +2 -0
  103. package/dist/validators/validateAndroidFullScreenAction.js +50 -0
  104. package/dist/validators/validateAndroidFullScreenAction.js.map +1 -0
  105. package/dist/validators/validateAndroidInput.d.ts +2 -0
  106. package/dist/validators/validateAndroidInput.js +54 -0
  107. package/dist/validators/validateAndroidInput.js.map +1 -0
  108. package/dist/validators/validateAndroidNotification.d.ts +2 -0
  109. package/dist/validators/validateAndroidNotification.js +529 -0
  110. package/dist/validators/validateAndroidNotification.js.map +1 -0
  111. package/dist/validators/validateAndroidPressAction.d.ts +2 -0
  112. package/dist/validators/validateAndroidPressAction.js +50 -0
  113. package/dist/validators/validateAndroidPressAction.js.map +1 -0
  114. package/dist/validators/validateAndroidStyle.d.ts +22 -0
  115. package/dist/validators/validateAndroidStyle.js +231 -0
  116. package/dist/validators/validateAndroidStyle.js.map +1 -0
  117. package/dist/validators/validateIOSAttachment.d.ts +6 -0
  118. package/dist/validators/validateIOSAttachment.js +102 -0
  119. package/dist/validators/validateIOSAttachment.js.map +1 -0
  120. package/dist/validators/validateIOSCategory.d.ts +2 -0
  121. package/dist/validators/validateIOSCategory.js +124 -0
  122. package/dist/validators/validateIOSCategory.js.map +1 -0
  123. package/dist/validators/validateIOSCategoryAction.d.ts +2 -0
  124. package/dist/validators/validateIOSCategoryAction.js +59 -0
  125. package/dist/validators/validateIOSCategoryAction.js.map +1 -0
  126. package/dist/validators/validateIOSInput.d.ts +2 -0
  127. package/dist/validators/validateIOSInput.js +32 -0
  128. package/dist/validators/validateIOSInput.js.map +1 -0
  129. package/dist/validators/validateIOSNotification.d.ts +2 -0
  130. package/dist/validators/validateIOSNotification.js +211 -0
  131. package/dist/validators/validateIOSNotification.js.map +1 -0
  132. package/dist/validators/validateIOSPermissions.d.ts +2 -0
  133. package/dist/validators/validateIOSPermissions.js +62 -0
  134. package/dist/validators/validateIOSPermissions.js.map +1 -0
  135. package/dist/validators/validateNotification.d.ts +11 -0
  136. package/dist/validators/validateNotification.js +129 -0
  137. package/dist/validators/validateNotification.js.map +1 -0
  138. package/dist/validators/validateTrigger.d.ts +2 -0
  139. package/dist/validators/validateTrigger.js +104 -0
  140. package/dist/validators/validateTrigger.js.map +1 -0
  141. package/dist/version.d.ts +1 -0
  142. package/dist/version.js.map +1 -0
  143. package/ios/NotifeeCore/Info.plist +22 -0
  144. package/ios/NotifeeCore/NotifeeCore+NSNotificationCenter.h +28 -0
  145. package/ios/NotifeeCore/NotifeeCore+NSNotificationCenter.m +72 -0
  146. package/ios/NotifeeCore/NotifeeCore+NSURLSession.h +25 -0
  147. package/ios/NotifeeCore/NotifeeCore+NSURLSession.m +55 -0
  148. package/ios/NotifeeCore/NotifeeCore+UNUserNotificationCenter.h +37 -0
  149. package/ios/NotifeeCore/NotifeeCore+UNUserNotificationCenter.m +242 -0
  150. package/ios/NotifeeCore/NotifeeCore.h +118 -0
  151. package/ios/NotifeeCore/NotifeeCore.m +784 -0
  152. package/ios/NotifeeCore/NotifeeCoreDelegateHolder.h +34 -0
  153. package/ios/NotifeeCore/NotifeeCoreDelegateHolder.m +70 -0
  154. package/ios/NotifeeCore/NotifeeCoreDownloadDelegate.h +39 -0
  155. package/ios/NotifeeCore/NotifeeCoreDownloadDelegate.m +68 -0
  156. package/ios/NotifeeCore/NotifeeCoreExtensionHelper.h +38 -0
  157. package/ios/NotifeeCore/NotifeeCoreExtensionHelper.m +224 -0
  158. package/ios/NotifeeCore/NotifeeCoreUtil.h +82 -0
  159. package/ios/NotifeeCore/NotifeeCoreUtil.m +793 -0
  160. package/ios/RNNotifee/NotifeeApiModule.h +25 -0
  161. package/ios/RNNotifee/NotifeeApiModule.m +371 -0
  162. package/ios/RNNotifee/NotifeeExtensionHelper.h +37 -0
  163. package/ios/RNNotifee/NotifeeExtensionHelper.m +37 -0
  164. package/ios/RNNotifee.xcodeproj/project.pbxproj +318 -0
  165. package/jest-mock.js +158 -0
  166. package/package.json +59 -0
  167. package/plugin/build/index.d.ts +3 -0
  168. package/plugin/build/index.js +12 -0
  169. package/plugin/build/index.js.map +1 -0
  170. package/plugin/build/withNotifeeProjectGradlePlugin.d.ts +5 -0
  171. package/plugin/build/withNotifeeProjectGradlePlugin.js +24 -0
  172. package/plugin/build/withNotifeeProjectGradlePlugin.js.map +1 -0
  173. package/plugin/src/index.ts +9 -0
  174. package/plugin/src/withNotifeeProjectGradlePlugin.ts +27 -0
  175. package/plugin/tsconfig.json +9 -0
  176. package/react-native.config.js +11 -0
  177. package/refresh-example.sh +71 -0
  178. package/src/NotifeeApiModule.ts +825 -0
  179. package/src/NotifeeJSEventEmitter.ts +11 -0
  180. package/src/NotifeeNativeError.ts +70 -0
  181. package/src/NotifeeNativeModule.ts +55 -0
  182. package/src/NotifeeNativeModule.web.ts +25 -0
  183. package/src/index.ts +33 -0
  184. package/src/types/Library.ts +28 -0
  185. package/src/types/Module.ts +625 -0
  186. package/src/types/Notification.ts +505 -0
  187. package/src/types/NotificationAndroid.ts +1443 -0
  188. package/src/types/NotificationIOS.ts +681 -0
  189. package/src/types/NotificationWeb.ts +5 -0
  190. package/src/types/PowerManagerInfo.ts +43 -0
  191. package/src/types/Trigger.ts +118 -0
  192. package/src/utils/id.ts +13 -0
  193. package/src/utils/index.ts +47 -0
  194. package/src/utils/validate.ts +92 -0
  195. package/src/validators/iosCommunicationInfo/validateIOSCommunicationInfo.ts +45 -0
  196. package/src/validators/iosCommunicationInfo/validateIOSCommunicationInfoPerson.ts +33 -0
  197. package/src/validators/validate.ts +85 -0
  198. package/src/validators/validateAndroidAction.ts +54 -0
  199. package/src/validators/validateAndroidChannel.ts +188 -0
  200. package/src/validators/validateAndroidChannelGroup.ts +49 -0
  201. package/src/validators/validateAndroidFullScreenAction.ts +65 -0
  202. package/src/validators/validateAndroidInput.ts +67 -0
  203. package/src/validators/validateAndroidNotification.ts +704 -0
  204. package/src/validators/validateAndroidPressAction.ts +65 -0
  205. package/src/validators/validateAndroidStyle.ts +315 -0
  206. package/src/validators/validateIOSAttachment.ts +136 -0
  207. package/src/validators/validateIOSCategory.ts +150 -0
  208. package/src/validators/validateIOSCategoryAction.ts +65 -0
  209. package/src/validators/validateIOSInput.ts +38 -0
  210. package/src/validators/validateIOSNotification.ts +296 -0
  211. package/src/validators/validateIOSPermissions.ts +78 -0
  212. package/src/validators/validateNotification.ts +156 -0
  213. package/src/validators/validateTrigger.ts +134 -0
  214. package/src/version.ts +2 -0
  215. package/tsconfig.json +23 -0
@@ -0,0 +1,793 @@
1
+ /**
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ #import "NotifeeCoreUtil.h"
19
+ #include <CoreGraphics/CGGeometry.h>
20
+ #import <Intents/INIntentIdentifiers.h>
21
+ #import <UIKit/UIKit.h>
22
+ #import "NotifeeCore+NSURLSession.h"
23
+
24
+ @implementation NotifeeCoreUtil
25
+
26
+ + (NSNumber *)numberForUNNotificationSetting:(UNNotificationSetting)setting {
27
+ NSNumber *asNumber = @-1;
28
+ if (setting == UNNotificationSettingNotSupported) {
29
+ asNumber = @-1;
30
+ } else if (setting == UNNotificationSettingDisabled) {
31
+ asNumber = @0;
32
+ } else if (setting == UNNotificationSettingEnabled) {
33
+ asNumber = @1;
34
+ }
35
+ return asNumber;
36
+ }
37
+
38
+ + (NSMutableArray<NSDictionary *> *)notificationActionsToDictionaryArray:
39
+ (NSArray<UNNotificationAction *> *)notificationActions {
40
+ NSMutableArray<NSDictionary *> *notificationActionDicts = [[NSMutableArray alloc] init];
41
+
42
+ for (UNNotificationAction *notificationAction in notificationActions) {
43
+ NSMutableDictionary *notificationActionDict = [NSMutableDictionary dictionary];
44
+
45
+ notificationActionDict[@"id"] = notificationAction.identifier;
46
+ notificationActionDict[@"title"] = notificationAction.title;
47
+
48
+ notificationActionDict[@"destructive"] =
49
+ @(((notificationAction.options & UNNotificationActionOptionDestructive) != 0));
50
+ notificationActionDict[@"foreground"] =
51
+ @(((notificationAction.options & UNNotificationActionOptionForeground) != 0));
52
+ notificationActionDict[@"authenticationRequired"] =
53
+ @(((notificationAction.options & UNNotificationActionOptionAuthenticationRequired) != 0));
54
+
55
+ if ([[notificationAction class] isKindOfClass:[UNTextInputNotificationAction class]]) {
56
+ UNTextInputNotificationAction *notificationInputAction =
57
+ (UNTextInputNotificationAction *)notificationAction;
58
+ if ([notificationInputAction textInputButtonTitle] == nil &&
59
+ [notificationInputAction textInputPlaceholder] == nil) {
60
+ notificationActionDict[@"input"] = @(YES);
61
+ } else {
62
+ NSMutableDictionary *inputDict = [NSMutableDictionary dictionary];
63
+ inputDict[@"buttonText"] = [notificationInputAction textInputButtonTitle];
64
+ inputDict[@"placeholderText"] = [notificationInputAction textInputPlaceholder];
65
+ notificationActionDict[@"input"] = inputDict;
66
+ }
67
+ } else {
68
+ notificationActionDict[@"input"] = @(NO);
69
+ }
70
+
71
+ [notificationActionDicts addObject:notificationActionDict];
72
+ }
73
+
74
+ return notificationActionDicts;
75
+ }
76
+
77
+ + (NSMutableArray<UNNotificationAction *> *)notificationActionsFromDictionaryArray:
78
+ (NSArray<NSDictionary *> *)actionDictionaries {
79
+ NSMutableArray<UNNotificationAction *> *notificationActions = [[NSMutableArray alloc] init];
80
+
81
+ for (NSDictionary *actionDictionary in actionDictionaries) {
82
+ UNNotificationAction *notificationAction;
83
+
84
+ NSString *id = actionDictionary[@"id"];
85
+ NSString *title = actionDictionary[@"title"];
86
+
87
+ UNNotificationActionOptions options = 0;
88
+
89
+ if ([actionDictionary[@"destructive"] isEqual:@(YES)]) {
90
+ options |= UNNotificationActionOptionDestructive;
91
+ }
92
+
93
+ if ([actionDictionary[@"foreground"] isEqual:@(YES)]) {
94
+ options |= UNNotificationActionOptionForeground;
95
+ }
96
+
97
+ if ([actionDictionary[@"authenticationRequired"] isEqual:@(YES)]) {
98
+ options |= UNNotificationActionOptionAuthenticationRequired;
99
+ }
100
+
101
+ if (actionDictionary[@"input"] != nil &&
102
+ [actionDictionary[@"input"] isKindOfClass:NSDictionary.class]) {
103
+ NSDictionary *inputDictionary = actionDictionary[@"input"];
104
+ NSString *buttonText = inputDictionary[@"buttonText"];
105
+ NSString *placeholderText = inputDictionary[@"placeholderText"];
106
+ notificationAction = [UNTextInputNotificationAction actionWithIdentifier:id
107
+ title:title
108
+ options:options
109
+ textInputButtonTitle:buttonText
110
+ textInputPlaceholder:placeholderText];
111
+ } else if (actionDictionary[@"input"] != nil) { // BOOL
112
+ notificationAction = [UNTextInputNotificationAction actionWithIdentifier:id
113
+ title:title
114
+ options:options];
115
+ } else {
116
+ notificationAction = [UNNotificationAction actionWithIdentifier:id
117
+ title:title
118
+ options:options];
119
+ }
120
+
121
+ [notificationActions addObject:notificationAction];
122
+ }
123
+
124
+ return notificationActions;
125
+ }
126
+
127
+ /**
128
+ * Builds the notification attachments
129
+ * If no attachments are resolved, an empty array will be returned
130
+ *
131
+ * @return NSArray<UNNotificationAttachment *> *
132
+ */
133
+ + (NSMutableArray<UNNotificationAttachment *> *)notificationAttachmentsFromDictionaryArray:
134
+ (NSArray<NSDictionary *> *)attachmentDictionaries {
135
+ NSMutableArray<UNNotificationAttachment *> *attachments = [[NSMutableArray alloc] init];
136
+
137
+ for (NSDictionary *attachmentDict in attachmentDictionaries) {
138
+ UNNotificationAttachment *attachment = [self attachmentFromDictionary:attachmentDict];
139
+ if (attachment) {
140
+ [attachments addObject:attachment];
141
+ }
142
+ }
143
+ return attachments;
144
+ }
145
+
146
+ /**
147
+ * Returns an UNNotificationAttachment from a file path or local resource
148
+ *
149
+ * @return UNNotificationAttachment or null if the attachment fails to resolve
150
+ */
151
+ + (UNNotificationAttachment *)attachmentFromDictionary:(NSDictionary *)attachmentDict {
152
+ NSString *identifier = attachmentDict[@"id"];
153
+ NSString *urlString = attachmentDict[@"url"];
154
+ NSURL *url;
155
+
156
+ if ([urlString hasPrefix:@"http://"] || [urlString hasPrefix:@"https://"]) {
157
+ // handle remote url by attempting to download attachement synchronously
158
+ url = [self downloadMediaSynchronously:urlString];
159
+ } else if ([urlString hasPrefix:@"/"]) {
160
+ // handle absolute file path
161
+ url = [NSURL fileURLWithPath:urlString];
162
+ } else {
163
+ // try to resolve local resource
164
+ url = [[NSBundle mainBundle] URLForResource:attachmentDict[@"url"] withExtension:nil];
165
+ }
166
+
167
+ if (url) {
168
+ NSError *error;
169
+ UNNotificationAttachment *attachment = [UNNotificationAttachment
170
+ attachmentWithIdentifier:identifier
171
+ URL:url
172
+ options:[self attachmentOptionsFromDictionary:attachmentDict]
173
+ error:&error];
174
+ if (error != nil) {
175
+ NSLog(@"NotifeeCore: An error occurred whilst trying to resolve an "
176
+ @"attachment %@: %@",
177
+ attachmentDict, error);
178
+ return nil;
179
+ } else if (attachment == nil) {
180
+ NSLog(@"NotifeeCore: Failed resolving an attachment %@: data at URL is "
181
+ @"not a supported type.",
182
+ attachmentDict);
183
+ }
184
+
185
+ return attachment;
186
+ }
187
+
188
+ NSLog(@"NotifeeCore: Unable to resolve url for attachment: %@", attachmentDict);
189
+ return nil;
190
+ }
191
+
192
+ /*
193
+ * Downloads a media file, syncronously to the NSCachesDirectory
194
+ *
195
+ * @param urlString NSString
196
+ * @return NSURL or nil
197
+ */
198
+ + (NSURL *)downloadMediaSynchronously:(NSString *)urlString {
199
+ NSURL *url = [NSURL URLWithString:urlString];
200
+
201
+ NSString *newCachedFileName = [self generateCachedFileName:15];
202
+
203
+ NSArray *localDirectoryPaths =
204
+ NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
205
+ NSString *tempDestination =
206
+ [localDirectoryPaths[0] stringByAppendingPathComponent:newCachedFileName];
207
+
208
+ @try {
209
+ NSError *error;
210
+
211
+ // Apple gives us a suggested file name which can be used to infer the file
212
+ // extension
213
+ NSString *suggestedFilename = [NotifeeCoreNSURLSession downloadItemAtURL:url
214
+ toFile:tempDestination
215
+ error:&error];
216
+
217
+ if (error) {
218
+ NSLog(@"NotifeeCore: Failed to download attachement with URL %@: %@", urlString, error);
219
+ return nil;
220
+ }
221
+
222
+ // Rename the recently downloaded file to include its file extension
223
+ NSFileManager *fileManager = [NSFileManager defaultManager];
224
+
225
+ NSString *fileExtension = [NSString stringWithFormat:@".%@", [suggestedFilename pathExtension]];
226
+
227
+ if (!fileExtension || [fileExtension isEqualToString:@""]) {
228
+ NSLog(@"NotifeeCore: Failed to determine file extension for attachment "
229
+ @"with URL %@: %@",
230
+ urlString, error);
231
+ return nil;
232
+ }
233
+
234
+ NSString *localFilePath =
235
+ [localDirectoryPaths[0] stringByAppendingPathComponent:newCachedFileName];
236
+
237
+ localFilePath = [localFilePath stringByAppendingString:fileExtension];
238
+ NSURL *localURL = [NSURL fileURLWithPath:localFilePath];
239
+
240
+ [fileManager moveItemAtPath:tempDestination toPath:localFilePath error:&error];
241
+
242
+ // Returns the local cached path to attachment
243
+ return localURL;
244
+ } @catch (NSException *exception) {
245
+ NSLog(@"NotifeeCore: An exception occured while attempting to download "
246
+ @"attachment with URL %@: "
247
+ @"%@",
248
+ urlString, exception);
249
+ return nil;
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Returns a NSDictionary representation of options related to the attached file
255
+ *
256
+ * @param optionsDict NSDictionary
257
+ */
258
+ + (NSDictionary *)attachmentOptionsFromDictionary:(NSDictionary *)optionsDict {
259
+ NSMutableDictionary *options = [NSMutableDictionary new];
260
+ if (optionsDict[@"typeHint"] != nil) {
261
+ options[UNNotificationAttachmentOptionsTypeHintKey] = optionsDict[@"typeHint"];
262
+ }
263
+
264
+ if (optionsDict[@"thumbnailHidden"] != nil) {
265
+ options[UNNotificationAttachmentOptionsThumbnailHiddenKey] = optionsDict[@"thumbnailHidden"];
266
+ }
267
+
268
+ if (optionsDict[@"thumbnailClippingRect"] != nil) {
269
+ NSDictionary *area = optionsDict[@"thumbnailClippingRect"];
270
+ NSNumber *x = area[@"x"];
271
+ NSNumber *y = area[@"y"];
272
+ NSNumber *width = area[@"width"];
273
+ NSNumber *height = area[@"height"];
274
+ CGRect areaRect =
275
+ CGRectMake([x doubleValue], [y doubleValue], [width doubleValue], [height doubleValue]);
276
+ options[UNNotificationAttachmentOptionsThumbnailClippingRectKey] =
277
+ (__bridge id _Nullable)(CGRectCreateDictionaryRepresentation(areaRect));
278
+ }
279
+
280
+ if (optionsDict[@"thumbnailTime"] != nil) {
281
+ options[UNNotificationAttachmentOptionsThumbnailTimeKey] = optionsDict[@"thumbnailTime"];
282
+ }
283
+
284
+ return options;
285
+ }
286
+
287
+ /**
288
+ * Returns an UNNotificationTrigger from NSDictionary representing a trigger
289
+ *
290
+ * @param triggerDict NSDictionary
291
+ * @return UNNotificationTrigger or null if trigger type is not recognised
292
+ */
293
+ + (UNNotificationTrigger *)triggerFromDictionary:(NSDictionary *)triggerDict {
294
+ UNNotificationTrigger *trigger;
295
+ NSInteger triggerType = [triggerDict[@"type"] integerValue];
296
+
297
+ if (triggerType == NotifeeCoreTriggerTypeTimestamp) {
298
+ trigger = [self timestampTriggerFromDictionary:triggerDict];
299
+ } else if (triggerType == NotifeeCoreTriggerTypeInterval) {
300
+ trigger = [self intervalTriggerFromDictionary:triggerDict];
301
+ } else {
302
+ NSLog(@"NotifeeCore: Failed to parse trigger with unknown trigger type: %ld",
303
+ (long)triggerType);
304
+ }
305
+
306
+ return trigger;
307
+ }
308
+
309
+ /**
310
+ * Returns an UNNotificationTrigger from NSDictionary representing a
311
+ * TimestampTrigger
312
+ *
313
+ * @param triggerDict NSDictionary
314
+ */
315
+ + (UNNotificationTrigger *)timestampTriggerFromDictionary:(NSDictionary *)triggerDict {
316
+ UNNotificationTrigger *trigger;
317
+ Boolean repeats = false;
318
+ NSCalendarUnit calendarUnit;
319
+
320
+ NSInteger repeatFrequency = [triggerDict[@"repeatFrequency"] integerValue];
321
+ NSNumber *timestampMillis = triggerDict[@"timestamp"];
322
+
323
+ // convert timestamp to a NSDate
324
+ NSInteger timestamp = [timestampMillis doubleValue] / 1000;
325
+ NSDate *date = [NSDate dateWithTimeIntervalSince1970:timestamp];
326
+
327
+ if (repeatFrequency != -1) {
328
+ repeats = true;
329
+
330
+ if (repeatFrequency == NotifeeCoreRepeatFrequencyHourly) {
331
+ // match by minute and second
332
+ calendarUnit = NSCalendarUnitMinute | NSCalendarUnitSecond;
333
+ } else if (repeatFrequency == NotifeeCoreRepeatFrequencyDaily) {
334
+ // match by hour, minute and second
335
+ calendarUnit = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
336
+ } else if (repeatFrequency == NotifeeCoreRepeatFrequencyWeekly) {
337
+ // match by day, hour, minute, and second
338
+ calendarUnit =
339
+ NSCalendarUnitWeekday | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
340
+ } else if (repeatFrequency == NotifeeCoreRepeatFrequencyMonthly) {
341
+ // match by day, hour, minute, and second
342
+ calendarUnit =
343
+ NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
344
+ } else {
345
+ NSLog(@"NotifeeCore: Failed to parse TimestampTrigger with unknown "
346
+ @"repeatFrequency: %ld",
347
+ (long)repeatFrequency);
348
+
349
+ return nil;
350
+ }
351
+ } else {
352
+ // Needs to match exactly to the second
353
+ calendarUnit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay |
354
+ NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
355
+ }
356
+
357
+ NSDateComponents *components = [[NSCalendar currentCalendar] components:calendarUnit
358
+ fromDate:date];
359
+ trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components
360
+ repeats:repeats];
361
+
362
+ return trigger;
363
+ }
364
+ /**
365
+ * Returns an UNNotificationTrigger from NSDictionary representing an
366
+ * IntervalTrigger
367
+ *
368
+ * @param triggerDict NSDictionary
369
+ */
370
+ + (UNNotificationTrigger *)intervalTriggerFromDictionary:(NSDictionary *)triggerDict {
371
+ double intervalNumber = [triggerDict[@"interval"] doubleValue];
372
+ NSString *timeUnit = triggerDict[@"timeUnit"];
373
+
374
+ NSTimeInterval intervalInSeconds = 0;
375
+
376
+ if ([timeUnit isEqualToString:kNotifeeCoreTimeUnitSeconds]) {
377
+ intervalInSeconds = intervalNumber;
378
+ } else if ([timeUnit isEqualToString:kNotifeeCoreTimeUnitMinutes]) {
379
+ // multiply by the number of seconds in 1 minute
380
+ intervalInSeconds = intervalNumber * 60;
381
+ } else if ([timeUnit isEqualToString:kNotifeeCoreTimeUnitHours]) {
382
+ // multiply by the number of seconds in 1 hour
383
+ intervalInSeconds = intervalNumber * 3600;
384
+ } else if ([timeUnit isEqualToString:kNotifeeCoreTimeUnitDays]) {
385
+ // multiply by the number of seconds in 1 day
386
+ intervalInSeconds = intervalNumber * 86400;
387
+ } else {
388
+ NSLog(@"NotifeeCore: Failed to parse IntervalTrigger with unknown "
389
+ @"timeUnit: %@",
390
+ timeUnit);
391
+ return nil;
392
+ }
393
+
394
+ return [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:intervalInSeconds repeats:true];
395
+ }
396
+
397
+ + (NSMutableArray<NSNumber *> *)intentIdentifiersFromStringArray:
398
+ (NSArray<NSString *> *)identifiers {
399
+ NSMutableArray<NSNumber *> *intentIdentifiers = [[NSMutableArray alloc] init];
400
+
401
+ for (NSString *identifier in identifiers) {
402
+ if ([identifier isEqualToString:INStartAudioCallIntentIdentifier]) {
403
+ // IOSIntentIdentifier.START_AUDIO_CALL
404
+ [intentIdentifiers addObject:@0];
405
+ } else if ([identifier isEqualToString:INStartVideoCallIntentIdentifier]) {
406
+ // IOSIntentIdentifier.START_VIDEO_CALL
407
+ [intentIdentifiers addObject:@1];
408
+ } else if ([identifier isEqualToString:INSearchCallHistoryIntentIdentifier]) {
409
+ // IOSIntentIdentifier.SEARCH_CALL_HISTORY
410
+ [intentIdentifiers addObject:@2];
411
+ } else if ([identifier isEqualToString:INSetAudioSourceInCarIntentIdentifier]) {
412
+ // IOSIntentIdentifier.SET_AUDIO_SOURCE_IN_CAR
413
+ [intentIdentifiers addObject:@3];
414
+ } else if ([identifier isEqualToString:INSetClimateSettingsInCarIntentIdentifier]) {
415
+ // IOSIntentIdentifier.SET_CLIMATE_SETTINGS_IN_CAR
416
+ [intentIdentifiers addObject:@4];
417
+ } else if ([identifier isEqualToString:INSetDefrosterSettingsInCarIntentIdentifier]) {
418
+ // IOSIntentIdentifier.SET_DEFROSTER_SETTINGS_IN_CAR
419
+ [intentIdentifiers addObject:@5];
420
+ } else if ([identifier isEqualToString:INSetSeatSettingsInCarIntentIdentifier]) {
421
+ // IOSIntentIdentifier.SET_SEAT_SETTINGS_IN_CAR
422
+ [intentIdentifiers addObject:@6];
423
+ } else if ([identifier isEqualToString:INSetProfileInCarIntentIdentifier]) {
424
+ // IOSIntentIdentifier.SET_PROFILE_IN_CAR
425
+ [intentIdentifiers addObject:@7];
426
+ } else if ([identifier isEqualToString:INSaveProfileInCarIntentIdentifier]) {
427
+ // IOSIntentIdentifier.SAVE_PROFILE_IN_CAR
428
+ [intentIdentifiers addObject:@8];
429
+ } else if ([identifier isEqualToString:INStartWorkoutIntentIdentifier]) {
430
+ // IOSIntentIdentifier.START_WORKOUT
431
+ [intentIdentifiers addObject:@9];
432
+ } else if ([identifier isEqualToString:INPauseWorkoutIntentIdentifier]) {
433
+ // IOSIntentIdentifier.PAUSE_WORKOUT
434
+ [intentIdentifiers addObject:@10];
435
+ } else if ([identifier isEqualToString:INEndWorkoutIntentIdentifier]) {
436
+ // IOSIntentIdentifier.END_WORKOUT
437
+ [intentIdentifiers addObject:@11];
438
+ } else if ([identifier isEqualToString:INCancelWorkoutIntentIdentifier]) {
439
+ // IOSIntentIdentifier.CANCEL_WORKOUT
440
+ [intentIdentifiers addObject:@12];
441
+ } else if ([identifier isEqualToString:INResumeWorkoutIntentIdentifier]) {
442
+ // IOSIntentIdentifier.RESUME_WORKOUT
443
+ [intentIdentifiers addObject:@13];
444
+ } else if ([identifier isEqualToString:INSetRadioStationIntentIdentifier]) {
445
+ // IOSIntentIdentifier.SET_RADIO_STATION
446
+ [intentIdentifiers addObject:@14];
447
+ } else if ([identifier isEqualToString:INSendMessageIntentIdentifier]) {
448
+ // IOSIntentIdentifier.SEND_MESSAGE
449
+ [intentIdentifiers addObject:@15];
450
+ } else if ([identifier isEqualToString:INSearchForMessagesIntentIdentifier]) {
451
+ // IOSIntentIdentifier.SEARCH_FOR_MESSAGES
452
+ [intentIdentifiers addObject:@16];
453
+ } else if ([identifier isEqualToString:INSetMessageAttributeIntentIdentifier]) {
454
+ // IOSIntentIdentifier.SET_MESSAGE_ATTRIBUTE
455
+ [intentIdentifiers addObject:@17];
456
+ } else if ([identifier isEqualToString:INSendPaymentIntentIdentifier]) {
457
+ // IOSIntentIdentifier.SEND_PAYMENT
458
+ [intentIdentifiers addObject:@18];
459
+ } else if ([identifier isEqualToString:INRequestPaymentIntentIdentifier]) {
460
+ // IOSIntentIdentifier.REQUEST_PAYMENT
461
+ [intentIdentifiers addObject:@19];
462
+ } else if ([identifier isEqualToString:INSearchForPhotosIntentIdentifier]) {
463
+ // IOSIntentIdentifier.SEARCH_FOR_PHOTOS
464
+ [intentIdentifiers addObject:@20];
465
+ } else if ([identifier isEqualToString:INStartPhotoPlaybackIntentIdentifier]) {
466
+ // IOSIntentIdentifier.START_PHOTO_PLAYBACK
467
+ [intentIdentifiers addObject:@21];
468
+ } else if ([identifier isEqualToString:INListRideOptionsIntentIdentifier]) {
469
+ // IOSIntentIdentifier.LIST_RIDE_OPTIONS
470
+ [intentIdentifiers addObject:@22];
471
+ } else if ([identifier isEqualToString:INRequestRideIntentIdentifier]) {
472
+ // IOSIntentIdentifier.REQUEST_RIDE
473
+ [intentIdentifiers addObject:@23];
474
+ } else if ([identifier isEqualToString:INGetRideStatusIntentIdentifier]) {
475
+ // IOSIntentIdentifier.GET_RIDE_STATUS
476
+ [intentIdentifiers addObject:@24];
477
+ }
478
+ }
479
+
480
+ return intentIdentifiers;
481
+ }
482
+
483
+ + (NSMutableArray<NSString *> *)intentIdentifiersFromNumberArray:
484
+ (NSArray<NSNumber *> *)identifiers {
485
+ NSMutableArray<NSString *> *intentIdentifiers = [[NSMutableArray alloc] init];
486
+
487
+ for (NSNumber *identifier in identifiers) {
488
+ if ([identifier isEqualToNumber:@0]) {
489
+ // IOSIntentIdentifier.START_AUDIO_CALL
490
+ [intentIdentifiers addObject:INStartAudioCallIntentIdentifier];
491
+ } else if ([identifier isEqualToNumber:@1]) {
492
+ // IOSIntentIdentifier.START_VIDEO_CALL
493
+ [intentIdentifiers addObject:INStartVideoCallIntentIdentifier];
494
+ } else if ([identifier isEqualToNumber:@2]) {
495
+ // IOSIntentIdentifier.SEARCH_CALL_HISTORY
496
+ [intentIdentifiers addObject:INSearchCallHistoryIntentIdentifier];
497
+ } else if ([identifier isEqualToNumber:@3]) {
498
+ // IOSIntentIdentifier.SET_AUDIO_SOURCE_IN_CAR
499
+ [intentIdentifiers addObject:INSetAudioSourceInCarIntentIdentifier];
500
+ } else if ([identifier isEqualToNumber:@4]) {
501
+ // IOSIntentIdentifier.SET_CLIMATE_SETTINGS_IN_CAR
502
+ [intentIdentifiers addObject:INSetClimateSettingsInCarIntentIdentifier];
503
+ } else if ([identifier isEqualToNumber:@5]) {
504
+ // IOSIntentIdentifier.SET_DEFROSTER_SETTINGS_IN_CAR
505
+ [intentIdentifiers addObject:INSetDefrosterSettingsInCarIntentIdentifier];
506
+ } else if ([identifier isEqualToNumber:@6]) {
507
+ // IOSIntentIdentifier.SET_SEAT_SETTINGS_IN_CAR
508
+ [intentIdentifiers addObject:INSetSeatSettingsInCarIntentIdentifier];
509
+ } else if ([identifier isEqualToNumber:@7]) {
510
+ // IOSIntentIdentifier.SET_PROFILE_IN_CAR
511
+ [intentIdentifiers addObject:INSetProfileInCarIntentIdentifier];
512
+ } else if ([identifier isEqualToNumber:@8]) {
513
+ // IOSIntentIdentifier.SAVE_PROFILE_IN_CAR
514
+ [intentIdentifiers addObject:INSaveProfileInCarIntentIdentifier];
515
+ } else if ([identifier isEqualToNumber:@9]) {
516
+ // IOSIntentIdentifier.START_WORKOUT
517
+ [intentIdentifiers addObject:INStartWorkoutIntentIdentifier];
518
+ } else if ([identifier isEqualToNumber:@10]) {
519
+ // IOSIntentIdentifier.PAUSE_WORKOUT
520
+ [intentIdentifiers addObject:INPauseWorkoutIntentIdentifier];
521
+ } else if ([identifier isEqualToNumber:@11]) {
522
+ // IntentIdentifier.END_WORKOUT
523
+ [intentIdentifiers addObject:INEndWorkoutIntentIdentifier];
524
+ } else if ([identifier isEqualToNumber:@12]) {
525
+ // IOSIntentIdentifier.CANCEL_WORKOUT
526
+ [intentIdentifiers addObject:INCancelWorkoutIntentIdentifier];
527
+ } else if ([identifier isEqualToNumber:@13]) {
528
+ // IOSIntentIdentifier.RESUME_WORKOUT
529
+ [intentIdentifiers addObject:INResumeWorkoutIntentIdentifier];
530
+ } else if ([identifier isEqualToNumber:@14]) {
531
+ // IOSIntentIdentifier.SET_RADIO_STATION
532
+ [intentIdentifiers addObject:INSetRadioStationIntentIdentifier];
533
+ } else if ([identifier isEqualToNumber:@15]) {
534
+ // IOSIntentIdentifier.SEND_MESSAGE
535
+ [intentIdentifiers addObject:INSendMessageIntentIdentifier];
536
+ } else if ([identifier isEqualToNumber:@16]) {
537
+ // IOSIntentIdentifier.SEARCH_FOR_MESSAGES
538
+ [intentIdentifiers addObject:INSearchForMessagesIntentIdentifier];
539
+ } else if ([identifier isEqualToNumber:@17]) {
540
+ // IOSIntentIdentifier.SET_MESSAGE_ATTRIBUTE
541
+ [intentIdentifiers addObject:INSetMessageAttributeIntentIdentifier];
542
+ } else if ([identifier isEqualToNumber:@18]) {
543
+ // IOSIntentIdentifier.SEND_PAYMENT
544
+ [intentIdentifiers addObject:INSendPaymentIntentIdentifier];
545
+ } else if ([identifier isEqualToNumber:@19]) {
546
+ // IOSIntentIdentifier.REQUEST_PAYMENT
547
+ [intentIdentifiers addObject:INRequestPaymentIntentIdentifier];
548
+ } else if ([identifier isEqualToNumber:@20]) {
549
+ // IOSIntentIdentifier.SEARCH_FOR_PHOTOS
550
+ [intentIdentifiers addObject:INSearchForPhotosIntentIdentifier];
551
+ } else if ([identifier isEqualToNumber:@21]) {
552
+ // IOSIntentIdentifier.START_PHOTO_PLAYBACK
553
+ [intentIdentifiers addObject:INStartPhotoPlaybackIntentIdentifier];
554
+ } else if ([identifier isEqualToNumber:@22]) {
555
+ // IOSIntentIdentifier.LIST_RIDE_OPTIONS
556
+ [intentIdentifiers addObject:INListRideOptionsIntentIdentifier];
557
+ } else if ([identifier isEqualToNumber:@23]) {
558
+ // IOSIntentIdentifier.REQUEST_RIDE
559
+ [intentIdentifiers addObject:INRequestRideIntentIdentifier];
560
+ } else if ([identifier isEqualToNumber:@24]) {
561
+ // IOSIntentIdentifier.GET_RIDE_STATUS
562
+ [intentIdentifiers addObject:INGetRideStatusIntentIdentifier];
563
+ }
564
+ }
565
+
566
+ return intentIdentifiers;
567
+ }
568
+
569
+ /**
570
+ * Returns timestamp in millisecons
571
+ *
572
+ * @param date NSDate
573
+ */
574
+ + (NSNumber *)convertToTimestamp:(NSDate *)date {
575
+ return [NSNumber numberWithDouble:([date timeIntervalSince1970] * 1000)];
576
+ }
577
+
578
+ /**
579
+ * Parse UNNotificationRequest to NSDictionary
580
+ *
581
+ * @param request UNNotificationRequest
582
+ */
583
+ + (NSMutableDictionary *)parseUNNotificationRequest:(UNNotificationRequest *)request {
584
+ NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
585
+
586
+ dictionary = [self parseUNNotificationContent:request.content];
587
+ dictionary[@"id"] = request.identifier;
588
+
589
+ NSDictionary *userInfo = request.content.userInfo;
590
+
591
+ // Check for remote details
592
+ if ([request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
593
+ NSMutableDictionary *remote = [NSMutableDictionary dictionary];
594
+
595
+ remote[@"messageId"] = userInfo[@"gcm.message_id"];
596
+ remote[@"senderId"] = userInfo[@"google.c.sender.id"];
597
+
598
+ if (userInfo[@"aps"] != nil) {
599
+ remote[@"mutableContent"] = userInfo[@"aps"][@"mutable-content"];
600
+ remote[@"contentAvailable"] = userInfo[@"aps"][@"content-available"];
601
+ }
602
+
603
+ dictionary[@"remote"] = remote;
604
+ }
605
+
606
+ dictionary[@"data"] = [self parseDataFromUserInfo:userInfo];
607
+
608
+ return dictionary;
609
+ }
610
+
611
+ + (NSMutableDictionary *)parseDataFromUserInfo:(NSDictionary *)userInfo {
612
+ NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
613
+ for (id key in userInfo) {
614
+ // build data dict from remaining keys but skip keys that shouldn't be included in data
615
+ if ([key isEqualToString:@"aps"] || [key hasPrefix:@"gcm."] || [key hasPrefix:@"google."] ||
616
+ // notifee or notifee_options
617
+ [key hasPrefix:@"notifee"] ||
618
+ // fcm_options
619
+ [key hasPrefix:@"fcm"]) {
620
+ continue;
621
+ }
622
+ data[key] = userInfo[key];
623
+ }
624
+
625
+ return data;
626
+ }
627
+
628
+ + (NSMutableDictionary *)parseUNNotificationContent:(UNNotificationContent *)content {
629
+ NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
630
+ NSMutableDictionary *iosDict = [NSMutableDictionary dictionary];
631
+
632
+ dictionary[@"subtitle"] = content.subtitle;
633
+ dictionary[@"body"] = content.body;
634
+ dictionary[@"data"] = [content.userInfo mutableCopy];
635
+
636
+ // title
637
+ if (content.title != nil) {
638
+ dictionary[@"title"] = content.title;
639
+ }
640
+
641
+ // subtitle
642
+ if (content.subtitle != nil) {
643
+ dictionary[@"subtitle"] = content.subtitle;
644
+ }
645
+
646
+ // body
647
+ if (content.body != nil) {
648
+ dictionary[@"body"] = content.body;
649
+ }
650
+
651
+ iosDict[@"badgeCount"] = content.badge;
652
+
653
+ // categoryId
654
+ if (content.categoryIdentifier != nil) {
655
+ iosDict[@"categoryId"] = content.categoryIdentifier;
656
+ }
657
+
658
+ // launchImageName
659
+ if (content.launchImageName != nil) {
660
+ iosDict[@"launchImageName"] = content.launchImageName;
661
+ }
662
+
663
+ // threadId
664
+ if (content.threadIdentifier != nil) {
665
+ iosDict[@"threadId"] = content.threadIdentifier;
666
+ }
667
+
668
+ // targetContentId
669
+ if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) {
670
+ if (content.targetContentIdentifier != nil) {
671
+ iosDict[@"targetContentId"] = content.targetContentIdentifier;
672
+ }
673
+ }
674
+
675
+ if (content.attachments != nil) {
676
+ // TODO: parse attachments
677
+ }
678
+
679
+ // sound
680
+ if (content.sound != nil) {
681
+ if ([content.sound isKindOfClass:[NSString class]]) {
682
+ iosDict[@"sound"] = content.sound;
683
+ } else if ([content.sound isKindOfClass:[NSDictionary class]]) {
684
+ NSDictionary *soundDict = content.sound;
685
+ NSMutableDictionary *notificationIOSSound = [[NSMutableDictionary alloc] init];
686
+
687
+ // ios.sound.name String
688
+ if (soundDict[@"name"] != nil) {
689
+ notificationIOSSound[@"name"] = soundDict[@"name"];
690
+ }
691
+
692
+ // sound.critical Boolean
693
+ if (soundDict[@"critical"] != nil) {
694
+ notificationIOSSound[@"critical"] = soundDict[@"critical"];
695
+ }
696
+
697
+ // ios.sound.volume Number
698
+ if (soundDict[@"volume"] != nil) {
699
+ notificationIOSSound[@"volume"] = soundDict[@"volume"];
700
+ }
701
+
702
+ // ios.sound
703
+ iosDict[@"sound"] = notificationIOSSound;
704
+ }
705
+ }
706
+
707
+ dictionary[@"ios"] = iosDict;
708
+ return dictionary;
709
+ }
710
+
711
+ + (INSendMessageIntent *)generateSenderIntentForCommunicationNotifciation:
712
+ (NSDictionary *)communicationInfo {
713
+ if (@available(iOS 15.0, *)) {
714
+ NSDictionary *sender = communicationInfo[@"sender"];
715
+ INPersonHandle *senderPersonHandle =
716
+ [[INPersonHandle alloc] initWithValue:sender[@"id"] type:INPersonHandleTypeUnknown];
717
+
718
+ // Parse sender's avatar
719
+ INImage *avatar = nil;
720
+ if (sender[@"avatar"] != nil) {
721
+ NSURL *url = [[NSURL alloc] initWithString:sender[@"avatar"]];
722
+ avatar = [INImage imageWithURL:url];
723
+ }
724
+
725
+ INPerson *senderPerson = [[INPerson alloc] initWithPersonHandle:senderPersonHandle
726
+ nameComponents:nil
727
+ displayName:sender[@"displayName"]
728
+ image:avatar
729
+ contactIdentifier:nil
730
+ customIdentifier:nil];
731
+
732
+ INSendMessageIntent *intent =
733
+ [[INSendMessageIntent alloc] initWithRecipients:nil
734
+ outgoingMessageType:INOutgoingMessageTypeOutgoingMessageText
735
+ content:communicationInfo[@"body"]
736
+ speakableGroupName:nil
737
+ conversationIdentifier:communicationInfo[@"conversationId"]
738
+ serviceName:nil
739
+ sender:senderPerson
740
+ attachments:nil];
741
+
742
+ return intent;
743
+ }
744
+
745
+ return nil;
746
+ }
747
+ /**
748
+ * Returns a random string using UUID
749
+ *
750
+ * @param length int
751
+ */
752
+ + (NSString *)generateCachedFileName:(int)length {
753
+ return [[NSUUID UUID] UUIDString];
754
+ }
755
+
756
+ /**
757
+ * Returns a shared instance of [UIApplication sharedApplication]
758
+ * Needed to prevent compile errors for App extensions when calling [UIApplication
759
+ * sharedApplication]
760
+ *
761
+ * @return instancetype
762
+ */
763
+ + (nullable instancetype)notifeeUIApplication {
764
+ static dispatch_once_t once;
765
+ static NotifeeCoreUtil *sharedInstance;
766
+ dispatch_once(&once, ^{
767
+ static Class applicationClass = nil;
768
+ if (![self isAppExtension]) {
769
+ Class cls = NSClassFromString(@"UIApplication");
770
+ if (cls && [cls respondsToSelector:NSSelectorFromString(@"sharedApplication")]) {
771
+ applicationClass = cls;
772
+ }
773
+ }
774
+
775
+ sharedInstance = (NotifeeCoreUtil *)[applicationClass sharedApplication];
776
+ });
777
+
778
+ return sharedInstance;
779
+ }
780
+
781
+ /**
782
+ * Checks if the current application is an extension
783
+ */
784
+ + (BOOL)isAppExtension {
785
+ #if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
786
+ BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"];
787
+ return appExtension;
788
+ #elif TARGET_OS_OSX
789
+ return NO;
790
+ #endif
791
+ }
792
+
793
+ @end