Je développe actuellement une application qui doit ouvrir un navigateur pour afficher une page Web . Pour ce faire, j'utilise la méthode [UIApplication sharedApplication] openURL
avec une URL.
Dans iOS 6, cela fonctionne parfaitement, mais dans iOS 7, l'application se bloque pendant plus de 10 secondes, puis le navigateur s'ouvre et tout va bien.
Cela se produit à l'aide d'un provisionnement ad hoc. Quelqu'un sur Internet a fait remarquer qu'il s'agissait d'un problème connu, cependant, un seul commentaire était tout ce que je pouvais trouver concernant ce problème.
J'ai constaté le même problème lors de l'appel - [UIApplication openUrl:] depuis le délégué d'application didReceiveRemoteNotification: ou didFinishLaunchingWithOptions: depuis iOS 7.
Je l'ai résolu en retardant un peu l'appel en utilisant GCD:
// objc
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] openURL:url];
});
Il laisse un peu de temps à iOS pour achever l’initialisation de l’application et l’appel s’effectue ensuite sans problème. Ne me demande pas pourquoi.
Est-ce que cela fonctionne pour vous?
Comme cette réponse est souvent vue, j'ai ajouté la version Swift:
// Swift
dispatch_async(dispatch_get_main_queue()) {
UIApplication.sharedApplication().openURL(url)
}
J'ai vu le même problème dans iOS 7. Ma solution n'est que légèrement différente de celles déjà proposées. En utilisant performSelector
avec un délai de seulement 0,1 seconde, l'application ouvre immédiatement l'URL.
[self performSelector:@selector(methodToRedirectToURL:) withObject:url afterDelay:0.1];
Avait exactement les mêmes symptômes que vous avez décrits: fonctionnait bien sur iOS6, mais environ 10 secondes se bloque sur iOS7 S'avère être un problème de thread.
Nous émettions le [UIApplication sharedApplication] openURL
directement à partir de la méthode AppDelegate applicationDidBecomeActive()
. Déplacer ceci vers un fil d’arrière-plan a instantanément résolu le problème:
- (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]];
}
Merci pour le conseil de tous les gars ci-dessus, voici comment je l'ai résolu dans Xamarin.iOS (et Xamarin.Forms). La solution est inspirée par ce que les gars ont discuté ci-dessus, et espère que cela aidera d'autres personnes confrontées au même problème mais utilisant 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));
});
});
}
}
</ pre> </ code>
Après une analyse comparative très rapide, j'ai trouvé que la méthode @lidsinkers était clairement la plus rapide. Surtout quand j'ai remplacé le délai de 0.1
par 0.001
.
J'ai donc décidé de le convertir en code Swift:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.001 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
UIApplication.sharedApplication().openURL(url)
}
Méthode complète:
/// 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)
}
}
Pour ios 9
if([[UIApplication sharedApplication] canOpenURL:url]){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[UIApplication sharedApplication] openURL:url];
});
}
cela semble avoir fonctionné pour moi
J'ai trouvé qu'il serait préférable de l'utiliser depuis 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) {
}];
}
});
Voici la réponse dans Swift 3.0 avec une vérification pour voir si nous pouvons ouvrir l'URL ou non.
guard let url = URL(string: myURLString) else {
return
}
if UIApplication.shared.canOpenURL(url) {
DispatchQueue.main.async {
UIApplication.shared.openURL(url)
}
}
Si vous mettez l'action "openURL" dans la méthode viewDidLoad, celle-ci s'exécutera lentement. Vous pouvez le mettre dans la méthode viewDidAppear. Ou, vous pouvez utiliser le GCD dans la méthode viewDidLoad comme ci-dessous:
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] openURL:url];
});
Swift 4.1 avec vérification de la version du système d'exploitation.
DispatchQueue.main.async() {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url)
} else {
UIApplication.shared.openURL(url)
}
}
Pour Swift3
DispatchQueue.main.async {
UIApplication.shared.openURL(url)
}