-
Notifications
You must be signed in to change notification settings - Fork 6k
Support iOS universal links route deep linking #27874
Conversation
d9521e5
to
1e1786f
Compare
openURL:(NSURL*)url | ||
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options | ||
infoPlistGetter:(NSDictionary* (^)())infoPlistGetter { | ||
if ([_lifeCycleDelegate application:application openURL:url options:options]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is now shared between two app delegate methods. Move the method-specific _lifeCycleDelegate
check up one level to -application:openURL:options:
.
infoPlistGetter:^NSDictionary*() { | ||
return [[NSBundle mainBundle] infoDictionary]; | ||
}]; | ||
if ([_lifeCycleDelegate application:application openURL:url options:options]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(it was moved here)
1e1786f
to
3c1f65c
Compare
if (userActivity.activityType == NSUserActivityTypeBrowsingWeb) { | ||
return NO; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not catching why this is here. It sounds like NSUserActivityTypeBrowsingWeb
is associated with universal links? Wouldn't you want this? I see this behavior matches what you want in your test so I assume it's true, I'm just not familiar with the API.
Maybe a few words as to why we return NO here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a reason to not process NSUserActivityTypeBrowsingWeb
so I removed this and the test.
https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app
We can always add it back later if there's some good reason to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds fine with me, we could wait a bit more to give @AlBlanc 24 hours to respond. He's probably celebrating the France basketball teams win =)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking I can merge this now and put the additional PR if should be excluded. Based on my reading of https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app it shouldn't be.
But yeah I can wait too, it's not a rush...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to merge this. I'll change it if we hear we need to exclude NSUserActivityTypeBrowsingWeb
for some reason.
OCMReject([navigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]); | ||
} | ||
|
||
- (void)testUniversalLinkPushRoute { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 2 tests are very similar, maybe it's worth considering pulling out a helper function to remove some of the boilerplate so the differences are more apparent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pulled the boilderplate in all these tests up into setUp
. Hopefully it's easier to read now.
3c1f65c
to
bee48ca
Compare
- (BOOL)application:(UIApplication*)application | ||
openURL:(NSURL*)url | ||
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options | ||
infoPlistGetter:(NSDictionary* (^)())infoPlistGetter; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wound up getting rid of this test injection helper and mocking out -[NSBundle objectForInfoDictionaryKey:]
instead.
OCMReject([navigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]); | ||
} | ||
|
||
- (void)testUniversalLinkPushRoute { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pulled the boilderplate in all these tests up into setUp
. Hopefully it's easier to read now.
|
||
// Retain callback until the tests are done. | ||
// https://github.com/flutter/flutter/issues/74267 | ||
@property(strong) id mockEngineFirstFrameCallback; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only just landed #27854 but this is probably a better name than blockNoInvoker
. Open to suggestions though!
return YES; | ||
} else if (!IsDeepLinkingEnabled(infoPlistGetter())) { | ||
- (BOOL)openURL:(NSURL*)url { | ||
NSNumber* isDeepLinkingEnabled = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was able to get rid of the static function here. -[NSBundle objectForInfoDictionaryKey:]
is now mocked in the tests.
arguments:@"/custom/route?query=test"]); | ||
} | ||
|
||
- (void)testLaunchUrlWithDeepLinkingNotSet { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New test.
OCMReject([self.mockNavigationChannel invokeMethod:OCMOCK_ANY arguments:OCMOCK_ANY]); | ||
} | ||
|
||
- (void)testLaunchUrlWithDeepLinkingDisabled { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New test.
bee48ca
to
673d3eb
Compare
Hi @jmagman |
2.6.0-0.0.pre |
Hi @jmagman The deep links works fine when I tap the link from email app. The issue is if I attach the link to push notification and tap on incoming push message -> it still opens the webview. Is this ok for current implementation? |
@vasilich6107 can you file a new issue with reproduction steps? |
No problem. Will do |
@vasilich6107 What setup and configuration did you do to get the deep links working (for links from an email)? |
@janjoosse thanks for support |
@vasilich6107 Did you open the issue? I'm also having problems with deep links when they are in foreground, after deep link is fired (either from push notification or CLI) |
I'm using flutter 2.10.1 and when I request: it open the app but the view is not push based on the path as expected (it works perfectly on android). Is this still working in 2.10 ? FlutterDeepLinkingEnabled is set to true for ios. It's what I need to get the view automatically pushed right ? I use onGenerateRoute for named routes. EDIT: by removing uni_links lib from my project it now works ! |
@dragouf Are the instructions at https://docs.flutter.dev/development/ui/navigation/deep-linking#enable-deep-linking-on-ios still valid for universal links? I don't see why we need the custom scheme. Do we still need the CFBundleURLTypes entry for universal links? |
@percula what they call deep links is not universal links. Deep links use custom scheme when universal links (or app links for android) use https. If you want to use https instead of custom scheme follow the readme of this library to activate it: https://pub.dev/packages/uni_links but do not install the library if you want the view to be pushed automatically based on the link path (the library seems to conflicts with this mechanism). so after I enabled universal links I use named routes with something like:
and
settings.name will contain the path from your link. |
Support deep linking/route pushing via universal links, which are registered
http
andhttps
scheme URLs, in addition to the already-supported custom schemes.If the URL isn't handled by the life cycle delegate, and isn't from web browsing, send
pushRoute
to the app.Share the open link/routing logic between
-application:continueUserActivity:restorationHandler:
and-application:openURL:options:
.Fixes flutter/flutter#82550
Pre-launch Checklist
writing and running engine tests.
///
).