2

現在、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 を含める必要があります)。しかし、イメージはウェブビュー自体。

私の最初の試み (このモデルに切り替える前) は、解析されたリクエストを変更することでした。しかし、すべての変更は無視されました....

この問題を解決する方法を知っている人はいますか? リクエストを実際に変更する方法はありますか? または、そうでない場合、少なくともリクエストの「ターゲット」を特定するか、転送できますか?

助けてくれてありがとう

4

1 に答える 1

3

問題の解決策を見つけました。サブキャッシングは正しいアプローチでしたが、UIWebView ではなく独自の NSURLProtocol でした。

だから私がしたこと:

NSURLProtocol の独自の Sublcass を作成します

@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 が yes を返した場合は、リクエストを処理する必要があります。ログイントークンとハッシュが含まれていないことはすでにわかっているので、追加する必要があるかどうかを判断する必要があります。一般的にリクエストを変更するには、リクエストの 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 を Protocol として AppDelegate に登録します。

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

このソリューションを使用すると、最初に、アプリの任意の部分がサーバーに送信される任意のリクエストにログイントークンを含めることができるという利点があります。これでもう心配いりません。また、最初にリソースをロードした後にリソースを保存したり、Webviews で App-Bundle の画像を使用したりするなど、クールなこともできます...

これが誰かに役立つことを願っています。

于 2014-04-27T04:59:16.657 に答える