Skip to content

Commit

Permalink
Add Dynamic Links PR to 7.3.0 release with Changelog update (#7119)
Browse files Browse the repository at this point in the history
  • Loading branch information
paulb777 authored Dec 7, 2020
1 parent 7134db8 commit 77dae0b
Show file tree
Hide file tree
Showing 7 changed files with 448 additions and 53 deletions.
3 changes: 3 additions & 0 deletions FirebaseDynamicLinks/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# v7.3.0

This comment has been minimized.

Copy link
@mikehardy

mikehardy Dec 14, 2020

Contributor

Hey @paulb777 - I feel like I'm a burr in your saddle, apologies for that but at least this time I don't have a wild goose chase of an issue. Just noting that the 7.3.0 release process was subtly different than the 7.2.0 one, which I noticed because of the burr in my saddle, the firebase-ios-sdk-frameworks pre-compiler we offer FlutterFire developers to halve their build time

Specifically, check how 'CocoaPods-7.2.0' tag has all the things attached to it while 'CocoaPods-7.3.0' does not:

related, the '7.2.0' vs '7.3.0' tag:

Looks like the 'CocoaPods-x.y.z' vs 'x.y.z' tags inverted contents somehow?

This comment has been minimized.

Copy link
@paulb777

paulb777 Dec 14, 2020

Author Member

@mikehardy Yep. Now that we're doing proper versioning for Swift Package Manager, we switched back to using the main version tag for the zip distribution. See https://github.com/firebase/firebase-ios-sdk/releases/tag/7.3.0.

Sorry about the silent change - I'll try to keep you in mind if we make future changes like this.

This comment has been minimized.

Copy link
@mikehardy

mikehardy Dec 14, 2020

Contributor

Ah ha :-), I'm not sure exactly how you'd transmit this information, not exactly a formal channel and release engineering is hard enough and we notice automatically with a little delay so it won't just sit there silently - so thank you but no worries of course. I'll adjust our script and we will march happily along. Cheers

