35

UIWebviewiPhoneでJavaScriptアラートのタイトルを変更することはできますか?

4

7 に答える 7

57

基本的にタイトルを変更することはできませんが、最近、タイトルのないアラートダイアログを表示する方法を見つけました。

var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", 'data:text/plain,');
document.documentElement.appendChild(iframe);
window.frames[0].window.alert('hello');
iframe.parentNode.removeChild(iframe);
于 2013-01-28T15:13:46.070 に答える
15

この問題に対する3つの別々の解決策を提示します。実動コードの最良の解決策は、@ Martin Hによって記述されたものです。これに対する私の唯一の追加は、それを実装する方法を示す具体的な例です。

私の他のソリューションは、UIWebViewの文書化されていない動作に依存していますが、content/JSに変更を加える必要はありません。

解決策1:@Martin Hによって提示された手法を示す具体的な例を次に示します。これは、文書化されていない動作に依存しないため、おそらく最良の解決策UIWebViewですUIAlertView

@interface TSViewController () <UIWebViewDelegate>
@end

@implementation TSViewController

- (UIWebView*) webView
{
    return (UIWebView*) self.view;
}

- (void) loadView
{
    UIWebView* wv = [[UIWebView alloc] initWithFrame: CGRectMake(0, 0, 320, 480)];
    wv.delegate = self;
    wv.scalesPageToFit = YES;

    self.view = wv;
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    [self.webView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString: @"http://www.craigslist.org"]]];
}

- (void) webViewDidFinishLoad: (UIWebView *) webView
{
    // inject some js to re-map window.alert()
    // ideally just do this in the html/js itself if you have control of that.
    NSString* js = @"window.alert = function(message) { window.location = \"http://action/alert?message=\" + message; }";
    [webView stringByEvaluatingJavaScriptFromString: js];

    // trigger an alert.  for demonstration only:
    [webView stringByEvaluatingJavaScriptFromString: @"alert('hello, world');" ];
}


- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSURL* url = request.URL;

    // look for our custom action to come through:
    if ( [url.host isEqualToString: @"action"] && [url.path isEqualToString: @"/alert"] )
    {
        // parse out the message
        NSString* message = [[[[url query] componentsSeparatedByString: @"="] lastObject] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

        // show our alert
        UIAlertView* av = [[UIAlertView alloc] initWithTitle: @"My Custom Title"
                                                     message: message
                                                    delegate: nil
                                           cancelButtonTitle: @"OK"
                                           otherButtonTitles: nil];

        [av show];

        return NO;
    }
    return YES;
}

解決策2:まず、本番コードで次の解決策を個人的に使用することは決してないだろうと言わせてください。 この機能を実現するための最良の方法は、@ Martin Hが彼の回答で提案していること、または空のタイトルが実際に望ましいものである場合は@twkが提案していることを実行することです。Webコンテンツ自体を制御できない場合は、コンテンツがロードされた後に@MartinHのコードを挿入できます。

とは言うものの、いくつかの仮定を立てれば、これは他の方法で達成可能です。まず、Javascriptalert()メソッドが実際に実際にマップされることUIAlertView。(実際にはそうです!)次に、他のアプリケーションソースからソースを識別するためのメカニズムをalert()考え出すことができます。(私たちはできる!)UIAlertViewUIAlertViews

私のアプローチは、をスウィズルすることUIAlertViewです。私は知っています-スウィズリングは吸うし、あらゆる種類の欠点があります。私はそれを助けることができれば、本番アプリでスウィズルすることはありません。しかし、この科学プロジェクトでは、メソッドをスウィズルしますUIAlertView setDelegate:

私が見つけたのは、1)javascriptアラートを表示するためのUIWebViewを構築し、2) UIAlertViewが設定される前にタイトルが設定されることです。独自の方法でスウィズリングすることで、2つのことを達成できます。1)が(代理人を検査するだけで...)に代わって委託されていることを確認できます。2)アラートビューの前にタイトルを再設定する機会があります。示されています。UIAlertViewUIAlertViewdelegateUIAlertView setDelegate:UIAlertViewUIWebView

