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 "FirebaseMessaging/Sources/Token/FIRMessagingTokenFetchOperation.h"
18
 
19
#import "FirebaseMessaging/Sources/FIRMessagingCode.h"
20
#import "FirebaseMessaging/Sources/FIRMessagingConstants.h"
21
#import "FirebaseMessaging/Sources/FIRMessagingDefines.h"
22
#import "FirebaseMessaging/Sources/FIRMessagingLogger.h"
23
#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h"
24
#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h"
25
#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h"
26
#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h"
27
 
28
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
29
 
30
// We can have a static int since this error should theoretically only
31
// happen once (for the first time). If it repeats there is something
32
// else that is wrong.
33
static int phoneRegistrationErrorRetryCount = 0;
34
static const int kMaxPhoneRegistrationErrorRetryCount = 10;
35
NSString *const kFIRMessagingFirebaseUserAgentKey = @"X-firebase-client";
36
NSString *const kFIRMessagingFirebaseHeartbeatKey = @"X-firebase-client-log-type";
37
NSString *const kFIRMessagingHeartbeatTag = @"fire-iid";
38
 
39
@implementation FIRMessagingTokenFetchOperation
40
 
41
- (instancetype)initWithAuthorizedEntity:(NSString *)authorizedEntity
42
                                   scope:(NSString *)scope
43
                                 options:(nullable NSDictionary<NSString *, NSString *> *)options
44
                      checkinPreferences:(FIRMessagingCheckinPreferences *)checkinPreferences
45
                              instanceID:(NSString *)instanceID {
46
  return [super initWithAction:FIRMessagingTokenActionFetch
47
           forAuthorizedEntity:authorizedEntity
48
                         scope:scope
49
                       options:options
50
            checkinPreferences:checkinPreferences
51
                    instanceID:instanceID];
52
}
53
 
54
- (void)performTokenOperation {
55
  NSMutableURLRequest *request = [self tokenRequest];
56
  NSString *checkinVersionInfo = self.checkinPreferences.versionInfo;
57
  [request setValue:checkinVersionInfo forHTTPHeaderField:@"info"];
58
  [request setValue:[FIRApp firebaseUserAgent]
59
      forHTTPHeaderField:kFIRMessagingFirebaseUserAgentKey];
60
  [request setValue:@([FIRHeartbeatInfo heartbeatCodeForTag:kFIRMessagingHeartbeatTag]).stringValue
61
      forHTTPHeaderField:kFIRMessagingFirebaseHeartbeatKey];
62
 
63
  // Build form-encoded body
64
  NSString *deviceAuthID = self.checkinPreferences.deviceID;
65
  NSMutableArray<NSURLQueryItem *> *queryItems =
66
      [[self class] standardQueryItemsWithDeviceID:deviceAuthID scope:self.scope];
67
  [queryItems addObject:[NSURLQueryItem queryItemWithName:@"sender" value:self.authorizedEntity]];
68
  [queryItems addObject:[NSURLQueryItem queryItemWithName:@"X-subtype"
69
                                                    value:self.authorizedEntity]];
70
 
71
  if (self.instanceID.length > 0) {
72
    [queryItems addObject:[NSURLQueryItem queryItemWithName:kFIRMessagingParamInstanceID
73
                                                      value:self.instanceID]];
74
  }
75
  // Create query items from passed-in options
76
  id apnsTokenData = self.options[kFIRMessagingTokenOptionsAPNSKey];
77
  id apnsSandboxValue = self.options[kFIRMessagingTokenOptionsAPNSIsSandboxKey];
78
  if ([apnsTokenData isKindOfClass:[NSData class]] &&
79
      [apnsSandboxValue isKindOfClass:[NSNumber class]]) {
80
    NSString *APNSString = FIRMessagingAPNSTupleStringForTokenAndServerType(
81
        apnsTokenData, ((NSNumber *)apnsSandboxValue).boolValue);
82
    // The name of the query item happens to be the same as the dictionary key
83
    NSURLQueryItem *item = [NSURLQueryItem queryItemWithName:kFIRMessagingTokenOptionsAPNSKey
84
                                                       value:APNSString];
85
    [queryItems addObject:item];
86
  }
87
  id firebaseAppID = self.options[kFIRMessagingTokenOptionsFirebaseAppIDKey];
88
  if ([firebaseAppID isKindOfClass:[NSString class]]) {
89
    // The name of the query item happens to be the same as the dictionary key
90
    NSURLQueryItem *item =
91
        [NSURLQueryItem queryItemWithName:kFIRMessagingTokenOptionsFirebaseAppIDKey
92
                                    value:(NSString *)firebaseAppID];
93
    [queryItems addObject:item];
94
  }
95
 
96
  NSURLComponents *components = [[NSURLComponents alloc] init];
97
  components.queryItems = queryItems;
98
  NSString *content = components.query;
99
  request.HTTPBody = [content dataUsingEncoding:NSUTF8StringEncoding];
100
  FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenFetchOperationFetchRequest,
101
                          @"Register request to %@ content: %@", FIRMessagingTokenRegisterServer(),
102
                          content);
