Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/44.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我的iPhone Objective-C代码如何在UIWebView中获得Javascript错误通知?_Iphone_Objective C_Webkit - Fatal编程技术网

我的iPhone Objective-C代码如何在UIWebView中获得Javascript错误通知?

我的iPhone Objective-C代码如何在UIWebView中获得Javascript错误通知?,iphone,objective-c,webkit,Iphone,Objective C,Webkit,我需要让我的iPhone Objective-C代码在UIWebView中捕获Javascript错误。这包括未捕获的异常、加载文件时的语法错误、未定义的变量引用等 这是一个开发环境,所以它不需要符合SDK标准。事实上,它只需要在模拟器上工作 我已经发现使用了一些隐藏的WebKit技巧,例如向JS公开Obj-C对象和截获警报弹出窗口,但我仍然无法找到这个 [注意:发布此消息后,我确实找到了一种使用调试委托的方法。是否有一种使用错误控制台/web inspector降低开销的方法?]我在固件1.x

我需要让我的iPhone Objective-C代码在UIWebView中捕获Javascript错误。这包括未捕获的异常、加载文件时的语法错误、未定义的变量引用等

这是一个开发环境,所以它不需要符合SDK标准。事实上,它只需要在模拟器上工作

我已经发现使用了一些隐藏的WebKit技巧,例如向JS公开Obj-C对象和截获警报弹出窗口,但我仍然无法找到这个


[注意:发布此消息后,我确实找到了一种使用调试委托的方法。是否有一种使用错误控制台/web inspector降低开销的方法?]

我在固件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];
}

现在我找到了一种在WebView中使用脚本调试器挂钩的方法(注意,不是UIWebView)。我首先必须将UIWebView子类化,并添加如下方法:

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

    if (scriptDebuggingEnabled) {
        [webView setScriptDebugDelegate:[[YourScriptDebugDelegate alloc] init]];
    }
}
#ifdef DEBUG
        myWebview = [[DebugWebView alloc] initWithFrame:frame];
#else
        myWebview = [[UIWebView alloc] initWithFrame:frame];
#endif
接下来,您应该创建一个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++定义,请参见

其他方法包括:

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

请注意,这些都隐藏在一个私有框架中,因此不要试图将其放入提交给应用商店的代码中,并为黑客攻击做好准备。我创建了一个SDK kosher error reporter,其中包括:

  • 错误消息
  • 发生错误的文件的名称
  • 发生错误的行号
  • 包含传递参数的JavaScript调用堆栈
  • 它是QuickConnectionPhone框架的一部分,可从

    甚至还有一个示例应用程序演示了如何向Xcode终端发送错误消息

    您所需要做的就是用try-catch来包围JavaScript代码,包括函数定义等。应该是这样的

    try{
    //put your code here
    }
    catch(err){
        logError(err);
    }
    
    它不能很好地处理编译错误,但可以处理所有其他错误。甚至匿名函数

    发展
    位于此处,包括指向wiki、sourceForge、google group和twitter的链接。也许这会对您有所帮助。

    我使用了Robert Sanders提出的伟大解决方案:

    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可能没有响应-WindowsScriptObject”,因为类接口是隐藏的。我忽略它们,效果很好。

    直截了当的方法:将此代码放在使用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
    
    然后像这样实例化它:

    - (void)webView:(id)webView windowScriptObjectAvailable:(id)newWindowScriptObject {
        // save these goodies
        windowScriptObject = newWindowScriptObject;
        privateWebView = webView;
    
        if (scriptDebuggingEnabled) {
            [webView setScriptDebugDelegate:[[YourScriptDebugDelegate alloc] init]];
        }
    }
    
    #ifdef DEBUG
            myWebview = [[DebugWebView alloc] initWithFrame:frame];
    #else
            myWebview = [[UIWebView alloc] initWithFrame:frame];
    #endif
    
    使用#ifdef DEBUG可以确保它不会出现在发布版本中,但我还建议您在不使用它时对其进行注释,因为它会影响性能。罗伯特·桑德斯和普塞拉获得了原始代码


    此外,如果使用ARC,您可能需要添加“-fno objc ARC”以防止某些生成错误。

    我创建了一个不错的小目录,您可以将其添加到项目中。。。 它基于Robert Sanders解决方案。荣誉

    您可以在此处加载它:


    这将使调试UIWebView变得更容易:)

    对于某些情况,一个更简单的解决方案可能是只添加到网页。

    如果您有Safari v 6+(我不确定您需要什么iOS版本),在开发过程中工作的一种方法是使用Safari开发工具并通过它连接到UIWebView

  • 在Safari中:启用开发菜单(首选项>高级>在菜单栏中显示开发菜单)
  • 通过电缆将手机插入电脑
  • 列表项
  • 加载应用程序(通过xcode或直接启动),然后转到要调试的屏幕
  • 回到Safari,打开“开发”菜单,在该菜单中查找您的设备名称(我的名为iPhone 5),该菜单应位于用户代理的正下方
  • 选择它,您将看到应用程序中当前可见的web视图的下拉列表
  • 如果屏幕上有多个webview,您可以尝试通过在“开发”菜单中滚动应用程序的名称来区分它们。相应的UIWebView将变为蓝色
  • 选择应用程序的名称,开发窗口打开,您可以检查控制台。您甚至可以通过它发出JS命令
    请参阅iOS7中的异常处理:

    第一次安装, 然后重写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);
            }
        }
    }];
    

    我在某个地方找到了它,但在2.1中它似乎对我不起作用。假设这些是添加到UIWebView子类中的方法。我尝试将UIWebView子类化并添加webView:WindowsScriptObjectAvailable方法,如您所述,但从未调用它。这是iphone 3.0 SDK的一部分。这是否不再有效,或者我做错了什么?我在iphone上试用过,效果很好。但是,似乎只提出了已处理的异常。如果未处理的异常消失,则可能没有帮助。im using Exception was在委托中引发,并在帧调用方上迭代。但是它们都有functionName返回null。你知道吗?你也可以用webView:didClearWindowObject:forFrame:方法为UIWebView创建一个类别,而不必实例化不同的类类型。我得到了一个关于接收方类型WebScriptCallFrame的错误,因为实例消息是一个前向声明。在…上