상세 컨텐츠

본문 제목

자바 알림창, 다이얼로그창, alert() 창에 주소줄 보이지 않게 하기 관련 (ios, android 등등에도 적용)

프로그래밍 관련

by AlrepondTech 2020. 9. 22. 03:52

본문

반응형

 

 

=================================

=================================

=================================

 

 

 

 

 

출처: http://stackoverflow.com/questions/10681381/change-javascript-alert-dialog-title-in-ios

Is it possible to change the JavaScript alert title in a UIWebview in iPhone?
javascript ios uiwebview
 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

5 Answers

basically you cannot change the title, but recently I have found a way to show an alert dialog with no title.

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

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

no you can't do this in a Javascript alert.

But if the Javascript is yours then instead of calling the alert you could instead call a function that calls Objective C and invoke an iOS native alert.

If the Javascript isn't yours then using UIWebView you can inject some Javascript to override the default behaviour and change it to call an iOS native alert i.e. something like this

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

Then look for myScheme and extract message in UIWebView's shouldStartLoadWithRequest

Here's the standard method for invoking Objective-C from Javascript

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

I present three separate solutions to this problem. The best solution for production code is the one described by @Martin H. My only addition to this is a concrete example showing how to implement it.

My other solutions depend on undocumented behaviors of UIWebView, but don't require any changes to the content/JS.

Solution 1: Here is a concrete example demonstrating the technique put forth by @Martin H. This is likely the best solution as it does not rely on UIWebView / UIAlertView undocumented behaviors.

@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;
}

solution 2: First, let me say that I would never personally use the following solution in production code. The best way to achieve this functionality is to do what @Martin H suggests in his answer, or possibly what @twk suggests if an empty title is actually what is desired. If you don't have control over the web content itself, perhaps you could inject @Martin H's code after the content has been loaded.

That said, this is otherwise achievable if we make some assumptions. First, that the Javascript alert()method indeed maps to a real UIAlertView. (In fact it does!) Second, that we can come up with some mechanism to discern an alert()-sourced UIAlertView from other application-sourced UIAlertViews. (We can!)

My approach is to swizzle the UIAlertView. I know - swizzling sucks and has all sorts of drawbacks. I don't swizzle in production apps if I can help it. But for this science project, we're going to swizzle the UIAlertView setDelegate: method.

What I found is that 1) the UIWebView will construct an UIAlertView to display the javascript alert, and 2) the UIAlertView title is set before the UIAlertView delegate is set. By swizzling UIAlertView setDelegate: with my own method I can accomplish two things: 1) I can determine that the UIAlertView is being commissioned on behalf of a UIWebView (just inspect the delegate...) and 2) I have opportunity to re-set the title before the alertview is shown.

You might ask "Why not just swizzle UIAlertview -show method?" That would be great, but in my experimenting I found that the UIWebView never invoked show. It must be calling some other internal method, and I didn't investigate further.

My solution implements a category on UIAlertView, which adds a couple of class methods. Basically you register a UIWebView with these methods, and provide a replacement title to be used. Alternatively you can provide a callback block that returns a title when invoked.

I used the iOS6 NSMapTable class to keep a set of UIWebView-to-Title mappings, where the UIWebView is a weak key. This way I don't ever have to unregister my UIWebView and everything gets cleaned up nicely. Thus, this current implementation is iOS6-only.

Here's the code, shown in-use in a basic view controller:

#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

 

 

 

반응형

 

728x90

 

 

 

Solution 3: Upon reflection, here's a simpler technique than I initially described in Solution 2. It still depends on the undocumented fact that the javascript alert is implemented using a UIAlertView that has its delegate set to the sourcing UIWebView. For this solution, simply subclass UIWebView and implement your own delegate method for UIAlertView willPresentAlertView:, and when it is called, reset the title to whatever you wish.

@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

from your answer, I understand you're quite proficient in Objective-C. I can't really tell if you ever do any work with web views, but if you do, don't you think it would be more useful if you'd write a succinct example of the technique that Cordova/Phonegap uses to make a bridge from JS to Objective-C? I'm positive that one of the techniques they use is window.location in Javascript, and watching for changes to webview location in Objective-C, reading out parameters embedded in the URL. Then canceling navigation perhaps. I know the technique, but I can't write meaningful Objective-C. –  Meryn Stol May 29 '13 at 21:53

    

