Можно ли изменить заголовок JavaScript-оповещения в UIWebview
в iPhone?
В принципе, вы не можете изменить заголовок, но недавно я нашел способ показать диалог предупреждения без заголовка.
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);
Я представляю три отдельных решения этой проблемы. Лучшее решение для производства кода описанного @Х. Мартин-мой единственный дополнение к это конкретный пример, показывающий, как это реализовать.
Другие мои решения зависят от незарегистрированных поведения UIWebView, но Дон'т требует каких-либо изменений в содержание и JS.
Решения 1: Вот конкретный пример, демонстрирующий технику, выдвинутые @Мартин х. Это, вероятно, лучшее решение, а не полагаться на 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: Во-первых, позвольте мне сказать, что я никогда бы лично использовать следующее решение в производственном коде. Лучший способ для достижения этой функции является делать то, что @Мартин ч показывает в своем ответе, или, возможно, что @моя жена предполагает, если пустое название на самом деле что то нужное. Если вы Don'т контролировать себя веб-контента, возможно, вы могли бы впрыскивают @Мартин ч's код после того, как контент был загружен.
Что сказал, это иначе достижимо, если мы сделаем некоторые предположения. Во-первых, что предупреждение на JavaScript ()
метод действительно соотносится с реальным UIAlertView. (На самом деле это делает!) Во-вторых, что мы можем придумать какой-то механизм, чтобы заметить их предупреждения ()
источников UIAlertView из других приложений-источников
UIAlertViews`. (Мы можем!)
Мой подход заключается в мошенничество в UIAlertView
. Я знаю - группирующее хреново и еще много всяких недостатков. Я Дон'т мошенничество в производственные приложения, если я могу помочь ему. Но для этого научный проект, мы'ре собираюсь мошенничество в UIAlertView setDelegate:
метод.
Я обнаружил, что 1) UIWebView
создаст UIAlertView для отображения JavaScript оповещения, и 2)
UIAlertViewзаголовок находится перед делегировать UIAlertView набор. По группирующее
UIAlertView setDelegate:с мой собственный способ я могу сделать две вещи: 1) я могу определить, что UIAlertView будет сдан на имени
UIWebView` (просто проверить делегат...) и 2) у меня есть возможность поменять название перед alertview отображается.
Вы можете спросить "Почему не просто мошенничество UIAlertview -показать способ
?&и" Это было бы здорово, но в мои эксперименты, я обнаружил, что UIWebView не ссылаться на "шоу". Это надо называть каким-то иным внутренним методом, и я не'т дальнейшего расследования.
Мое решение реализует категорию на UIAlertView, который добавляет пару методов класса. В основном вы регистрируете UIWebView с помощью этих методов, и укажите название замены, которые будут использоваться. Кроме того, вы можете предоставить блок обратного вызова, которая возвращает заголовок при вызове.
Я использовал в iOS6 NSMapTable
класс, чтобы сохранить набор UIWebView до звания сопоставления, где UIWebView является слабым ключом. Таким образом, я не'Т когда-нибудь придется отменить мой UIWebView и все отмылась. Таким образом, текущая реализация в iOS6-только.
Здесь'ы код, показанный в основной контроллер представления:
#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 оповещения осуществляется с помощью UIAlertView, что был делегатом установить в поиске UIWebView. Для этого решения, просто подкласс 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
Нет, вы не можете сделать это в оповещении Javascript.
Но если Javascript ваш, то вместо вызова оповещения вы можете вызвать функцию, которая вызовет Objective C и вызовет родное оповещение iOS.
Если Javascript не ваш, то с помощью UIWebView вы можете внедрить некоторый Javascript, чтобы переопределить поведение по умолчанию и изменить его для вызова родного оповещения iOS, т.е. что-то вроде этого
window.alert = function(message) {
window.location = "myScheme://" + message"
};
Затем найдите myScheme и извлеките сообщение в UIWebView's shouldStartLoadWithRequest
Вот'стандартный метод вызова Objective-C из Javascript
https://stackoverflow.com/questions/1662473/how-to-call-objective-c-from-javascript
Если уж на то пошло, Phonegap/Cordova предлагает функцию navigator.notification.alert. Она позволяет указать пользовательский заголовок.
Просто сделать класс для UIWebView и сделать willPresentAlertView функции (alertView: UIAlertView) в нем. После этого сеть alertView.заголовок = "и ваше название на" ФАВ; и это делается.
import UIKit
class webviewClass: UIWebView {
func willPresentAlertView(alertView: UIAlertView) {
alertView.title = "my custum title"
}
}
После этого, когда когда-либо предупреждения или подтверждения и... показали, свое индивидуальное название будет показано.
Осознав @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);
}
Использовать Cordova-плагин-диалоги. Он позволяет создавать собственные диалоговые окна.
Ниже код будет создавать собственные оповещения:
navigator.notification.alert(message, alertCallback, [title], [buttonName])