J'ai besoin que mon code iPhone Objective-C détecte les erreurs Javascript dans une UIWebView. Cela inclut des exceptions non capturées, des erreurs de syntaxe lors du chargement de fichiers, des références de variables non définies, etc.
Il s'agit d'un environnement de développement, il n'a donc pas besoin d'être casher SDK. En fait, il n'a vraiment besoin que de travailler sur le simulateur.
J'ai déjà trouvé utilisé certaines des astuces WebKit cachées, par exemple exposer les objets Obj-C à JS et intercepter les popups d'alerte, mais celui-ci m'échappe toujours.
[REMARQUE: après avoir posté cela, j'ai trouvé un moyen d'utiliser un délégué de débogage. Existe-t-il un moyen de réduire les frais généraux en utilisant la console d'erreur/l'inspecteur Web?]
J'ai maintenant trouvé un moyen d'utiliser les crochets de débogage de script dans WebView (notez, PAS UIWebView). J'ai d'abord dû sous-classer UIWebView et ajouter une méthode comme celle-ci:
- (void)webView:(id)webView windowScriptObjectAvailable:(id)newWindowScriptObject {
// save these goodies
windowScriptObject = newWindowScriptObject;
privateWebView = webView;
if (scriptDebuggingEnabled) {
[webView setScriptDebugDelegate:[[YourScriptDebugDelegate alloc] init]];
}
}
Ensuite, vous devez créer une classe YourScriptDebugDelegate qui contient des méthodes comme celles-ci:
// in YourScriptDebugDelegate
- (void)webView:(WebView *)webView didParseSource:(NSString *)source
baseLineNumber:(unsigned)lineNumber
fromURL:(NSURL *)url
sourceId:(int)sid
forWebFrame:(WebFrame *)webFrame
{
NSLog(@"NSDD: called didParseSource: sid=%d, url=%@", sid, url);
}
// some source failed to parse
- (void)webView:(WebView *)webView failedToParseSource:(NSString *)source
baseLineNumber:(unsigned)lineNumber
fromURL:(NSURL *)url
withError:(NSError *)error
forWebFrame:(WebFrame *)webFrame
{
NSLog(@"NSDD: called failedToParseSource: url=%@ line=%d error=%@\nsource=%@", url, lineNumber, error, source);
}
- (void)webView:(WebView *)webView exceptionWasRaised:(WebScriptCallFrame *)frame
sourceId:(int)sid
line:(int)lineno
forWebFrame:(WebFrame *)webFrame
{
NSLog(@"NSDD: exception: sid=%d line=%d function=%@, caller=%@, exception=%@",
sid, lineno, [frame functionName], [frame caller], [frame exception]);
}
Cela a probablement un impact important sur l'exécution, car le délégué de débogage peut également fournir des méthodes à appeler pour entrer et quitter une trame de pile et pour exécuter chaque ligne de code.
Voir http://www.koders.com/noncode/fid7DE7ECEB052C3531743728D41A233A951C79E0AE.aspx pour la définition Objective-C++ de WebScriptDebugDelegate.
Ces autres méthodes:
// just entered a stack frame (i.e. called a function, or started global scope)
- (void)webView:(WebView *)webView didEnterCallFrame:(WebScriptCallFrame *)frame
sourceId:(int)sid
line:(int)lineno
forWebFrame:(WebFrame *)webFrame;
// about to execute some code
- (void)webView:(WebView *)webView willExecuteStatement:(WebScriptCallFrame *)frame
sourceId:(int)sid
line:(int)lineno
forWebFrame:(WebFrame *)webFrame;
// about to leave a stack frame (i.e. return from a function)
- (void)webView:(WebView *)webView willLeaveCallFrame:(WebScriptCallFrame *)frame
sourceId:(int)sid
line:(int)lineno
forWebFrame:(WebFrame *)webFrame;
Notez que tout cela est caché dans un cadre privé, alors n'essayez pas de mettre cela dans le code que vous soumettez à l'App Store, et soyez prêt pour un certain piratage pour le faire fonctionner.
J'ai créé une jolie petite catégorie drop-in que vous pouvez ajouter à votre projet ... Elle est basée sur la solution Robert Sanders. Gloire.
Vous pouvez le télécharger ici:
Cela devrait faciliter le débogage de votre UIWebView :)
J'ai utilisé l'excellente solution proposée par Robert Sanders: Comment mon code iPhone Objective-C peut-il être averti des erreurs Javascript dans une UIWebView?
Ce crochet pour webkit fonctionne bien également sur iPhone . Au lieu d'UIWebView standard, j'ai alloué MyUIWebView dérivé. J'avais également besoin de définir des classes cachées dans MyWebScriptObjectDelegate.h:
@class WebView;
@class WebFrame;
@class WebScriptCallFrame;
Dans l'ios sdk 4.1, la fonction:
- (void)webView:(id)webView windowScriptObjectAvailable:(id)newWindowScriptObject
est obsolète et à la place j'ai utilisé la fonction:
- (void)webView:(id)sender didClearWindowObject:(id)windowObject forFrame:(WebFrame*)frame
De plus, je reçois des avertissements ennuyeux comme "NSObject peut ne pas répondre -windowScriptObject" car l'interface de classe est masquée. Je les ignore et ça marche bien.
Une façon qui fonctionne pendant le développement si vous avez Safari v 6+ (je ne suis pas sûr de la version iOS dont vous avez besoin) est d'utiliser les outils de développement Safari et de vous connecter à UIWebView à travers lui.
Straight Forward Way: Mettez ce code au-dessus de votre contrôleur/vue qui utilise UIWebView
#ifdef DEBUG
@interface DebugWebDelegate : NSObject
@end
@implementation DebugWebDelegate
@class WebView;
@class WebScriptCallFrame;
@class WebFrame;
- (void)webView:(WebView *)webView exceptionWasRaised:(WebScriptCallFrame *)frame
sourceId:(int)sid
line:(int)lineno
forWebFrame:(WebFrame *)webFrame
{
NSLog(@"NSDD: exception: sid=%d line=%d function=%@, caller=%@, exception=%@",
sid, lineno, [frame functionName], [frame caller], [frame exception]);
}
@end
@interface DebugWebView : UIWebView
id windowScriptObject;
id privateWebView;
@end
@implementation DebugWebView
- (void)webView:(id)sender didClearWindowObject:(id)windowObject forFrame:(WebFrame*)frame
{
[sender setScriptDebugDelegate:[[DebugWebDelegate alloc] init]];
}
@end
#endif
Et puis instanciez-le comme ceci:
#ifdef DEBUG
myWebview = [[DebugWebView alloc] initWithFrame:frame];
#else
myWebview = [[UIWebView alloc] initWithFrame:frame];
#endif
L'utilisation de #ifdef DEBUG garantit qu'il ne sera pas inclus dans la version, mais je recommanderais également de le commenter lorsque vous ne l'utilisez pas car cela a un impact sur les performances. Nous remercions Robert Sanders et Prcela pour le code original
De plus, si vous utilisez ARC, vous devrez peut-être ajouter "-fno-objc-arc" pour éviter certaines erreurs de génération.
J'ai créé un rapporteur d'erreurs casher SDK qui comprend:
Il fait partie du framework QuickConnectiPhone disponible depuis le projet sourceForge
Il existe même un exemple d'application qui montre comment envoyer un message d'erreur au terminal Xcode.
Tout ce que vous devez faire est d'entourer votre code JavaScript, y compris les définitions de fonction, etc. avec try catch. Ça devrait ressembler à ça.
try{
//put your code here
}
catch(err){
logError(err);
}
Cela ne fonctionne pas très bien avec les erreurs de compilation mais fonctionne avec tous les autres. Même des fonctions anonymes.
Le développement le blog est ici est ici et inclut des liens vers le wiki, sourceForge, le groupe google et Twitter. Peut-être que cela vous aiderait.
Première configuration WebViewJavascriptBridge , puis remplacez la fonction console.error.
En javascript
window.originConsoleError = console.error;
console.error = (msg) => {
window.originConsoleError(msg);
bridge.callHandler("sendConsoleLogToNative", {
action:action,
message:message
}, null)
};
Dans Objective-C
[self.bridge registerHandler:@"sendConsoleLogToNative" handler:^(id data, WVJBResponseCallback responseCallback) {
NSString *action = data[@"action"];
NSString *msg = data[@"message"];
if (isStringValid(action)){
if ([@"console.error" isEqualToString:action]){
NSLog(@"JS error :%@",msg);
}
}
}];
Je l'ai fait dans le firmware 1.x mais pas 2.x. Voici le code que j'ai utilisé dans 1.x, il devrait au moins vous aider sur votre chemin.
// Dismiss Javascript alerts and telephone confirms
/*- (void)alertSheet:(UIAlertSheet*)sheet buttonClicked:(int)button
{
if (button == 1)
{
[sheet setContext: nil];
}
[sheet dismiss];
}*/
// Javascript errors and logs
- (void) webView: (WebView*)webView addMessageToConsole: (NSDictionary*)dictionary
{
NSLog(@"Javascript log: %@", dictionary);
}
// Javascript alerts
- (void) webView: (WebView*)webView runJavaScriptAlertPanelWithMessage: (NSString*) message initiatedByFrame: (WebFrame*) frame
{
NSLog(@"Javascript Alert: %@", message);
UIAlertSheet *alertSheet = [[UIAlertSheet alloc] init];
[alertSheet setTitle: @"Javascript Alert"];
[alertSheet addButtonWithTitle: @"OK"];
[alertSheet setBodyText:message];
[alertSheet setDelegate: self];
[alertSheet setContext: self];
[alertSheet popupAlertAnimated:YES];
}
Voir la gestion des exceptions dans iOS7: http://www.bignerdranch.com/blog/javascriptcore-example/
[context setExceptionHandler:^(JSContext *context, JSValue *value) {
NSLog(@"%@", value);
}];