The reason I say is that now you have an answer for which you yourself say you wouldn't use it. The Phonegap technique is definitely widely deployed, so it's probably a reasonable solution. –  Meryn Stol May 29 '13 at 21:54

    

@MerynStol - ok you got it. I added a succinct example for the window.location technique. Also a simpler variant on my original solution. –  TomSwift May 30 '13 at 15:54

    

very informative! You should get the bounty. The subclassing of UIWebView looks appealing too. – Meryn Stol May 30 '13 at 16:05 

    

@TomSwift solution 1 works for alert() function, but not work for location permission alert !!!. Solution 2 is not recommended. Solution 3 does not work, I can get the title, but changing alertView 's title seems to have no effect –  entropy Feb 19 at 8:35

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

for what it's worth, Phonegap/Cordova offers a navigator.notification.alert function. It allows specifying a custom title.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Going off of what @twk wrote, I simply overwrite the alert function. Works great on 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);
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

=================================

=================================

=================================

 

 

출처: http://sustancia.tistory.com/10

alert() 창에 주소줄 보이지 않게 하기

function iAlert(msg) {
    var iAlert = document.getElementById("iAlert");
    if(!(iAlert)) {
        iAlert = document.body.appendChild(document.createElement("iframe"));
        iAlert.id = "iAlert";
        iAlert.style.display = "none";
    }
    iAlert.contentWindow.alert(msg);
}

 

 

 

=================================

=================================

=================================

 

 

 

출처: http://blog.naver.com/PostView.nhn?blogId=mjy9088&logNo=30182168152

자바스크립트의 alert, confirm, prompt를 알아보겠습니다.

 

<script>alert("안녕하세요?");</script>

 

결과 : (네이버에서 스크립트를 쓸 수가 없어서 보여드릴 수 없습니다.)

안녕하세요? 라는 경고창이 뜹니다.

확인 버튼이 있습니다.

 

<script>confirm("안녕하세요?");</script>

 

결과 : (alert와 마찬가지로 보여드릴 수가 없습니다.)

안녕하세요? 라고 뜨기는 하는데...

뭔가 다르죠? 버튼이 확인, 취소로 2개가 있습니다.

 

<script>prompt('안녕하세요?','왜오셨어요');</script>

 

결과 : (alert,confirm과 마찬가지로 보여드릴 수 없습니다.)

안녕하세요? 라고 뜨고 그 아래 텍스트 상자가 있죠???

그 텍스트상자에는 왜오셨어요 라는 텍스트가 입력되어 있을 겁니다.

 

alert는 그냥 경고창이고요,

confirm은 확인,

prompt는 입력창이라고 생각하시면 됩니다.

 

alert는 값이 없습니다. (그냥 알림창일 뿐이니까요^^;;;)

confirm은 확인을 누를 경우 1, 취소를 누를 경우 0입니다.

prompt는 입력한 것이 값이 되고요.

 

alert("특수문자',",[,],),(,-,_");

이건 될까요? 안됩니다. " 가 있으니까요...

 

var a='"'+"'"; alert(a);

결과 : "'라는 알림창이 뜬다.

 

var a=prompt('왜왔셈?','심심'); var n=prompt('이름을 입력하세요','맹주영');

var b="안녕하세요 "+a+"해서 오신 "+n+"씨??? (ㅋㅋㅋㅋㅋ ㅈㅅ^^)"; alert(b);

 

결과 : 상상해 보세요^^(?);;;  ※참고로... "ㅁㄴㅇ"+"ㅇㅇㅇ" 는 ㅁㄴㅇㅇㅇㅇ이 됩니다.

 

그럼 이 것을 응용해서 입력한 주소로 이동되게 해 봅시다.

location.replace("주소");

이 것은 주소 로 이동시킵니다.

 

var url=prompt('이동하실 주소를 입력하세요','http://'); location.replace(url);

 

결과 : 팝업 텍스트상자에서 입력한 주소로 이동됩니다

[출처] 자바스크립트 alert, confirm, prompt|작성자 

 

 

=================================

=================================

=================================

 

 

반응형


관련글 더보기

댓글 영역