iOS - Use AFNetworking with custom NSURLProtocol class
Asked Answered
D

3

7

I have a custom NSURLProtocol class that I have implemented with the help of this tutorial. My implementations are pretty much the same as in the tutorial, aside from the names, data model, etc...

Essentially, I am trying to send a HTTP request, but instead of the URL starting with: "http://", it needs to start with, say: "bla://"

Now, I am trying to register the protocol class and use it via the AFNetworking framework, and I'm having some trouble.

The canInitWithRequest: method starts returning NO at some point, and at this point the request fails and I keep getting a "unsupported URL" error.

In addition to registering the protocol class, I have tried to add the class to AFHTTPSessionManager's protocolClasses by calling this in thedidFinishLaunchingWithOptions method:

[NSURLProtocol registerClass:[MyURLProtocol class]];
NSMutableArray *protocolsArray = [NSMutableArray arrayWithArray:[AFHTTPSessionManager manager].session.configuration.protocolClasses];
[protocolsArray addObject:[MyURLProtocol class]];
[AFHTTPSessionManager manager].session.configuration.protocolClasses = [protocolsArray copy];

And I have also added the url scheme to the URL Schemes field in the app's info.plist

Still no luck... Is what I'm trying to do even possible? And if so, what could I be missing? Thanks

Dahlberg answered 26/1, 2015 at 10:36 Comment(3)
Do your methods in your NSURLProtocol class get called?Bakerman
Yes, the protocol methods seem to be working fine. Moreover, when I put "http://" in the beginning of the request url, the server responds (with the wrong response of course, because it's the wrong protocol). So the requests are definitely being sent.Dahlberg
I just tested what ryanwa suggests and it works.Bick
C
6

So, for other looking for information about this:

Along with the fact that AFURLSessionManager doesn't use the standard NSURLProtocol registrations, it also processes the array First-In-First-Out, not Last-In-First-Out like NSURLProtocol.

Meaning, if you want to overwrite the behavior of the AFURLSessionManager (say for testing purposes), you can't just add your NSURLProtocol subclass to session.configuration.protocolClasses, you must instead add it to the beginning of the array (or at least in front of the behavior you're overwriting/modifying).

Cheddite answered 24/2, 2015 at 6:48 Comment(1)
Correct answer: changing the line [protocolsArray addObject:[MyURLProtocol class]]; to [protocolsArray insertObject:[MyURLProtocol class] atIndex:0]; shuld work.Bick
I
2

So, firstly @dopcn is right that you need to retain your instance of AFHTTPSessionManager.

@ryanwa was partially correct that you need to insert the new protocol at the start of the array, but it still won't work because the configuration can't be changed after the NSURLSession is made. The correct solution is to use initWithSessionConfiguration:

NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSMutableArray * protocolsArray = [sessionConfiguration.protocolClasses mutableCopy];
[protocolsArray insertObject:[MyURLProtocol class] atIndex:0];
sessionConfiguration.protocolClasses = protocolsArray;
AFHTTPSessionManager * myManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:sessionConfiguration]; //retain this somewhere!

As far as I'm aware you don't need to register your NSURLProtocol subclass with registerClass. This worked for me on iOS 9.1 on an iPad Mini 4.

From the docs on NSURLSession:

@property(readonly, copy) NSURLSessionConfiguration *configuration

Description

A copy of the configuration object for this session. (read-only) Changing mutable values within the configuration object has no effect on the current session, but you can create a new session with the modified configuration object.

Incorporated answered 26/1, 2016 at 21:58 Comment(0)
E
1

Hi [AFHTTPSessionManager manager] doesn't return a singleton object instead it returns a brand new instance. So if you just set protocolClasses in didFinishLaunchingWithOptions for one instance of AFHTTPSessionManager but use another instance created by [AFHTTPSessionManager manager] elsewhere the new manager doesn't has your custom protocol class registered. This might lead to problem.

Expulsion answered 26/1, 2015 at 15:12 Comment(1)
Thanks! that's very good to know. I have moved the AFHTTPSessionManager instance to a singleton utility class in my app, but unfortunately this didn't solve my problem. BTW, it turns out that the example project gives me the same result when I punch in my server's address. I have a feeling that there's something wrong with the implementation of the protocol itself...Dahlberg

© 2022 - 2024 — McMap. All rights reserved.