103
 
104
  FIRMessaging_WEAKIFY(self);
105
  void (^requestHandler)(NSData *, NSURLResponse *, NSError *) =
106
      ^(NSData *data, NSURLResponse *response, NSError *error) {
107
        FIRMessaging_STRONGIFY(self);
108
        [self handleResponseWithData:data response:response error:error];
109
      };
110
  NSURLSessionConfiguration *config = NSURLSessionConfiguration.defaultSessionConfiguration;
111
  config.timeoutIntervalForResource = 60.0f;  // 1 minute
112
  NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
113
  self.dataTask = [session dataTaskWithRequest:request completionHandler:requestHandler];
114
  [self.dataTask resume];
115
}
116
 
117
#pragma mark - Request Handling
118
 
119
- (void)handleResponseWithData:(NSData *)data
120
                      response:(NSURLResponse *)response
121
                         error:(NSError *)error {
122
  if (error) {
123
    FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenFetchOperationRequestError,
124
                            @"Token fetch HTTP error. Error Code: %ld", (long)error.code);
125
    [self finishWithResult:FIRMessagingTokenOperationError token:nil error:error];
126
    return;
127
  }
128
  NSString *dataResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
129
 
130
  if (dataResponse.length == 0) {
131
    NSError *error = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeUnknown
132
                                       failureReason:@"Empty response."];
133
    [self finishWithResult:FIRMessagingTokenOperationError token:nil error:error];
134
    return;
135
  }
136
  NSDictionary *parsedResponse = [self parseFetchTokenResponse:dataResponse];
137
 
138
  if ([parsedResponse[@"token"] length]) {
139
    [self finishWithResult:FIRMessagingTokenOperationSucceeded
140
                     token:parsedResponse[@"token"]
141
                     error:nil];
142
    return;
143
  }
144
 
145
  NSString *errorValue = parsedResponse[@"Error"];
146
  NSError *responseError = nil;
147
  if (errorValue.length) {
148
    NSArray *errorComponents = [errorValue componentsSeparatedByString:@":"];
149
    // HACK (Kansas replication delay), PHONE_REGISTRATION_ERROR on App
150
    // uninstall and reinstall.
151
    if ([errorComponents containsObject:@"PHONE_REGISTRATION_ERROR"]) {
152
      // Encountered issue http://b/27043795
153
      // Retry register until successful or another error encountered or a
154
      // certain number of tries are over.
155
 
156
      if (phoneRegistrationErrorRetryCount < kMaxPhoneRegistrationErrorRetryCount) {
157
        const int nextRetryInterval = 1 << phoneRegistrationErrorRetryCount;
158
        FIRMessaging_WEAKIFY(self);
159
 
160
        dispatch_after(
161
            dispatch_time(DISPATCH_TIME_NOW, (int64_t)(nextRetryInterval * NSEC_PER_SEC)),
162
            dispatch_get_main_queue(), ^{
163
              FIRMessaging_STRONGIFY(self);
164
              phoneRegistrationErrorRetryCount++;
165
              [self performTokenOperation];
166
            });
167
        return;
168
      }
169
    } else if ([errorComponents containsObject:kFIRMessaging_CMD_RST]) {
170
      NSString *failureReason = @"Identity is invalid. Server request identity reset.";
171
      FIRMessagingLoggerDebug(kFIRMessagingMessageCodeInternal001, @"%@", failureReason);
172
      responseError = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeInvalidIdentity
173
                                        failureReason:failureReason];
174
    }
175
  }
176
  if (!responseError) {
177
    NSString *failureReason = @"Invalid fetch response, expected 'token' or 'Error' key";
178
    FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenFetchOperationBadResponse, @"%@",
179
                            failureReason);
180
    responseError = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeUnknown
181
                                      failureReason:failureReason];
182
  }
183
  [self finishWithResult:FIRMessagingTokenOperationError token:nil error:responseError];
184
}
185
 
186
// expect a response e.g. "token=<reg id>\nGOOG.ttl=123"
187
- (NSDictionary *)parseFetchTokenResponse:(NSString *)response {
188
  NSArray *lines = [response componentsSeparatedByString:@"\n"];
189
  NSMutableDictionary *parsedResponse = [NSMutableDictionary dictionary];
190
  for (NSString *line in lines) {
191
    NSArray *keyAndValue = [line componentsSeparatedByString:@"="];
192
    if ([keyAndValue count] > 1) {
193
      parsedResponse[keyAndValue[0]] = keyAndValue[1];
194
    }
195
  }
196
  return parsedResponse;
197
}
198
 
199
@end