I'm currently developing an App, that needs to open a browser to display a webpage. To do that i use the [UIApplication sharedApplication] openURL
method with an url.
我目前正在开发一个应用,需要打开浏览器才能显示网页。为此,我使用带有url的[UIApplication sharedApplication] openURL方法。
In iOS 6 this works perfectly, but in iOS 7 it freezes the app for 10+ seconds, then opens the browser and all is good.
在ios6系统中,这个功能很好,但在ios7系统中,它会将应用程序冻结10秒以上,然后打开浏览器,一切都很好。
This happens using ad hoc provisioning. Someone on the internet commented that this was a known problem, however, that one comment was all i could find regarding this problem.
这是使用临时配置实现的。有人在网上评论说,这是一个已知的问题,但是,关于这个问题,我只能找到一个评论。
9 个解决方案
#1
90
I noticed the same problem when calling -[UIApplication openUrl:] from the Application Delegate didReceiveRemoteNotification: or didFinishLaunchingWithOptions: since iOS 7.
当我从应用委托didReceiveRemoteNotification:或者didFinishLaunchingWithOptions: iOS 7上调用-[UIApplication openUrl:]时,我注意到了同样的问题。
I solved it by delaying the call a bit using GCD :
我用GCD的方式来解决这个问题:
// objc
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] openURL:url];
});
It let iOS some time to finish application initialization and the call is then performed without any problem. Don't ask me why.
它让iOS有一段时间来完成应用程序的初始化,然后在没有任何问题的情况下执行调用。不要问我为什么。
Does this works for you ?
这对你有用吗?
As this answer is often seen, I added the swift version:
由于这个答案经常被看到,我添加了swift版本:
// swift
dispatch_async(dispatch_get_main_queue()) {
UIApplication.sharedApplication().openURL(url)
}
#2
10
I have seen the same issue in iOS 7. My solution is only slightly different from those already proposed. By using performSelector
with just a 0.1 second delay, the app immediately opens the URL.
我在ios7中也见过同样的问题。我的解决方案与已经提出的方案稍有不同。通过使用只延迟0.1秒的performSelector,应用程序立即打开URL。
[self performSelector:@selector(methodToRedirectToURL:) withObject:url afterDelay:0.1];
#3
9
Had the exact same symptoms that you described: worked fine on iOS6, but ~10 second hang on iOS7. Turns out to be a threading issue.
和你描述的症状一模一样:iOS6工作正常,但iOS7等10秒。原来是一个线程问题。
We were issuing the [UIApplication sharedApplication] openURL
directly from the AppDelegate method applicationDidBecomeActive()
. Moving this to a background thread instantly solved the problem:
我们直接从AppDelegate方法applicationDidBecomeActive()发出[UIApplication sharedApplication] openURL。将其移动到后台线程立即解决了这个问题:
- (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]];
}
#4
5
Thanks for the advise from all the guys above, this is how I solved it in Xamarin.iOS (and Xamarin.Forms). The solution is inspired by what the guys have discussed above, and hope it helps others facing the same problem but using Xamarin.
谢谢以上所有人的建议,这就是我在《海蓝宝石》中解决的方法。iOS(Xamarin.Forms)。这个解决方案的灵感来自于上面的讨论,希望它能帮助其他人面对同样的问题而不是使用海蓝宝石。
[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));
});
});
}
}
}
#5
4
After doing some very quick benchmarking I found @lidsinkers method to quite clearly be the fastest. Especially when I replaced the delay of 0.1
with 0.001
.
在做了一些非常快速的基准测试之后,我发现@lidsinkers方法显然是最快的。特别是我用0。001替换了0。1的延迟。
Thus I decided to convert it to Swift code:
于是我决定将其转换为Swift code:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.001 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
UIApplication.sharedApplication().openURL(url)
}
Full method:
完整的方法:
/// 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)
}
}
#6
2
For ios 9
ios 9
if([[UIApplication sharedApplication] canOpenURL:url]){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[UIApplication sharedApplication] openURL:url];
});
}
this seems to have worked for me
这似乎对我起了作用
#7
1
I found it will get better to use this since iOS 10.
我发现在ios10之后使用它会更好。
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) {
}];
}
});
#8
0
If you put the "openURL" action in the viewDidLoad method, then it sure will execute slowly. You can put it in the viewDidAppear method. Or, you can use the GCD in the viewDidLoad method like below:
如果在viewDidLoad方法中放置“openURL”操作,那么它肯定会缓慢执行。你可以把它放到viewDidAppear方法中。或者,您可以在viewDidLoad方法中使用GCD,如下所示:
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] openURL:url];
});
#9
0
Here is the answer in Swift 3.0 with a check to see if we can open the URL or not.
这是Swift 3.0的答案,检查一下我们是否可以打开URL。
guard let url = URL(string: myURLString) else {
return
}
if UIApplication.shared.canOpenURL(url) {
DispatchQueue.main.async {
UIApplication.shared.openURL(url)
}
}
#1
90
I noticed the same problem when calling -[UIApplication openUrl:] from the Application Delegate didReceiveRemoteNotification: or didFinishLaunchingWithOptions: since iOS 7.
当我从应用委托didReceiveRemoteNotification:或者didFinishLaunchingWithOptions: iOS 7上调用-[UIApplication openUrl:]时,我注意到了同样的问题。
I solved it by delaying the call a bit using GCD :
我用GCD的方式来解决这个问题:
// objc
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] openURL:url];
});
It let iOS some time to finish application initialization and the call is then performed without any problem. Don't ask me why.
它让iOS有一段时间来完成应用程序的初始化,然后在没有任何问题的情况下执行调用。不要问我为什么。
Does this works for you ?
这对你有用吗?
As this answer is often seen, I added the swift version:
由于这个答案经常被看到,我添加了swift版本:
// swift
dispatch_async(dispatch_get_main_queue()) {
UIApplication.sharedApplication().openURL(url)
}
#2
10
I have seen the same issue in iOS 7. My solution is only slightly different from those already proposed. By using performSelector
with just a 0.1 second delay, the app immediately opens the URL.
我在ios7中也见过同样的问题。我的解决方案与已经提出的方案稍有不同。通过使用只延迟0.1秒的performSelector,应用程序立即打开URL。
[self performSelector:@selector(methodToRedirectToURL:) withObject:url afterDelay:0.1];
#3
9
Had the exact same symptoms that you described: worked fine on iOS6, but ~10 second hang on iOS7. Turns out to be a threading issue.
和你描述的症状一模一样:iOS6工作正常,但iOS7等10秒。原来是一个线程问题。
We were issuing the [UIApplication sharedApplication] openURL
directly from the AppDelegate method applicationDidBecomeActive()
. Moving this to a background thread instantly solved the problem:
我们直接从AppDelegate方法applicationDidBecomeActive()发出[UIApplication sharedApplication] openURL。将其移动到后台线程立即解决了这个问题:
- (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]];
}
#4
5
Thanks for the advise from all the guys above, this is how I solved it in Xamarin.iOS (and Xamarin.Forms). The solution is inspired by what the guys have discussed above, and hope it helps others facing the same problem but using Xamarin.
谢谢以上所有人的建议,这就是我在《海蓝宝石》中解决的方法。iOS(Xamarin.Forms)。这个解决方案的灵感来自于上面的讨论,希望它能帮助其他人面对同样的问题而不是使用海蓝宝石。
[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));
});
});
}
}
}
#5
4
After doing some very quick benchmarking I found @lidsinkers method to quite clearly be the fastest. Especially when I replaced the delay of 0.1
with 0.001
.
在做了一些非常快速的基准测试之后,我发现@lidsinkers方法显然是最快的。特别是我用0。001替换了0。1的延迟。
Thus I decided to convert it to Swift code:
于是我决定将其转换为Swift code:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.001 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
UIApplication.sharedApplication().openURL(url)
}
Full method:
完整的方法:
/// 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)
}
}
#6
2
For ios 9
ios 9
if([[UIApplication sharedApplication] canOpenURL:url]){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[UIApplication sharedApplication] openURL:url];
});
}
this seems to have worked for me
这似乎对我起了作用
#7
1
I found it will get better to use this since iOS 10.
我发现在ios10之后使用它会更好。
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) {
}];
}
});
#8
0
If you put the "openURL" action in the viewDidLoad method, then it sure will execute slowly. You can put it in the viewDidAppear method. Or, you can use the GCD in the viewDidLoad method like below:
如果在viewDidLoad方法中放置“openURL”操作,那么它肯定会缓慢执行。你可以把它放到viewDidAppear方法中。或者,您可以在viewDidLoad方法中使用GCD,如下所示:
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] openURL:url];
});
#9
0
Here is the answer in Swift 3.0 with a check to see if we can open the URL or not.
这是Swift 3.0的答案,检查一下我们是否可以打开URL。
guard let url = URL(string: myURLString) else {
return
}
if UIApplication.shared.canOpenURL(url) {
DispatchQueue.main.async {
UIApplication.shared.openURL(url)
}
}