我目前正在开发一个需要打开浏览器才能显示网页的应用程序。为此,我使用[UIApplication sharedApplication] openURL
带有 url 的方法。
在 iOS 6 中,这可以完美运行,但在 iOS 7 中,它会冻结应用程序 10 多秒,然后打开浏览器,一切都很好。
这使用临时配置发生。互联网上有人评论说这是一个已知问题,但是,关于这个问题,我只能找到一条评论。
从 iOS 7 开始,从 Application Delegate didReceiveRemoteNotification: 或 didFinishLaunchingWithOptions: 调用 -[UIApplication openUrl:] 时,我注意到了同样的问题。
我通过使用 GCD 稍微延迟调用来解决它:
// objc
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] openURL:url];
});
它让 iOS 有一些时间来完成应用程序初始化,然后调用没有任何问题。不要问我为什么。
这对你有用吗?
由于经常看到这个答案,我添加了 swift 版本:
// swift
dispatch_async(dispatch_get_main_queue()) {
UIApplication.sharedApplication().openURL(url)
}
我在 iOS 7 中看到了同样的问题。我的解决方案与已经提出的解决方案略有不同。通过performSelector
仅使用 0.1 秒的延迟,应用程序会立即打开 URL。
[self performSelector:@selector(methodToRedirectToURL:) withObject:url afterDelay:0.1];
有与您描述的完全相同的症状:在 iOS6 上运行良好,但在 iOS7 上挂起约 10 秒。原来是线程问题。
[UIApplication sharedApplication] openURL
我们直接从 AppDelegate 方法发出 applicationDidBecomeActive()
。将此移动到后台线程立即解决了问题:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
...
// hangs for 10 seconds
// [[UIApplication sharedApplication] openURL:[NSURL URLWithString: url]];
// Fix: use threads!
[NSThread detachNewThreadSelector:@selector(openbrowser_in_background:) toTarget:self withObject:url];
...
}
- (void)openbrowser_in_background:(NSString *)url
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: url]];
}
感谢以上所有人的建议,这就是我在 Xamarin.iOS(和 Xamarin.Forms)中解决它的方法。该解决方案的灵感来自上面讨论的内容,并希望它可以帮助其他面临相同问题但使用 Xamarin 的人。
[Register("AppDelegate")]
public class AppDelegate
{
....
public override bool OpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
{
// We do some logic to respond to launching app, and return to that app.
Task.Delay(500).ContinueWith(_ => {
this.InvokeOnMainThread( () => {
UIApplication.SharedApplication.OpenUrl(NSUrl.FromString(openUri));
});
});
}
}
在做了一些非常快速的基准测试之后,我发现@lidsinkers 方法显然是最快的。特别是当我用 替换延迟0.1
时0.001
。
因此我决定将其转换为 Swift 代码:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.001 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
UIApplication.sharedApplication().openURL(url)
}
完整方法:
/// An attempt at solving 'openUrl()' freeze problem
func lidsinkerOpenURL(url: NSURL) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.001 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
UIApplication.sharedApplication().openURL(url)
}
}
对于 iOS 9
if([[UIApplication sharedApplication] canOpenURL:url]){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[UIApplication sharedApplication] openURL:url];
});
}
这似乎对我有用
我发现从 iOS 10 开始使用它会变得更好。
dispatch_async(dispatch_get_main_queue(), ^{
if ([[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."].firstObject integerValue] < 10) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel:..."]];
} else {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel:..."] options:@{} completionHandler:^(BOOL success) {
}];
}
});
如果你把“openURL”动作放在 viewDidLoad 方法中,那么它肯定会执行得很慢。你可以把它放在 viewDidAppear 方法中。或者,您可以在 viewDidLoad 方法中使用 GCD,如下所示:
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] openURL:url];
});
这是 Swift 3.0 中的答案,检查我们是否可以打开 URL。
guard let url = URL(string: myURLString) else {
return
}
if UIApplication.shared.canOpenURL(url) {
DispatchQueue.main.async {
UIApplication.shared.openURL(url)
}
}
带有操作系统版本检查的 Swift 4.1。
DispatchQueue.main.async() {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url)
} else {
UIApplication.shared.openURL(url)
}
}
对于 Swift3
DispatchQueue.main.async {
UIApplication.shared.openURL(url)
}