Запрос на изменение веб-представления должен запускать StartLoadWithRequest:
В настоящее время я занимаюсь разработкой гибридного приложения, которое использует webView shouldStartLoadWithRequest: для предоставления токена для входа в систему. Моя функция работает нормально для каждого обычного запроса (например, клик)
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request
NSLog([NSString stringWithFormat:@"Loading View: %@",[[request URL] absoluteString]]);
if ([[[request URL] absoluteString] rangeOfString:BASE_URL].location != NSNotFound) {
NSString *token = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginToken];
NSString *hash = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginHash];
NSString *params = [NSString stringWithFormat:@"mobile=app&user_token=%@&user_hash=%@",token,hash];
if([[request URL] query] == nil) {
[self LoadUrl:[[request URL] absoluteString] withGetParams:params append:NO];
return NO;
}else{
if([[[request URL] absoluteString] rangeOfString:params].location == NSNotFound){
[self LoadUrl:[[request URL] absoluteString] withGetParams:params append:YES];
return NO;
}
}
}
-(void)LoadUrl:(NSString *)url withGetParams:(NSString *)params append:(BOOL)append{
NSString *PreUrl;
if(append == YES) PreUrl = [NSString stringWithFormat:@"%@&%@",url,params];
else PreUrl = [NSString stringWithFormat:@"%@?%@",url,params];
NSURL *nsurl = [NSURL URLWithString: PreUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:nsurl];
[self.WebView loadRequest:request];
}
Проблема, с которой я столкнулся в этом коде, заключается в том, что если я загружу изображение, например, оно будет определено как "добавляемое к хешированию" (это правильно, я хочу, чтобы в каждом запросе был включен Auth), НО изображение будет загружено в Сам вебвью.
Моя первая попытка (до того, как я переключился на эту модель) состояла в том, чтобы изменить проанализированный запрос. Но каждое изменение было проигнорировано....
У кого-нибудь есть идея, как я могу решить эту проблему? Есть ли способ действительно изменить запросы? Или, если нет, могу ли я хотя бы определить "цель" запроса или переслать его?
Спасибо за любую помощь
1 ответ
Я нашел решение для моей проблемы. Sublcassing был правильным подходом, но не UIWebView, а собственным NSURLProtocol.
Итак, что я сделал:
Создайте собственный Sublcass NSURLProtocol
@interface MyURL : NSURLProtocol <NSURLConnectionDelegate>
Добавьте некоторую стандартную обработку для HTTP-соединений
@interface MyURL () <NSURLConnectionDelegate>
@property (nonatomic, strong) NSURLConnection *connection;
@property (nonatomic, strong) NSMutableData *mutableData;
@property (nonatomic, strong) NSURLResponse *response;
@end
@implementation MyURL
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
return request;
}
- (void)stopLoading
{
[self.connection cancel];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.client URLProtocol:self didLoadData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[self.client URLProtocol:self didFailWithError:error];
self.connection = nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self.client URLProtocolDidFinishLoading:self];
self.connection = nil;
}
@end
А теперь интересная часть - изменение каждого запроса, который идет на мой сервер
Итак, сначала: проверьте, идет ли этот запрос на мой сервер, и определите, должен ли мой протокол о нем позаботиться.
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
NSString *token = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginToken];
NSString *hash = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginHash];
if([NSURLProtocol propertyForKey:@"TokenSet" inRequest:request]) return NO; // We already handled it
if((hash == nil) || (token == nil) ) return NO; // We are not logged in
NSString *params = [NSString stringWithFormat:@"mobile=app&user_token=%@&user_hash=%@",token,hash];
if (([[[request URL] absoluteString] rangeOfString:BASE_URL].location != NSNotFound) && ([[[request URL] absoluteString] rangeOfString:@"/assets/"].location == NSNotFound)){
if([[[request URL] absoluteString] rangeOfString:params].location == NSNotFound){
return YES; // URL does not contain the login token & we're not requesting an asset (js/img/etc.)
}
}
return NO;
}
Так что если + (BOOL)canInitWithRequest:(NSURLRequest *) запрос вернул да, я должен обработать запрос. Я уже знаю, что он не содержит токен входа и хэш, поэтому я должен определить, должен ли он быть добавлен или нет. Чтобы изменить запрос в целом, я создаю MutableCopy нашего запроса, изменяю его и устанавливаю наш URLConnection на запрос.
- (void)startLoading
{
NSMutableURLRequest *newRequest = [self.request mutableCopy];
NSString *PreURL;
NSString *token = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginToken];
NSString *hash = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginHash];
NSString *params = [NSString stringWithFormat:@"mobile=app&user_token=%@&user_hash=%@",token,hash];
if([[newRequest URL] query] == nil) {
PreURL = [NSString stringWithFormat:@"%@?%@",[[newRequest URL] absoluteString],params];
}else{
if([[[newRequest URL] absoluteString] rangeOfString:params].location == NSNotFound){
PreURL = [NSString stringWithFormat:@"%@&%@",[[newRequest URL] absoluteString],params];
}
}
NSURL *nsurl = [NSURL URLWithString: PreURL];
[newRequest setURL:nsurl];
[NSURLProtocol setProperty:@"YES" forKey:@"TokenSet" inRequest:newRequest];
self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
И чтобы закончить все это, мы регистрируем наш URL-протокол как протокол в AppDelegate.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[NSURLProtocol registerClass:[MyURL class]];
}
С помощью этого решения я в первую очередь имею преимущество в том, что токен для входа в систему ЛЮБОЙ запрос отправляет ЛЮБОЙ части моего Приложения на мой Сервер. Больше не надо беспокоиться об этом. И я могу делать классные вещи, такие как сохранение ресурсов после их первой загрузки или даже использовать изображения из моего набора приложений в веб-обозрениях...
Я надеюсь, что это помогает кому-то.