Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
/*
2
 * Copyright 2019 Google
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file 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
#import <nanopb/pb.h>
18
#import <nanopb/pb_decode.h>
19
#import <nanopb/pb_encode.h>
20
 
21
#import <GoogleDataTransport/GoogleDataTransport.h>
22
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
23
#import "FirebaseMessaging/Sources/FIRMessagingCode.h"
24
#import "FirebaseMessaging/Sources/FIRMessagingConstants.h"
25
#import "FirebaseMessaging/Sources/FIRMessagingLogger.h"
26
#import "FirebaseMessaging/Sources/Protogen/nanopb/me.nanopb.h"
27
#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessagingExtensionHelper.h"
28
 
29
static NSString *const kPayloadOptionsName = @"fcm_options";
30
static NSString *const kPayloadOptionsImageURLName = @"image";
31
static NSString *const kNoExtension = @"";
32
static NSString *const kImagePathPrefix = @"image/";
33
 
34
#pragma mark - nanopb helper functions
35
 
36
/** Callocs a pb_bytes_array and copies the given NSData bytes into the bytes array.
37
 *
38
 * @note Memory needs to be free manually, through pb_free or pb_release.
39
 * @param data The data to copy into the new bytes array.
40
 */
41
pb_bytes_array_t *FIRMessagingEncodeData(NSData *data) {
42
  pb_bytes_array_t *pbBytesArray = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length));
43
  if (pbBytesArray != NULL) {
44
    [data getBytes:pbBytesArray->bytes length:data.length];
45
    pbBytesArray->size = (pb_size_t)data.length;
46
  }
47
  return pbBytesArray;
48
}
49
/** Callocs a pb_bytes_array and copies the given NSString's bytes into the bytes array.
50
 *
51
 * @note Memory needs to be free manually, through pb_free or pb_release.
52
 * @param string The string to encode as pb_bytes.
53
 */
54
pb_bytes_array_t *FIRMessagingEncodeString(NSString *string) {
55
  NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding];
56
  return FIRMessagingEncodeData(stringBytes);
57
}
58
 
59
@interface FIRMessagingMetricsLog : NSObject <GDTCOREventDataObject>
60
 
61
@property(nonatomic) fm_MessagingClientEventExtension eventExtension;
62
 
63
@end
64
 
65
@implementation FIRMessagingMetricsLog
66
 
67
- (instancetype)initWithEventExtension:(fm_MessagingClientEventExtension)eventExtension {
68
  self = [super init];
69
  if (self) {
70
    _eventExtension = eventExtension;
71
  }
72
  return self;
73
}
74
 
75
- (NSData *)transportBytes {
76
  pb_ostream_t sizestream = PB_OSTREAM_SIZING;
77
 
78
  // Encode 1 time to determine the size.
79
  if (!pb_encode(&sizestream, fm_MessagingClientEventExtension_fields, &_eventExtension)) {
80
    FIRMessagingLoggerError(kFIRMessagingServiceExtensionTransportBytesError,
81
                            @"Error in nanopb encoding for size: %s", PB_GET_ERROR(&sizestream));
82
  }
83
 
84
  // Encode a 2nd time to actually get the bytes from it.
85
  size_t bufferSize = sizestream.bytes_written;
86
  CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize);
87
  CFDataSetLength(dataRef, bufferSize);
88
  pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize);
89
  if (!pb_encode(&ostream, fm_MessagingClientEventExtension_fields, &_eventExtension)) {
90
    FIRMessagingLoggerError(kFIRMessagingServiceExtensionTransportBytesError,
91
                            @"Error in nanopb encoding for bytes: %s", PB_GET_ERROR(&ostream));
92
  }
93
  CFDataSetLength(dataRef, ostream.bytes_written);
94
 
95
  return CFBridgingRelease(dataRef);
96
}
97
 
98
@end
99
 
