46

iPhone Objective-C コードで UIWebView の Javascript エラーをキャッチする必要があります。これには、キャッチされない例外、ファイル読み込み時の構文エラー、未定義の変数参照などが含まれます。

これは開発環境用であるため、SDK-kosher である必要はありません。実際、シミュレータ上で動作する必要があるだけです。

Obj-C オブジェクトを JS に公開したり、アラート ポップアップをインターセプトしたりするなど、WebKit の隠しトリックのいくつかを使用していることは既にわかっていますが、これはまだわかりません。

[注: これを投稿した後、デバッグ デリゲートを使用する 1 つの方法を見つけました。エラー コンソール/Web インスペクタを使用して、オーバーヘッドを削減する方法はありますか?]

4

10 に答える 10

28

WebView でスクリプト デバッガー フックを使用する 1 つの方法を見つけました (注意、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 に提出するコードにこれを入れようとしないでください。ハッカーが動作するように準備してください。

于 2008-10-10T22:57:58.653 に答える
13

プロジェクトに追加できる素敵な小さなドロップイン カテゴリを作成しました... これは、Robert Sanders のソリューションに基づいています。称賛。

ここからダウンロードできます:

UIWebView+デバッグ

これにより、UIWebViewのデバッグがはるかに簡単になります:)

于 2012-07-16T00:10:27.800 に答える
11

Robert Sanders から提案された優れたソリューションを使用しました: How can my iPhone Objective-C code get notifications of Javascript errors in a UIWebView?

Webkit のそのフックはiPhoneでも正常に動作します。標準の UIWebView の代わりに、派生 MyUIWebView を割り当てました。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」などの迷惑な警告が表示されます。私はそれらを無視し、それはうまくいきます。

于 2010-11-05T17:02:54.640 に答える
9

Safari v 6+ (必要な iOS バージョンが不明) を使用している場合に開発中に機能する 1 つの方法は、Safari 開発ツールを使用し、それを介して UIWebView にフックすることです。

  1. Safari の場合: [開発] メニューを有効にします ([設定] > [詳細設定] > [メニュー バーに [開発] メニューを表示])。
  2. ケーブルを介して携帯電話をコンピュータに接続します。
  3. リスト項目
  4. アプリをロードし (xcode を使用するか、起動するだけ)、デバッグする画面に移動します。
  5. Safari に戻り、[開発] メニューを開き、そのメニューでデバイスの名前を探します (私の場合は iPhone 5 と呼ばれます)。ユーザー エージェントのすぐ下にあるはずです。
  6. それを選択すると、アプリで現在表示されている Web ビューのドロップダウンが表示されます。
  7. 画面に複数の webview がある場合は、開発メニューでアプリの名前にカーソルを合わせると、それらを区別することができます。対応する UIWebView が青色に変わります。
  8. アプリの名前を選択すると、開発ウィンドウが開き、コンソールを調べることができます。それを介して JS コマンドを発行することもできます。
于 2013-03-18T18:53:41.977 に答える
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 を使用すると、リリース ビルドに含まれなくなりますが、パフォーマンスに影響するため、使用しない場合はコメント アウトすることもお勧めします。元のコードについては、Robert Sanders と Precela の功績によるものです。

また、ARC を使用している場合は、ビルド エラーを防ぐために「-fno-objc-arc」を追加する必要がある場合があります。

于 2011-10-08T01:35:43.297 に答える
4

以下を含むSDKコーシャエラーレポーターを作成しました。

  1. エラーメッセージ
  2. エラーが発生したファイルの名前
  3. エラーが発生した行番号
  4. 渡されたパラメータを含むJavaScriptコールスタック

これは、sourceForgeプロジェクトから入手できるQuickConnectiPhoneフレームワークの一部です。

Xcode端末にエラーメッセージを送信する方法を示すサンプルアプリケーションもあります。

関数定義などを含むJavaScriptコードをtrycatchで囲むだけです。このようになります。

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

コンパイルエラーではうまく機能しませんが、他のすべてのエラーでは機能します。匿名関数ですら。

開発ブログはここ にあり、wiki、sourceForge、googleグループ、およびtwitterへのリンクが含まれています。多分これはあなたを助けるでしょう。

于 2009-04-21T20:58:36.453 に答える
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];
}
于 2008-10-10T22:14:06.280 に答える
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);
        }
    }
}];
于 2017-04-13T03:37:45.413 に答える
0

iOS7 での例外処理を参照してください: http://www.bignerdranch.com/blog/javascriptcore-example/

[context setExceptionHandler:^(JSContext *context, JSValue *value) {
    NSLog(@"%@", value);
}];
于 2015-02-22T22:21:19.513 に答える
-3

場合によっては、 Firebug Liteを Web ページに追加するだけの簡単な解決策があります。

于 2012-11-16T09:34:53.593 に答える