「スウィズルUIAlertview -show法だけじゃないの?」と聞くかもしれません。 それは素晴らしいことですが、私の実験では、UIWebViewが呼び出されなかったことがわかりましたshow。それは他の内部メソッドを呼び出しているに違いありません、そして私はそれ以上調査しませんでした。

私のソリューションは、UIAlertViewにカテゴリを実装し、いくつかのクラスメソッドを追加します。基本的に、UIWebViewをこれらのメソッドに登録し、使用する置換タイトルを提供します。または、呼び出されたときにタイトルを返すコールバックブロックを提供することもできます。

iOS6クラスを使用してNSMapTable、UIWebViewからタイトルへのマッピングのセットを保持しました。UIWebViewは弱鍵です。このようにして、登録を解除する必要がなくなり、UIWebViewすべてが正常にクリーンアップされます。 したがって、この現在の実装はiOS6のみです。

基本的なViewControllerで使用中のコードは次のとおりです。

#import <objc/runtime.h>

typedef NSString*(^TSAlertTitleBlock)(UIWebView* webView, NSString* defaultTitle );

@interface UIAlertView (TS)
@end

@implementation UIAlertView (TS)

NSMapTable* g_webViewMapTable;

+ (void) registerWebView: (UIWebView*) webView alertTitleStringOrBlock: (id) stringOrBlock
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        g_webViewMapTable = [NSMapTable weakToStrongObjectsMapTable];

        // $wizzle
        Method originalMethod = class_getInstanceMethod(self, @selector(setDelegate:));
        Method overrideMethod = class_getInstanceMethod(self, @selector(setDelegate_ts:));
        method_exchangeImplementations(originalMethod, overrideMethod);
    });

    [g_webViewMapTable setObject: [stringOrBlock copy] forKey: webView];
}

+ (void) registerWebView: (UIWebView*) webView alertTitle: (NSString*) title
{
    [self registerWebView: webView alertTitleStringOrBlock: title];
}

+ (void) registerWebView: (UIWebView*) webView alertTitleBlock: (TSAlertTitleBlock) alertTitleBlock
{
    [self registerWebView: webView alertTitleStringOrBlock: alertTitleBlock];
}

- (void) setDelegate_ts: (id) delegate
{
    // call the original implementation
    [self setDelegate_ts: delegate];

    // oooh - is a UIWebView asking for this UIAlertView????
    if ( [delegate isKindOfClass: [UIWebView class]] )
    {
        // see if we've registered a title/title-block
        for ( UIWebView* wv in g_webViewMapTable.keyEnumerator )
        {
            if ( wv != delegate)
                continue;

            id stringOrBlock = [g_webViewMapTable objectForKey: wv];

            if ( [stringOrBlock isKindOfClass: NSClassFromString( @"NSBlock" )] )
            {
                stringOrBlock = ((TSAlertTitleBlock)stringOrBlock)( wv, self.title );
            }

            NSParameterAssert( [stringOrBlock isKindOfClass: [NSString class]] );

            [self setTitle: stringOrBlock];
            break;
        }
    }
}

@end

@interface TSViewController () <UIWebViewDelegate>
@end

@implementation TSViewController

- (UIWebView*) webView
{
    return (UIWebView*) self.view;
}

- (void) loadView
{
    UIWebView* wv = [[UIWebView alloc] initWithFrame: CGRectMake(0, 0, 320, 480)];
    wv.delegate = self;
    wv.scalesPageToFit = YES;

    self.view = wv;
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    // method 1: bind a title to a webview:
    [UIAlertView registerWebView: self.webView alertTitle: nil];

    /*
    // method 2: return a title each time it's needed:
    [UIAlertView registerWebView: self.webView
                 alertTitleBlock: ^NSString *(UIWebView *webView, NSString* defaultTitle) {

                     return @"Custom Title";
    }];
     */

    [self.webView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString: @"http://www.craigslist.org"]]];
}

