【问题标题】:Modify Request of webView shouldStartLoadWithRequest:修改 webView 的 Request 的 shouldStartLoadWithRequest:
【发布时间】:2014-04-24 09:00:13
【问题描述】:

目前我正在开发一个混合应用程序,它使用 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)但是图像将被加载到 Webview 本身中。

我的第一次尝试(在我切换到这个模型之前)是修改解析的请求。但是每一个变化都被忽略了......

有没有人知道我该如何解决这个问题?有没有办法真正修改请求?或者如果没有,我至少可以确定请求的“目标”或转发它吗?

感谢您的帮助

【问题讨论】:

  • 你是否厌倦了子类化UIWebView

标签: ios objective-c webview shouldstartload


【解决方案1】:

我找到了解决问题的方法。 Sublcassing 是正确的方法,但不是 UIWebView,而是一个自己的 NSURLProtocol。

所以我做了什么:

创建一个自己的 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 *)request 返回是,我必须处理请求。我已经知道它不包含登录令牌和哈希,所以我必须确定是否必须附加它。一般来说,为了修改请求,我为我们的请求创建了一个 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-Protocol 注册为 AppDelegate 中的协议。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [NSURLProtocol registerClass:[MyURL class]];
}

有了这个解决方案,我首先拥有的优势是在我的应用程序的任何部分发送到我的服务器的任何请求中都有我的登录令牌。不用再担心这个了。而且我可以做一些很酷的事情,比如在第一次加载资源后节省资源,甚至在 Webviews 中使用我的 App-Bundle 中的图像......

我希望这对某人有所帮助。

【讨论】:

  • 是的,这太棒了;谢谢你张贴这个。对我来说,简洁与彻底的程度恰到好处!
  • 有没有办法只为webview注册url协议?此解决方案将修改应用程序中的所有请求。
  • 抱歉,我知道这已经很晚了 - 最近没有在这里检查过,但如果我没记错的话,这是修改 webview 的每个请求的唯一方法,例如来自内部或图像的 ajax 调用/文件已加载。但是您可以轻松地将标签或获取参数附加到您的应用程序在 web 视图之外发出的每个请求,并让 urlprotocol 基于它忽略它们
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-15
  • 1970-01-01
相关资源
最近更新 更多