2008-10-10 32 views
45

我需要我的iPhone Objective-C代碼在UIWebView中捕獲Javascript錯誤。這包括未捕獲的異常,加載文件時的語法錯誤,未定義的變量引用等。我的iPhone Objective-C代碼如何在UIWebView中獲得Javascript錯誤的通知?

這是針對開發環境的,因此它不需要是SDK-Kosher。事實上,它只需要在模擬器上工作。

我已經找到了一些隱藏的WebKit技巧用於例如將Obj-C對象暴露給JS並攔截警報彈出窗口,但是這個仍然在逃避我。

[注意:發佈後,我確實找到了一種使用調試代理的方式。有沒有更低的開銷,使用錯誤控制檯/網絡檢查器?]

回答

0

我已經在固件1.x,但不是2.x做到這一點。 這裏是我在1.x中使用的代碼,它至少應該幫助你。

// 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]; 
} 
+0

我已經發現的地方,但它不會出現在我的2.1工作。假設這些是添加到UIWebView的子類的方法。 – 2008-10-10 22:51:18

28

我現在已經找到了使用腳本調試器掛鉤在WebView中(注意,不是一個UIWebView)的一種方式。我首先要繼承一個UIWebView並添加這樣的方法:

- (void)webView:(id)webView windowScriptObjectAvailable:(id)newWindowScriptObject { 
    // save these goodies 
    windowScriptObject = newWindowScriptObject; 
    privateWebView = webView; 

    if (scriptDebuggingEnabled) { 
     [webView setScriptDebugDelegate:[[YourScriptDebugDelegate alloc] init]]; 
    } 
} 

接下來,你應該創建一個包含這樣的方法YourScriptDebugDelegate類:

// 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]); 
} 

有可能是這個大的運行時間的影響,因爲調試代理還可以提供進入和退出堆棧幀的方法,以及執行每行代碼。對於WebScriptDebugDelegate的Objective-C++定義,請參閱http://www.koders.com/noncode/fid7DE7ECEB052C3531743728D41A233A951C79E0AE.aspx

那些其他方法:

// 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; 

注意,這是所有藏在一個私人的框架,所以不要試圖把這個代碼提交到App Store,而對於一些兩輪牛車準備讓它起作用。

+1

我試圖繼承UIWebView並添加webView:windowScriptObjectAvailable方法,正如你所描述的,但它永遠不會被調用。這是與iPhone 3.0 SDK。這是不是工作了,或者我做錯了什麼? – pjb3 2009-06-29 16:39:11

+0

我在iphone上試了這個,效果很好。但是,似乎只有處理異常被提出。如果未處理的異常消失,這可能沒有幫助。 – Prcela 2010-11-22 09:31:57

+0

即時通訊在代理中使用exceptionWasRaised並遍歷幀調用方。但它們都具有functionName返回null。任何想法? – at0mzk 2011-02-23 09:25:03

4

我已經創建了一個SDK的猶太錯誤記者,其中包括:

  1. 的錯誤消息
  2. 發生錯誤的行號發生錯誤的文件的名稱包含傳遞的參數的JavaScript callstack

它是QuickConnectPhone框架的一部分,可從the sourceForge project

甚至還有一個示例應用程序,顯示如何將錯誤消息發送到Xcode終端。

您需要做的就是圍繞您的JavaScript代碼,包括函數定義等。它應該看起來像這樣。

try{ 
//put your code here 
} 
catch(err){ 
    logError(err); 
} 

它不能很好地適用於編譯錯誤,但適用於所有其他人。即使是匿名功能。

開發blog is here 是在這裏,包括wiki,sourceForge,谷歌組和twitter的鏈接。也許這會幫助你。

11

我使用了羅伯特·桑德斯提出了很好的解決方案:How can my iPhone Objective-C code get notified of Javascript errors in a UIWebView?

那鉤WebKit的作品也罰款iPhone。我分配了派生的MyUIWebView,而不是標準的UIWebView。我還需要定義隱藏類中MyWebScriptObjectDelegate.h:

@class WebView;
@class WebFrame;
@class WebScriptCallFrame;

的IOS SDK內4.1功能:

- (void)webView:(id)webView windowScriptObjectAvailable:(id)newWindowScriptObject 

棄用,而是它我使用的功能:

- (void)webView:(id)sender didClearWindowObject:(id)windowObject forFrame:(WebFrame*)frame 

此外,我得到一些惱人的警告,如「NSObject可能不會響應-windowScriptObject」,因爲類接口是隱藏的。我忽略它們,它很好。

8

直接的方法:把你的控制器/視圖的頂部這段代碼中使用的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 

然後實例是這樣的:

#ifdef DEBUG 
     myWebview = [[DebugWebView alloc] initWithFrame:frame]; 
#else 
     myWebview = [[UIWebView alloc] initWithFrame:frame]; 
#endif 

使用的#ifdef DEBUG保證它不會在發佈版本中發佈,但是我還建議您在不使用時註釋它,因爲它會對性能產生影響。信貸轉到羅伯特桑德斯和Prcela的原始代碼

此外,如果使用ARC,您可能需要添加「-fno-objc-arc」以防止一些構建錯誤。

+2

您也可以使用webView:didClearWindowObject:forFrame:方法爲UIWebView創建一個類別,而不必實例化不同的類類型。 – 2012-05-26 17:11:01

13

我創建了一個漂亮的小插件類別,您可以添加到您的項目... 它基於羅伯特桑德斯解決方案。榮譽。

你可以在這裏下載中心它:

UIWebView+Debug

這應該使人們更方便調試你的UIWebView :)

-3

對於某些情況下,簡單的解決方案可能是隻加Firebug Lite到網頁。

7

如果你有Safari v 6+(我不確定你需要什麼樣的iOS版本),開發過程中的一種方法是使用Safari開發工具並通過它掛接到UIWebView。

  1. 在Safari中:啓用開發菜單(首選項>高級>顯示開發菜單欄菜單)
  2. 將您的手機變成電腦通過電纜。
  3. 列表項
  4. 加載應用程序(通過xcode或只是啓動它)並轉到您要調試的屏幕。
  5. 回到Safari,打開Develop菜單,在該菜單中查找設備名稱(我的名字叫iPhone 5),應該在User Agent下。
  6. 選擇它,你應該看到在你的應用程序中當前可見的web瀏覽器的下拉菜單。
  7. 如果您在屏幕上有多個webview,您可以嘗試通過在開發菜單中滾動應用程序的名稱來區分它們。相應的UIWebView將變成藍色。
  8. 選擇應用程序的名稱,開發窗口打開,您可以檢查控制檯。你甚至可以通過它發出JS命令。在iOS7
0

首次設置WebViewJavascriptBridge, 然後覆蓋console.error功能。

在javascript中

window.originConsoleError = console.error; 
    console.error = (msg) => { 
     window.originConsoleError(msg); 
     bridge.callHandler("sendConsoleLogToNative", { 
      action:action, 
      message:message 
     }, null) 
    }; 

在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); 
     } 
    } 
}]; 
相關問題