在 didFinishLaunchingWithOptions 之后几秒钟调用应用程序 openURL
Posted
技术标签:
【中文标题】在 didFinishLaunchingWithOptions 之后几秒钟调用应用程序 openURL【英文标题】:Application openURL gets called a few seconds after didFinishLaunchingWithOptions 【发布时间】:2017-02-20 13:16:33 【问题描述】:我的应用程序中有一个深层链接功能,在一种情况下运行良好。 根据打开应用程序的 url,我有 3 个不同的入职页面。 因此,当应用程序启动时,我需要知道哪个链接(如果有)打开了应用程序,然后显示正确的入职页面。问题是我需要知道在方法中显示什么屏幕:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
但我只能知道深层链接是否打开了应用程序
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
在调用didFinishLaunchingWithOptions
5 秒后被调用(我计算了秒数)。所以我有 5 秒的时间看到错误的入职页面,直到调用 openURL
(如果它会被调用)。
所以我的问题是:有什么方法可以知道应用程序是在didFinishLaunchingWithOptions
之前还是期间从 URL 启动的?
顺便说一句,当应用从深层链接打开时,didFinishLaunchingWithOptions
中的 launchOptions
为零
【问题讨论】:
你好 aviv_eik 我也在实现相同的功能并面临同样的问题。你能帮我整理一下吗?提前致谢 【参考方案1】:您正在寻找的启动选项键是 UIApplicationLaunchOptionsURLKey
(Objective-C) / UIApplicationLaunchOptionsKey.url
(Swift)。
如果您的目标是 ios 9 及更高版本,您只需拦截来自
application:didFinishLaunchingWithOptions:
(如果应用程序尚未在内存中)
application:openURL:options:
(如果应用程序已经在后台)。
这是UIApplicationDelegate
的简约实现,应该涵盖这两种情况 - 请注意,为了清楚起见,已省略了许多不相关的逻辑:
目标-C:
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
NSURL *url = launchOptions[UIApplicationLaunchOptionsURLKey];
if (url)
// TODO: handle URL from here
return YES;
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
// TODO: handle URL from here
return YES;
@end
斯威夫特 5:
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
if let url = launchOptions?[.url] as? URL
// TODO: handle URL from here
return true
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool
// TODO: handle URL from here
return true
【讨论】:
当我从深度链接打开我的应用程序时,didFinishLaunchingWithOptions 中的“launchOptions”为零,但“openURL”确实被触发(使用深度链接 url)。我确实在“didFinishLaunchingWithOptions”中显示了我的入职页面,你认为我应该在哪里显示应用程序启动时的第一个关键窗口 好吧,让我问一些其他问题:您是从网络浏览器打开您的应用程序吗?您的目标是什么最低 iOS 版本?注意 application:didFinishLaunchingWithOptions: 每次运行时只调用一次。如果您的应用程序已经在后台,则 application:openURL:options: 将被调用。我对窗口设置的评论仅适用于您将情节提要作为“主界面”设置的情况。如果你是从 application:didFinishLaunchingWithOptions: 自己设置界面,你会没事的,请忽略评论。 为了清晰起见,我改进了我的答案 - 它已经在运行 iOS 9.3.4 和 iOS 10.3 的设备上使用 Xcode 8.3 进行了测试,适用于 Objective-C 和 Swift 构建。确保您确实在您的Info.plist
的URL Types
> URL Schemes
中设置了一个值(例如“my-app”),在您的设备上构建应用程序然后杀死它,然后尝试打开例如任何网络浏览器中的“my-app://”。
虽然在我编写 cmets 时这是一个老问题,但仍然想警告新读者,没有必要同时处理 application:didFinishLaunchingWithOptions:
和 application(_:open:options:)
中的 URL。只需检查application(_:open:options:)
就足够了。 developer.apple.com/documentation/uikit/uiapplicationdelegate#//…
是的。 @KutayDemireren 似乎是对的 - 即使应用程序之前被杀死,也会调用 application(_:open:options:) 【参考方案2】:
我刚刚在 iOS 13 中遇到了类似的问题,但在 iOS 13 中情况发生了变化,因为引入了 UIWindowSceneDelegate 并且现在可以完成之前由 UIApplicationDelegate
完成的一些工作(取决于您的应用程序设置)。
@Olivier 在这个线程中的answer 对我来说仍然非常有用,因为它指出了处理 URL 方案的两种情况;即当应用程序尚未在内存中时,调用application:didFinishLaunchingWithOptions:
,当应用程序已经加载并在后台时,第二种情况调用application:openURL:options:
。
所以,正如我在上面提到的,如果您使用 XCode 11 生成的默认应用程序模板,自 iOS 13 以来情况会有所不同。我不会在这里详细介绍,所以这里有一个关于题目:Understanding the iOS 13 Scene Delegate.
但是,如果您对场景使用新方法,则修改的关键方法是scene(_:willConnectTo:options:)
(文档here)和scene(_:openURLContexts:)
(文档here)。前者是在应用程序尚未加载时对 URL 方案进行操作的位置(因此它有点取代 application:didFinishLaunchingWithOptions:
),而后者是当应用程序已经在后台时获取 URL 的位置,而 URL 方案是调用(所以这个替换了application:openURL:options:
)。
使用scene(_:willConnectTo:options:)
,您可以执行以下操作来查找 URL 方案的 URL(如果有):
if let url = connectionOptions.urlContexts.first?.url
// handle
对于scene(_:openURLContexts:)
,您可以查看URLContexts
集合的内部。
我希望这会有所帮助!
【讨论】:
【参考方案3】:以前的好主意。 我做了一些测试..
我确认 iOS 13 的几率和错误。
序言: 我启用了 plist 上的所有标志: (来自https://forums.developer.apple.com/thread/118932)
... UIFileSharingEnabled LSSupportsOpeningDocumentsInPlace UISupportsDocumentBrowser .. 并在 plist 中添加了所有类型:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeIconFiles</key>
<array/>
<key>CFBundleTypeName</key>
<string>abc File</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>org.example.app.document.abc</string>
</array>
</dict>
</array>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>abc File</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>org.example.app.document.abc</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>abc</string>
</array>
</dict>
</dict>
</array>
我在这里登录:
1)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
// Override point for customization after application launch.
print(documentsDir())
if let url = launchOptions?[.url] as? URL
// TODO: handle URL from here
openWriteAndCloseLog(msg: "1 " + url.absoluteString, withTimestamp: true)
return true
2)
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool
// TODO: handle URL from here
openWriteAndCloseLog(msg: "2 " + url.absoluteString, withTimestamp: true)
return true
3)
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
if let url = connectionOptions.urlContexts.first?.url
// handle
openWriteAndCloseLog(msg: "3 " + url.absoluteString, withTimestamp: true)
guard let _ = (scene as? UIWindowScene) else return
似乎我们只通过了 3(根据我的调试日志,我可以看到内部文档,正如我通过 iTunes 共享的那样)
我做了一个小演示应用来测试它。
https://github.com/ingconti/DocumentBroswerSampleApp
您可以从(例如,mal..)打开附件 你会看到:
【讨论】:
以上是关于在 didFinishLaunchingWithOptions 之后几秒钟调用应用程序 openURL的主要内容,如果未能解决你的问题,请参考以下文章
NOIP 2015 & SDOI 2016 Round1 & CTSC 2016 & SDOI2016 Round2游记