- [added] Manually created dynamic links should be subject to allowed/blocked check (#5853)

# v4.3.1
- [changed] Client id usage in api call and respective checks in the code.
- [fixed] Fix attempts to connect to invalid ipv6 domain by updating ipv4 and ipv6 to use a single, valid endpoint (#5032)
Expand Down
1 change: 1 addition & 0 deletions FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ typedef void (^FIRPostInstallAttributionCompletionHandler)(

/** A definition for a block used to return data and errors after an asynchronous task. */
typedef void (^FIRNetworkRequestCompletionHandler)(NSData *_Nullable data,
NSURLResponse *_Nullable response,
NSError *_Nullable error);

// these enums must be in sync with google/firebase/dynamiclinks/v1/dynamic_links.proto
Expand Down
114 changes: 78 additions & 36 deletions FirebaseDynamicLinks/Sources/FIRDynamicLinkNetworking.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
static NSString *const kFDLAnalyticsDataMediumKey = @"utmMedium";
static NSString *const kFDLAnalyticsDataCampaignKey = @"utmCampaign";
static NSString *const kHeaderIosBundleIdentifier = @"X-Ios-Bundle-Identifier";
static NSString *const kGenericErrorDomain = @"com.firebase.dynamicLinks";

typedef NSDictionary *_Nullable (^FIRDLNetworkingParserBlock)(
NSString *requestURLString,
Expand All @@ -67,7 +68,7 @@ void FIRMakeHTTPRequest(NSURLRequest *request, FIRNetworkRequestCompletionHandle
[session dataTaskWithRequest:request
completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response,
NSError *_Nullable error) {
completion(data, error);
completion(data, response, error);
}];
[dataTask resume];
}
Expand All @@ -91,6 +92,41 @@ - (instancetype)initWithAPIKey:(NSString *)APIKey URLScheme:(NSString *)URLSchem
return self;
}

+ (nullable NSError *)extractErrorForShortLink:(NSURL *)url
data:(NSData *)data
response:(NSURLResponse *)response
error:(nullable NSError *)error {
if (error) {
return error;
}

NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
NSError *customError = nil;

if (![response isKindOfClass:[NSHTTPURLResponse class]]) {
customError =
[NSError errorWithDomain:kGenericErrorDomain
code:0
userInfo:@{@"message" : @"Response should be of type NSHTTPURLResponse."}];
} else if ((statusCode < 200 || statusCode >= 300) && data) {
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if ([result isKindOfClass:[NSDictionary class]] && [result objectForKey:@"error"]) {
id err = [result objectForKey:@"error"];
customError = [NSError errorWithDomain:kGenericErrorDomain code:statusCode userInfo:err];
} else {
customError = [NSError
errorWithDomain:kGenericErrorDomain
code:0
userInfo:@{
@"message" :
[NSString stringWithFormat:@"Failed to resolve link: %@", url.absoluteString]
}];
}
}

return customError;
}

#pragma mark - Public interface

- (void)resolveShortLink:(NSURL *)url
Expand All @@ -108,34 +144,39 @@ - (void)resolveShortLink:(NSURL *)url
@"sdk_version" : FDLSDKVersion
};

FIRNetworkRequestCompletionHandler resolveLinkCallback = ^(NSData *data, NSError *error) {
NSURL *resolvedURL;

if (!error && data) {
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if ([result isKindOfClass:[NSDictionary class]]) {
id invitationIDObject = [result objectForKey:@"invitationId"];

NSString *invitationIDString;
if ([invitationIDObject isKindOfClass:[NSDictionary class]]) {
NSDictionary *invitationIDDictionary = invitationIDObject;
invitationIDString = invitationIDDictionary[@"id"];
} else if ([invitationIDObject isKindOfClass:[NSString class]]) {
invitationIDString = invitationIDObject;
FIRNetworkRequestCompletionHandler resolveLinkCallback =
^(NSData *data, NSURLResponse *response, NSError *error) {
NSURL *resolvedURL = nil;
NSError *extractedError = [FIRDynamicLinkNetworking extractErrorForShortLink:url
data:data
response:response
error:error];

if (!extractedError && data) {
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if ([result isKindOfClass:[NSDictionary class]]) {
id invitationIDObject = [result objectForKey:@"invitationId"];

NSString *invitationIDString;
if ([invitationIDObject isKindOfClass:[NSDictionary class]]) {
NSDictionary *invitationIDDictionary = invitationIDObject;
invitationIDString = invitationIDDictionary[@"id"];
} else if ([invitationIDObject isKindOfClass:[NSString class]]) {
invitationIDString = invitationIDObject;
}

NSString *deepLinkString = result[kFDLResolvedLinkDeepLinkURLKey];
NSString *minAppVersion = result[kFDLResolvedLinkMinAppVersionKey];
NSString *utmSource = result[kFDLAnalyticsDataSourceKey];
NSString *utmMedium = result[kFDLAnalyticsDataMediumKey];
NSString *utmCampaign = result[kFDLAnalyticsDataCampaignKey];
resolvedURL = FIRDLDeepLinkURLWithInviteID(invitationIDString, deepLinkString,
utmSource, utmMedium, utmCampaign, NO, nil,
minAppVersion, self->_URLScheme, nil);
}
}

NSString *deepLinkString = result[kFDLResolvedLinkDeepLinkURLKey];
NSString *minAppVersion = result[kFDLResolvedLinkMinAppVersionKey];
NSString *utmSource = result[kFDLAnalyticsDataSourceKey];
NSString *utmMedium = result[kFDLAnalyticsDataMediumKey];
NSString *utmCampaign = result[kFDLAnalyticsDataCampaignKey];
resolvedURL = FIRDLDeepLinkURLWithInviteID(invitationIDString, deepLinkString, utmSource,
utmMedium, utmCampaign, NO, nil, minAppVersion,
self->_URLScheme, nil);
}
}
handler(resolvedURL, error);
};
handler(resolvedURL, extractedError);
};

NSString *requestURLString =
[NSString stringWithFormat:@"%@/reopenAttribution%@", kiOSReopenRestBaseUrl,
Expand Down Expand Up @@ -242,13 +283,14 @@ - (void)convertInvitation:(NSString *)invitationID
}
};

FIRNetworkRequestCompletionHandler convertInvitationCallback = ^(NSData *data, NSError *error) {
if (handler) {
dispatch_async(dispatch_get_main_queue(), ^{
handler(error);
});
}
};
FIRNetworkRequestCompletionHandler convertInvitationCallback =
^(NSData *data, NSURLResponse *response, NSError *error) {
if (handler) {
dispatch_async(dispatch_get_main_queue(), ^{
handler(error);
});
}
};

NSString *requestURL = [NSString stringWithFormat:@"%@/convertInvitation%@", kApiaryRestBaseUrl,
FIRDynamicLinkAPIKeyParameter(_APIKey)];
Expand All @@ -270,7 +312,7 @@ - (void)sendRequestWithBaseURLString:(NSString *)baseURL
stringWithFormat:@"%@/%@%@", baseURL, endpointPath, FIRDynamicLinkAPIKeyParameter(_APIKey)];