- (void) webViewDidFinishLoad: (UIWebView *) webView
{
    // trigger an alert
    [webView stringByEvaluatingJavaScriptFromString: @"alert('hello, world');" ];
}

@end

解決策3:振り返ってみると、これは解決策2で最初に説明したよりも簡単な手法です。それでも、JavaScriptアラートがソーシングUIWebViewにデリゲートが設定されているUIAlertViewを使用して実装されているという文書化されていない事実に依存します。このソリューションでは、UIWebViewをサブクラス化し、UIAlertView willPresentAlertView:の独自のデリゲートメソッドを実装し、呼び出されたら、タイトルを任意の値にリセットします。

@interface TSWebView : UIWebView
@end

@implementation TSWebView

- (void) willPresentAlertView:(UIAlertView *)alertView
{
    if ( [self.superclass instancesRespondToSelector: @selector( willPresentAlertView:) ])
    {
        [super performSelector: @selector( willPresentAlertView:) withObject: alertView];
    }

    alertView.title = @"My Custom Title";
}

@end

@interface TSViewController () <UIWebViewDelegate>
@end

@implementation TSViewController

- (UIWebView*) webView
{
    return (UIWebView*) self.view;
}

- (void) loadView
{
    UIWebView* wv = [[TSWebView alloc] initWithFrame: CGRectMake(0, 0, 320, 480)];
    wv.delegate = self;
    wv.scalesPageToFit = YES;

    self.view = wv;
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    [self.webView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString: @"http://www.craigslist.org"]]];
}

- (void) webViewDidFinishLoad: (UIWebView *) webView
{
    // trigger an alert
    [webView stringByEvaluatingJavaScriptFromString: @"alert('hello, world');" ];
}

@end
于 2013-05-29T01:16:33.030 に答える
10

いいえ、Javascriptアラートでこれを行うことはできません。

ただし、Javascriptが自分のものである場合は、アラートを呼び出す代わりに、ObjectiveCを呼び出す関数を呼び出してiOSネイティブアラートを呼び出すことができます。

Javascriptが自分のものでない場合は、UIWebViewを使用して、Javascriptを挿入してデフォルトの動作をオーバーライドし、iOSネイティブアラートを呼び出すように変更できます。

window.alert = function(message) {
  window.location = "myScheme://" + message"
};

次に、mySchemeを探し、UIWebViewのshouldStartLoadWithRequestでメッセージを抽出します

JavascriptからObjective-Cを呼び出すための標準的な方法は次のとおりです

JavascriptからObjective-Cを呼び出す方法は?

于 2012-05-24T14:25:33.053 に答える
4

Phonegap / Cordovaは、その価値について、navigator.notification.alert関数を提供します。カスタムタイトルを指定できます。

于 2013-05-25T17:32:34.833 に答える
1

UIWebViewのクラスを作成し、その中でwillPresentAlertView(alertView:UIAlertView)関数を作成するだけです。その後、セットalertView.title = "your fav title"して完了です。

    import UIKit

class webviewClass: UIWebView {

func willPresentAlertView(alertView: UIAlertView) {


    alertView.title = "my custum title"
}

}

その後、アラートまたは確認して...が表示されると、カスタムタイトルが表示されます。

于 2016-03-01T19:43:09.787 に答える
0

@twkが書いたものから離れて、私は単にアラート機能を上書きします。ios7でうまく機能します。

function alert(words){
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", 'data:text/plain,');
document.documentElement.appendChild(iframe);
window.frames[0].window.alert(words);
iframe.parentNode.removeChild(iframe);
}
于 2014-02-25T06:05:05.317 に答える
0

cordova-plugin-dialogsを使用します。ネイティブダイアログを作成できます。

以下のコードはネイティブアラートを作成します:

navigator.notification.alert(message, alertCallback, [title], [buttonName])
于 2015-10-05T16:57:13.717 に答える