100
@interface FIRMessagingExtensionHelper ()
101
@property(nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
102
@property(nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
103
 
104
@end
105
 
106
@implementation FIRMessagingExtensionHelper
107
 
108
- (void)populateNotificationContent:(UNMutableNotificationContent *)content
109
                 withContentHandler:(void (^)(UNNotificationContent *_Nonnull))contentHandler {
110
  self.contentHandler = [contentHandler copy];
111
  self.bestAttemptContent = content;
112
 
113
  // The `userInfo` property isn't available on newer versions of tvOS.
114
#if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_WATCH
115
  NSString *currentImageURL = content.userInfo[kPayloadOptionsName][kPayloadOptionsImageURLName];
116
  if (!currentImageURL) {
117
    [self deliverNotification];
118
    return;
119
  }
120
  NSURL *attachmentURL = [NSURL URLWithString:currentImageURL];
121
  if (attachmentURL) {
122
    [self loadAttachmentForURL:attachmentURL
123
             completionHandler:^(UNNotificationAttachment *attachment) {
124
               if (attachment != nil) {
125
                 self.bestAttemptContent.attachments = @[ attachment ];
126
               }
127
               [self deliverNotification];
128
             }];
129
  } else {
130
    FIRMessagingLoggerError(kFIRMessagingServiceExtensionImageInvalidURL,
131
                            @"The Image URL provided is invalid %@.", currentImageURL);
132
    [self deliverNotification];
133
  }
134
#else
135
  [self deliverNotification];
136
#endif
137
}
138
 
139
#if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_WATCH
140
- (NSString *)fileExtensionForResponse:(NSURLResponse *)response {
141
  NSString *suggestedPathExtension = [response.suggestedFilename pathExtension];
142
  if (suggestedPathExtension.length > 0) {
143
    return [NSString stringWithFormat:@".%@", suggestedPathExtension];
144
  }
145
  if ([response.MIMEType containsString:kImagePathPrefix]) {
146
    return [response.MIMEType stringByReplacingOccurrencesOfString:kImagePathPrefix
147
                                                        withString:@"."];
148
  }
149
  return kNoExtension;
150
}
151
 
152
- (void)loadAttachmentForURL:(NSURL *)attachmentURL
153
           completionHandler:(void (^)(UNNotificationAttachment *))completionHandler {
154
  __block UNNotificationAttachment *attachment = nil;
155
 
156
  NSURLSession *session = [NSURLSession
157
      sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
158
  [[session
159
      downloadTaskWithURL:attachmentURL
160
        completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) {
161
          if (error != nil) {
162
            FIRMessagingLoggerError(kFIRMessagingServiceExtensionImageNotDownloaded,
163
                                    @"Failed to download image given URL %@, error: %@\n",
164
                                    attachmentURL, error);
165
            completionHandler(attachment);
166
            return;
167
          }
168
 
169
          NSFileManager *fileManager = [NSFileManager defaultManager];
170
          NSString *fileExtension = [self fileExtensionForResponse:response];
171
          NSURL *localURL = [NSURL
172
              fileURLWithPath:[temporaryFileLocation.path stringByAppendingString:fileExtension]];
173
          [fileManager moveItemAtURL:temporaryFileLocation toURL:localURL error:&error];
174
          if (error) {
175
            FIRMessagingLoggerError(
176
                kFIRMessagingServiceExtensionLocalFileNotCreated,
177
                @"Failed to move the image file to local location: %@, error: %@\n", localURL,
178
                error);
179
            completionHandler(attachment);
180
            return;
181
          }
182
 
183
          attachment = [UNNotificationAttachment attachmentWithIdentifier:@""
184
                                                                      URL:localURL
185
                                                                  options:nil
186
                                                                    error:&error];
187
          if (error) {
188
            FIRMessagingLoggerError(kFIRMessagingServiceExtensionImageNotAttached,
189
                                    @"Failed to create attachment with URL %@, error: %@\n",
190
                                    localURL, error);
191
            completionHandler(attachment);
192
            return;
193
          }
194
          completionHandler(attachment);
195
        }] resume];
196
}
197
#endif
198
 
199
- (void)deliverNotification {
200
  if (self.contentHandler) {
201
    self.contentHandler(self.bestAttemptContent);
202
  }
203
}
204
 
205
- (void)exportDeliveryMetricsToBigQueryWithMessageInfo:(NSDictionary *)info {
206
  GDTCORTransport *transport = [[GDTCORTransport alloc] initWithMappingID:@"1249"
207
                                                             transformers:nil
208
                                                                   target:kGDTCORTargetFLL];
209
 
210
  fm_MessagingClientEventExtension eventExtension = fm_MessagingClientEventExtension_init_default;
211
 
212
  fm_MessagingClientEvent clientEvent = fm_MessagingClientEvent_init_default;
213
  if (!info[kFIRMessagingSenderID]) {
214
    FIRMessagingLoggerError(kFIRMessagingServiceExtensionInvalidProjectID,
215
                            @"Delivery logging failed: Invalid project ID");
216
    return;
217
  }
218
  clientEvent.project_number = (int64_t)[info[kFIRMessagingSenderID] longLongValue];
219
 
220
  if (!info[kFIRMessagingMessageIDKey] ||
221
      ![info[kFIRMessagingMessageIDKey] isKindOfClass:NSString.class]) {
222
    FIRMessagingLoggerWarn(kFIRMessagingServiceExtensionInvalidMessageID,
223
                           @"Delivery logging failed: Invalid Message ID");
224
    return;
225
  }
226
  clientEvent.message_id = FIRMessagingEncodeString(info[kFIRMessagingMessageIDKey]);
227
 
228
  if (!info[kFIRMessagingFID] || ![info[kFIRMessagingFID] isKindOfClass:NSString.class]) {
229
    FIRMessagingLoggerWarn(kFIRMessagingServiceExtensionInvalidInstanceID,
230
                           @"Delivery logging failed: Invalid Instance ID");
231
    return;
232
  }
233
  clientEvent.instance_id = FIRMessagingEncodeString(info[kFIRMessagingFID]);
234
 
235
  if ([info[@"aps"][kFIRMessagingMessageAPNSContentAvailableKey] intValue] == 1 &&
236
      ![GULAppEnvironmentUtil isAppExtension]) {
237
    clientEvent.message_type = fm_MessagingClientEvent_MessageType_DATA_MESSAGE;
238
  } else {
239
    clientEvent.message_type = fm_MessagingClientEvent_MessageType_DISPLAY_NOTIFICATION;
240
  }
241
  clientEvent.sdk_platform = fm_MessagingClientEvent_SDKPlatform_IOS;
242
 
243
  NSString *bundleID = [NSBundle mainBundle].bundleIdentifier;
244
  if ([GULAppEnvironmentUtil isAppExtension]) {
245
    bundleID = [[self class] bundleIdentifierByRemovingLastPartFrom:bundleID];
246
  }
247
  if (bundleID) {
248
    clientEvent.package_name = FIRMessagingEncodeString(bundleID);
249
  }
250
  clientEvent.event = fm_MessagingClientEvent_Event_MESSAGE_DELIVERED;
251
 
252
  if (info[kFIRMessagingAnalyticsMessageLabel]) {
253
    clientEvent.analytics_label =
254
        FIRMessagingEncodeString(info[kFIRMessagingAnalyticsMessageLabel]);
255
  }
256
  if (info[kFIRMessagingAnalyticsComposerIdentifier]) {
257
    clientEvent.campaign_id =
258
        (int64_t)[info[kFIRMessagingAnalyticsComposerIdentifier] longLongValue];
259
  }
260
  if (info[kFIRMessagingAnalyticsComposerLabel]) {
261
    clientEvent.composer_label =
262
        FIRMessagingEncodeString(info[kFIRMessagingAnalyticsComposerLabel]);
263
  }
264
 
265
  eventExtension.messaging_client_event = &clientEvent;
266
  FIRMessagingMetricsLog *log =
267
      [[FIRMessagingMetricsLog alloc] initWithEventExtension:eventExtension];
268
 
269
  GDTCOREvent *event = [transport eventForTransport];
270
  event.dataObject = log;
271
  event.qosTier = GDTCOREventQoSFast;
272
 
273
  // Use this API for SDK service data events.
274
  [transport sendDataEvent:event];
275
}
276
 
277
+ (NSString *)bundleIdentifierByRemovingLastPartFrom:(NSString *)bundleIdentifier {
278
  NSString *bundleIDComponentsSeparator = @".";
279
 
280
  NSMutableArray<NSString *> *bundleIDComponents =
281
      [[bundleIdentifier componentsSeparatedByString:bundleIDComponentsSeparator] mutableCopy];
282
  [bundleIDComponents removeLastObject];
283
 
284
  return [bundleIDComponents componentsJoinedByString:bundleIDComponentsSeparator];
285
}
286
 
287
@end