AutorÃa | Ultima modificación | Ver Log |
/** Copyright 2017 Google** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#import <TargetConditionals.h>#if TARGET_OS_IOS || TARGET_OS_TV#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"#import "FirebaseInAppMessaging/Sources/FIRCore+InAppMessaging.h"#import "FirebaseInAppMessaging/Sources/Private/Data/FIRIAMFetchResponseParser.h"#import "FirebaseInAppMessaging/Sources/Private/Data/FIRIAMMessageContentDataWithImageURL.h"#import "FirebaseInAppMessaging/Sources/Private/Data/FIRIAMMessageDefinition.h"#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMMsgFetcherUsingRestful.h"#import "FirebaseInAppMessaging/Sources/Private/Runtime/FIRIAMFetchFlow.h"#import "FirebaseInAppMessaging/Sources/Private/Runtime/FIRIAMSDKSettings.h"static NSInteger const SuccessHTTPStatusCode = 200;@interface FIRIAMMsgFetcherUsingRestful ()@property(readonly) NSURLSession *URLSession;@property(readonly, copy, nonatomic) NSString *serverHostName;@property(readonly, copy, nonatomic) NSString *appBundleID;@property(readonly, copy, nonatomic) NSString *httpProtocol;@property(readonly, copy, nonatomic) NSString *fbProjectNumber;@property(readonly, copy, nonatomic) NSString *apiKey;@property(readonly, copy, nonatomic) NSString *firebaseAppId;@property(readonly, nonatomic) FIRIAMServerMsgFetchStorage *fetchStorage;@property(readonly, nonatomic) FIRIAMClientInfoFetcher *clientInfoFetcher;@property(readonly, nonatomic) FIRIAMFetchResponseParser *responseParser;@end@implementation FIRIAMMsgFetcherUsingRestful- (instancetype)initWithHost:(NSString *)serverHostHTTPProtocol:(NSString *)HTTPProtocolproject:(NSString *)fbProjectNumberfirebaseApp:(NSString *)fbAppIdAPIKey:(NSString *)apiKeyfetchStorage:(FIRIAMServerMsgFetchStorage *)fetchStorageinstanceIDFetcher:(FIRIAMClientInfoFetcher *)clientInfoFetcherusingURLSession:(nullable NSURLSession *)URLSessionresponseParser:(FIRIAMFetchResponseParser *)responseParser {if (self = [super init]) {_URLSession = URLSession ? URLSession : [NSURLSession sharedSession];_serverHostName = [serverHost copy];_fbProjectNumber = [fbProjectNumber copy];_firebaseAppId = [fbAppId copy];_httpProtocol = [HTTPProtocol copy];_apiKey = [apiKey copy];_clientInfoFetcher = clientInfoFetcher;_fetchStorage = fetchStorage;_appBundleID = [NSBundle mainBundle].bundleIdentifier;_responseParser = responseParser;}return self;}- (void)updatePostFetchData:(NSMutableDictionary *)postDatawithImpressionList:(NSArray<FIRIAMImpressionRecord *> *)impressionListinstanceIDString:(nonnull NSString *)IIDValueIIDToken:(nonnull NSString *)IIDToken {NSMutableArray *impressionListForPost = [[NSMutableArray alloc] init];for (FIRIAMImpressionRecord *nextImpressionRecord in impressionList) {NSDictionary *nextImpression = @{@"campaign_id" : nextImpressionRecord.messageID,@"impression_timestamp_millis" : @(nextImpressionRecord.impressionTimeInSeconds * 1000)};[impressionListForPost addObject:nextImpression];}[postData setObject:impressionListForPost forKey:@"already_seen_campaigns"];if (IIDValue) {NSDictionary *clientAppInfo = @{@"gmp_app_id" : self.firebaseAppId,@"app_instance_id" : IIDValue,@"app_instance_id_token" : IIDToken};[postData setObject:clientAppInfo forKey:@"requesting_client_app"];}NSMutableArray *clientSignals = [@{} mutableCopy];// set client signal fields only when they are presentif ([self.clientInfoFetcher getAppVersion]) {[clientSignals setValue:[self.clientInfoFetcher getAppVersion] forKey:@"app_version"];}if ([self.clientInfoFetcher getOSVersion]) {[clientSignals setValue:[self.clientInfoFetcher getOSVersion] forKey:@"platform_version"];}if ([self.clientInfoFetcher getDeviceLanguageCode]) {[clientSignals setValue:[self.clientInfoFetcher getDeviceLanguageCode] forKey:@"language_code"];}if ([self.clientInfoFetcher getTimezone]) {[clientSignals setValue:[self.clientInfoFetcher getTimezone] forKey:@"time_zone"];}[postData setObject:clientSignals forKey:@"client_signals"];}- (void)fetchMessagesWithImpressionList:(NSArray<FIRIAMImpressionRecord *> *)impressonListwithIIDvalue:(NSString *)iidValueIIDToken:(NSString *)iidTokencompletion:(FIRIAMFetchMessageCompletionHandler)completion {NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];[request setHTTPMethod:@"POST"];if (_appBundleID.length) {// Handle the case in which the API key is being restricted to specific iOS app bundle,// which can be set on Google Cloud console side for API key credentials.[request addValue:_appBundleID forHTTPHeaderField:@"X-Ios-Bundle-Identifier"];}[request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];[request addValue:@"application/json" forHTTPHeaderField:@"Accept"];[request addValue:iidToken forHTTPHeaderField:@"x-goog-firebase-installations-auth"];NSMutableDictionary *postFetchDict = [[NSMutableDictionary alloc] init];[self updatePostFetchData:postFetchDictwithImpressionList:impressonListinstanceIDString:iidValueIIDToken:iidToken];NSData *postFetchData = [NSJSONSerialization dataWithJSONObject:postFetchDictoptions:0error:nil];NSString *requestURLString = [NSStringstringWithFormat:@"%@://%@/v1/sdkServing/projects/%@/eligibleCampaigns:fetch?key=%@",self.httpProtocol, self.serverHostName, self.fbProjectNumber, self.apiKey];[request setURL:[NSURL URLWithString:requestURLString]];[request setHTTPBody:postFetchData];FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM130001",@"Making a restful API request for pulling messages with fetch POST body as %@ ""and request headers as %@",postFetchDict, request.allHTTPHeaderFields);NSURLSessionDataTask *postDataTask = [self.URLSessiondataTaskWithRequest:requestcompletionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {if (error) {FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM130002",@"Internal error: encountered error in pulling messages from server"":%@",error);completion(nil, nil, 0, error);} else {if ([response isKindOfClass:[NSHTTPURLResponse class]]) {NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;if (httpResponse.statusCode == SuccessHTTPStatusCode) {// got response data successfullyFIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM130007",@"Fetch API response headers are %@", [httpResponse allHeaderFields]);NSError *errorJson = nil;NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:dataoptions:kNilOptionserror:&errorJson];if (errorJson) {FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM130003",@"Failed to parse the response body as JSON string %@", errorJson);completion(nil, nil, 0, errorJson);} else {NSInteger discardCount;NSNumber *nextFetchWaitTimeFromResponse;NSArray<FIRIAMMessageDefinition *> *messages = [self.responseParserparseAPIResponseDictionary:responseDictdiscardedMsgCount:&discardCountfetchWaitTimeInSeconds:&nextFetchWaitTimeFromResponse];if (messages) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM130012",@"API request for fetching messages and parsing the response was ""successful.");[self.fetchStoragesaveResponseDictionary:responseDictwithCompletion:^(BOOL success) {if (!success)FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM130010",@"Failed to persist server fetch response");}];// always report success regardless of whether we are able to persist into// storage. they should get fixed in the next fetch cycle if it happens.completion(messages, nextFetchWaitTimeFromResponse, discardCount, nil);} else {NSString *errorDesc =@"Failed to recognize the fiam messages in the server response";FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM130011", @"%@", errorDesc);NSError *error =[NSError errorWithDomain:kFirebaseInAppMessagingErrorDomaincode:0userInfo:@{NSLocalizedDescriptionKey : errorDesc}];completion(nil, nil, 0, error);}}} else {NSString *responseBody = [[NSString alloc] initWithData:dataencoding:NSUTF8StringEncoding];FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM130004",@"Failed restful api request to fetch in-app messages: seeing http "@"status code as %ld with body as %@",(long)httpResponse.statusCode, responseBody);NSError *error = [NSError errorWithDomain:NSURLErrorDomaincode:httpResponse.statusCodeuserInfo:nil];completion(nil, nil, 0, error);}} else {NSString *errorDesc = @"Got a non http response type from fetch endpoint";FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM130005", @"%@", errorDesc);NSError *error = [NSError errorWithDomain:kFirebaseInAppMessagingErrorDomaincode:0userInfo:@{NSLocalizedDescriptionKey : errorDesc}];completion(nil, nil, 0, error);}}}];if (postDataTask == nil) {NSString *errorDesc =@"Internal error: NSURLSessionDataTask failed to be created due to possibly ""incorrect parameters";FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM130006", @"%@", errorDesc);NSError *error = [NSError errorWithDomain:kFirebaseInAppMessagingErrorDomaincode:0userInfo:@{NSLocalizedDescriptionKey : errorDesc}];completion(nil, nil, 0, error);} else {[postDataTask resume];}}#pragma mark - protocol FIRIAMMessageFetcher- (void)fetchMessagesWithImpressionList:(NSArray<FIRIAMImpressionRecord *> *)impressonListwithCompletion:(FIRIAMFetchMessageCompletionHandler)completion {// First step is to fetch the instance id value and token on the fly. We are not caching the data// since the fetch operation frequency is low enough that we are not concerned about its impact// on server load and this guarantees that we always have an up-to-date iid values and tokens.[self.clientInfoFetcherfetchFirebaseInstallationDataWithProjectNumber:self.fbProjectNumberwithCompletion:^(NSString *_Nullable FID,NSString *_Nullable FISToken,NSError *_Nullable error) {if (error) {FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM130008",@"Not able to get iid value and/or token for "@"talking to server: %@",error.localizedDescription);completion(nil, nil, 0, error);} else {[self fetchMessagesWithImpressionList:impressonListwithIIDvalue:FIDIIDToken:FISTokencompletion:completion];}}];}@end#endif // TARGET_OS_IOS || TARGET_OS_TV