FIRNetworkRequestCompletionHandler completeInvitationByDeviceCallback =
^(NSData *data, NSError *error) {
^(NSData *data, NSURLResponse *response, NSError *error) {
if (error || !data) {
dispatch_async(dispatch_get_main_queue(), ^{
handler(nil, nil, error);
Expand Down
35 changes: 25 additions & 10 deletions FirebaseDynamicLinks/Sources/FIRDynamicLinks.m
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,10 @@ - (nullable FIRDynamicLink *)dynamicLinkFromCustomSchemeURL:(NSURL *)url {
return nil;
}

- (nullable FIRDynamicLink *)dynamicLinkFromUniversalLinkURL:(NSURL *)url {
- (nullable FIRDynamicLink *)
dynamicLinkInternalFromUniversalLinkURL:(NSURL *)url
completion:
(nullable FIRDynamicLinkUniversalLinkHandler)completion {
if ([self canParseUniversalLinkURL:url]) {
if (url.query.length > 0) {
NSDictionary *parameters = FIRDLDictionaryFromQuery(url.query);
Expand All @@ -414,8 +417,10 @@ - (nullable FIRDynamicLink *)dynamicLinkFromUniversalLinkURL:(NSURL *)url {
[self.dynamicLinkNetworking
resolveShortLink:url
FDLSDKVersion:FIRFirebaseVersion()
completion:^(NSURL *_Nullable resolverURL, NSError *_Nullable resolverError){
// Nothing to do
completion:^(NSURL *_Nullable resolverURL, NSError *_Nullable resolverError) {
if (completion) {
completion(dynamicLink, resolverError);
}
}];
#ifdef GIN_SCION_LOGGING
FIRDLLogEventToScion(FIRDLLogEventAppOpen, parameters[kFIRDLParameterSource],
Expand All @@ -427,9 +432,21 @@ - (nullable FIRDynamicLink *)dynamicLinkFromUniversalLinkURL:(NSURL *)url {
}
}
}
if (completion) {
completion(nil, nil);
}
return nil;
}

- (nullable FIRDynamicLink *)dynamicLinkFromUniversalLinkURL:(NSURL *)url {
return [self dynamicLinkInternalFromUniversalLinkURL:url completion:nil];
}

- (void)dynamicLinkFromUniversalLinkURL:(NSURL *)url
completion:(FIRDynamicLinkUniversalLinkHandler)completion {
[self dynamicLinkInternalFromUniversalLinkURL:url completion:completion];
}

- (BOOL)handleUniversalLink:(NSURL *)universalLinkURL
completion:(FIRDynamicLinkUniversalLinkHandler)completion {
if ([self matchesShortLinkFormat:universalLinkURL]) {
Expand All @@ -448,14 +465,12 @@ - (BOOL)handleUniversalLink:(NSURL *)universalLinkURL
}];
return YES;
} else {
FIRDynamicLink *dynamicLink = [self dynamicLinkFromUniversalLinkURL:universalLinkURL];
if (dynamicLink) {
completion(dynamicLink, nil);
return YES;
}
[self dynamicLinkFromUniversalLinkURL:universalLinkURL completion:completion];
BOOL canHandleUniversalLink =
[self canParseUniversalLinkURL:universalLinkURL] && universalLinkURL.query.length > 0 &&
FIRDLDictionaryFromQuery(universalLinkURL.query)[kFIRDLParameterLink];
return canHandleUniversalLink;
}

return NO;
}

- (void)resolveShortLink:(NSURL *)url completion:(FIRDynamicLinkResolverHandler)completion {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,21 @@ NS_SWIFT_NAME(DynamicLinks)
- (nullable FIRDynamicLink *)dynamicLinkFromCustomSchemeURL:(NSURL *)url
NS_SWIFT_NAME(dynamicLink(fromCustomSchemeURL:));

/**
* @method dynamicLinkFromUniversalLinkURL:completion:
* @abstract Get a Dynamic Link from a universal link URL. This method parses universal link
* URLs, for instance,
* "https://example.page.link?link=https://www.google.com&ibi=com.google.app&ius=comgoogleapp".
* It is suggested to call it inside your |UIApplicationDelegate|'s
* |application:continueUserActivity:restorationHandler:| method.
* @param url Custom scheme URL.
* @param completion A block that handles the outcome of attempting to get a Dynamic Link from a
* universal link URL.
*/
- (void)dynamicLinkFromUniversalLinkURL:(NSURL *)url
completion:(FIRDynamicLinkUniversalLinkHandler)completion
NS_SWIFT_NAME(dynamicLink(fromUniversalLink:completion:));

/**
* @method dynamicLinkFromUniversalLinkURL:
* @abstract Get a Dynamic Link from a universal link URL. This method parses universal link
Expand All @@ -78,12 +93,12 @@ NS_SWIFT_NAME(DynamicLinks)
* @return Dynamic Link object if the URL is valid and has link parameter, otherwise nil.
*/
- (nullable FIRDynamicLink *)dynamicLinkFromUniversalLinkURL:(NSURL *)url
NS_SWIFT_NAME(dynamicLink(fromUniversalLink:));
NS_SWIFT_NAME(dynamicLink(fromUniversalLink:))
DEPRECATED_MSG_ATTRIBUTE("Use dynamicLinkFromUniversalLinkURL:completion: instead.");

/**
* @method handleUniversalLink:completion:
* @abstract Convenience method to handle a Universal Link whether it is long or short. A long link
* will call the handler immediately, but a short link may not.
* @abstract Convenience method to handle a Universal Link whether it is long or short.
* @param url A Universal Link URL.
* @param completion A block that handles the outcome of attempting to create a FIRDynamicLink.
* @return YES if FIRDynamicLinks is handling the link, otherwise, NO.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ - (void)testResolveShortLinkServiceCompletionDoesntCrashWhenNilDataIsRetrieved {
void (^executeRequestBlock)(id, NSDictionary *, NSString *, FIRNetworkRequestCompletionHandler) =
^(id p1, NSDictionary *requestBody, NSString *requestURLString,
FIRNetworkRequestCompletionHandler handler) {
handler(nil, nil);
handler(nil, nil, nil);
};

SEL executeRequestSelector = @selector(executeOnePlatformRequest:forURL:completionHandler:);
Expand Down
Loading

0 comments on commit 77dae0b

Please sign in to comment.