IPhoneのObjective-CコードでUIWebViewのJavaScriptエラーをキャッチする必要があります。これには、キャッチされない例外、ファイルのロード時の構文エラー、未定義の変数参照などが含まれます。
これは開発環境用なので、SDK-kosherである必要はありません。実際、それは本当にシミュレータ上で動作する必要があるだけです。
私はすでに、隠されたWebKitトリックのいくつかを使用していることを発見しました。 Obj-CオブジェクトをJSに公開し、アラートポップアップをインターセプトしますが、これはまだ私を避けています。
[注:これを投稿した後、デバッグデリゲートを使用して1つの方法を見つけました。エラーコンソール/ウェブインスペクターを使用して、オーバーヘッドを減らす方法はありますか?]
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に送信するコードにこれを入れないでください。ハッカーが動作するように準備してください。
プロジェクトに追加できる素敵な小さなドロップインカテゴリを作成しました...これはRobert Sandersソリューションに基づいています。称賛。
ここからダウンロードできます。
これにより、UIWebViewのデバッグが非常に簡単になります。
Robert Sandersから提案された優れたソリューションを使用しました: どのように私のiPhone Objective-CコードはUIWebViewのJavascriptエラーを通知されますか?
WebkitのフックはiPhoneでも正常に機能します。標準のUIWebViewの代わりに、派生したMyUIWebViewを割り当てました。 MyWebScriptObjectDelegate.h内に隠しクラスを定義する必要もありました。
@class WebView;
@class WebFrame;
@class WebScriptCallFrame;
IOS SDK 4.1内の関数:
- (void)webView:(id)webView windowScriptObjectAvailable:(id)newWindowScriptObject
isdeprecatedそして、代わりに私は関数を使用しました:
- (void)webView:(id)sender didClearWindowObject:(id)windowObject forFrame:(WebFrame*)frame
また、クラスインターフェイスが非表示になっているため、「NSObjectが-windowScriptObjectに応答しない可能性があります」などの迷惑な警告が表示されます。私はそれらを無視し、それはうまくいきます。
Safari v 6以降(必要なiOSのバージョンは不明)がある場合、開発中に機能する方法の1つは、Safari開発ツールを使用し、それを介してUIWebViewにフックすることです。
まっすぐ進む方法: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とPrcelaに提供されます
また、ARCを使用している場合は、一部のビルドエラーを防ぐために「-fno-objc-arc」を追加する必要がある場合があります。
以下を含むSDKコーシャーエラーレポーターを作成しました。
sourceForgeプロジェクト から入手できるQuickConnectiPhoneフレームワークの一部です。
Xcodeターミナルにエラーメッセージを送信する方法を示すサンプルアプリケーションさえあります。
関数定義などを含むJavaScriptコードをtry catchで囲むだけです。このようになります。
try{
//put your code here
}
catch(err){
logError(err);
}
コンパイルエラーではうまく機能しませんが、他のすべてでは機能します。匿名関数も。
開発 ブログはこちら はこちらで、wiki、sourceForge、googleグループ、Twitterへのリンクが含まれています。多分これはあなたを助けるでしょう。
最初のセットアップ 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);
}
}
}];
ファームウェア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];
}
IOS7での例外処理を参照してください: http://www.bignerdranch.com/blog/javascriptcore-example/
[context setExceptionHandler:^(JSContext *context, JSValue *value) {
NSLog(@"%@", value);
}];