Support deeplinking using universal links

Summary:
## See the following [Proposal](https://fburl.com/gdoc/z90ch5in)

## Problem

We want to add support for universal links.
In order to do that, developers who have app events integration (AEM) will be required to add a call to the `openURL:` on the SDK delegate class from `application(_:continue:restorationHandler:)` in the short term.

We would like to simplify things for app developers since extracting the webpage URL from NSUserActivity may cause confusion and errors for deep linking.

## Solution

The better way is to just introduce a method with a similar signature to `application(_:continue:restorationHandler:)` in the SDK delegate.
Developers could simply invoke that method in order to have the universal link processed.

By doing that, we will to make FB SDK more accessible to developers.

## Testing

See the test plan section

Reviewed By: samodom

Differential Revision: D34786435

fbshipit-source-id: 289fea5ecc9e106fe0c9fcc94bf2a65b0c07c0ab
This commit is contained in:
Daniel Huri
2022-03-14 13:40:41 -07:00
committed by Facebook GitHub Bot
parent 2d60224ea1
commit d57a25a755
5 changed files with 71 additions and 2 deletions

View File

@@ -12,6 +12,27 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
[Full Changelog](https://github.com/facebook/facebook-ios-sdk/compare/v13.0.0...HEAD) [Full Changelog](https://github.com/facebook/facebook-ios-sdk/compare/v13.0.0...HEAD)
### Notable Changes
#### Added an API to support deep linking using Universal Links
In order to ensure that your app properly supports [deep linking from app ads](https://developers.facebook.com/docs/app-ads/deep-linking) with Universal Links, you will need to implement `application(_:continue:restorationHandler:)` in your App Delegate, and call `ApplicationDelegate.shared.application(_:continue:)` from your implementation.
Your change might look like the following snippet:
```swift
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
ApplicationDelegate.shared.application(application, continue: userActivity)
// Rest of implementation...
return true
}
```
## 13.0.0 ## 13.0.0
### Notable Changes ### Notable Changes

View File

@@ -189,6 +189,14 @@ static UIApplicationState _applicationState;
#pragma mark - UIApplicationDelegate #pragma mark - UIApplicationDelegate
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
{
if (userActivity.activityType != NSUserActivityTypeBrowsingWeb) {
return NO;
}
return [self application:application openURL:userActivity.webpageURL options:@{}];
}
- (BOOL)application:(UIApplication *)application - (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options

View File

@@ -36,6 +36,18 @@ NS_SWIFT_NAME(ApplicationDelegate)
@property (class, nonatomic, readonly, strong) FBSDKApplicationDelegate *sharedInstance @property (class, nonatomic, readonly, strong) FBSDKApplicationDelegate *sharedInstance
NS_SWIFT_NAME(shared); NS_SWIFT_NAME(shared);
/**
Call this method from the [UIApplicationDelegate application:continue:restorationHandler:] method
of the AppDelegate for your app. It should be invoked in order to properly process the web URL (universal link)
once the end user is redirected to your app.
@param application The application as passed to [UIApplicationDelegate application:continue:restorationHandler:].
@param userActivity The user activity as passed to [UIApplicationDelegate application:continue:restorationHandler:].
@return YES if the URL was intended for the Facebook SDK, NO if not.
*/
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity;
/** /**
Call this method from the [UIApplicationDelegate application:openURL:sourceApplication:annotation:] method Call this method from the [UIApplicationDelegate application:openURL:sourceApplication:annotation:] method
of the AppDelegate for your app. It should be invoked for the proper processing of responses during interaction of the AppDelegate for your app. It should be invoked for the proper processing of responses during interaction
@@ -49,7 +61,7 @@ NS_SWIFT_NAME(shared);
@param annotation The annotation as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:]. @param annotation The annotation as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:].
@return YES if the url was intended for the Facebook SDK, NO if not. @return YES if the URL was intended for the Facebook SDK, NO if not.
*/ */
- (BOOL)application:(UIApplication *)application - (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url openURL:(NSURL *)url
@@ -67,7 +79,7 @@ NS_SWIFT_NAME(shared);
@param options The options dictionary as passed to [UIApplicationDelegate application:openURL:options:]. @param options The options dictionary as passed to [UIApplicationDelegate application:openURL:options:].
@return YES if the url was intended for the Facebook SDK, NO if not. @return YES if the URL was intended for the Facebook SDK, NO if not.
*/ */
- (BOOL)application:(UIApplication *)application - (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url openURL:(NSURL *)url

View File

@@ -528,6 +528,33 @@ final class ApplicationDelegateTests: XCTestCase {
) )
} }
func testOpeningUniversalLinkChecksAEMFeatureAvailability() {
// See https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app
let userActivity = NSUserActivity(activityType: NSUserActivityTypeBrowsingWeb)
userActivity.webpageURL = SampleURLs.validUniversalLink
delegate.application(
UIApplication.shared,
continue: userActivity
)
XCTAssertTrue(
featureChecker.capturedFeaturesContains(.AEM),
"Opening a deep link should check if the AEM feature is enabled"
)
}
func testOpeningUniversalLinkNonBrowsingWebDoesNotCheckAEMAvailability() {
let userActivity = NSUserActivity(activityType: "Example")
userActivity.webpageURL = SampleURLs.validUniversalLink
delegate.application(
UIApplication.shared,
continue: userActivity
)
XCTAssertFalse(
featureChecker.capturedFeaturesContains(.AEM),
"Opening a deep link should check if the AEM feature is enabled"
)
}
// MARK: - Application Observers // MARK: - Application Observers
func testDefaultsObservers() { func testDefaultsObservers() {

View File

@@ -12,6 +12,7 @@ public enum SampleURLs {
// swiftlint:disable force_unwrapping // swiftlint:disable force_unwrapping
public static let valid = URL(string: "https://www.example.com")! public static let valid = URL(string: "https://www.example.com")!
public static let validApp = URL(string: "fb://test.com")! public static let validApp = URL(string: "fb://test.com")!
public static let validUniversalLink = URL(string: "https://www.test.com")!
public static let validPNG = URL(string: "https://www.example.com/babyamnimal.png")! public static let validPNG = URL(string: "https://www.example.com/babyamnimal.png")!
// swiftlint:enable force_unwrapping // swiftlint:enable force_unwrapping