Vkontakte iOS SDK v2

    Good evening!

    It all started with the fact that a more or less convenient tool was needed to work with the API of the social network VKontakte for iOS. However, Google quickly upset me with the search results:

    Everything seems to be fine, the most important thing is, but the use does not cause pleasant sensations.

    Under the cut, I’ll tell you how the updated version of VKontakte iOS SDK v2 works, how it all started and where it came to.


    Introduction


    Description of the first version of Vkontakte iOS SDK on Habré can be found on this link.

    The second version is fundamentally different from the first and the one that is integrated into ASASocialServices .

    In order to better understand what changed after the release of the first version, you need to understand what were the main features / disadvantages of the first version:
    • Inability to cache requests
    • Requests were synchronized
    • Lack of file upload status on VK server
    • The inability to work with multiple users (meaning the storage and reuse of authorization data like an access token)
    • It was not possible to log out of the current authorized user account.


    In the second version, many of the shortcomings, or rather all, were eliminated (new ones may have appeared, but we will try to fix and eliminate them over time) and now there are the following features / features in the SDK:
    • storage that allows you to work with many users
    • request caching for each user separately
    • logout of the last authorized user
    • requests are now separate classes that you can use and configure for yourself (there is a connection between requests and storage)
    • requests are now used by delegates to notify about the status of the request (use of blocks is considered, but no more)
    • the ability to track the status of uploading a file to the VK server
    • the user is now an object in which all the actions that he can perform are encapsulated (join a group, leave a message on the wall, etc.)
    • documentation, which in the second version has become better, more complete and in which it will now be possible to find some interesting features in the work of classes / methods


    From plans for the future, the following points can be distinguished:
    • An implementation of a class of type VKRequest, which will already operate with blocks. The programmer will have the opportunity to select and use either requests + delegates or requests + blocks.
    • Improve the storage and add the ability to the programmer to specify his own storage, which will meet some mandatory protocol methods VKStorageDataDelegate + VKStorageCacheDataDelegate.
    • Implement the ability to auto-update cache data for specific requests. It may look something like this: in the background, at specified intervals, a request will be made, which, if successful, will update the cache data, thereby speeding up the subsequent data retrieval for this request.
    • Storage of custom cookies to implement automatic login and update access token.
    • Adding another method to VKConnectorDelegate, which will be called when it is necessary to carry out any user actions (captcha input, data input during application authorization, etc.)
    • ...


    Storage


    The repository ( VKStorage) was conceived as a kind of data management point for authorized users.

    Storage can perform the following actions:
    • Add New Object
    • Delete specific object
    • Delete all data
    • Delete all cache data
    • Get the storage object by the specified user identifier (the "keys" in the repository are user unique identifiers)
    • Get all objects that are in storage


    The storage consists of storage objects - VKStorageItemwhich is nothing more than an object containing two fields - a user access token and a cache object.

    To initialize the storage object, it is enough to specify the user access token and the main directory for the cache (not specifically for this user, but in general).

    The storage stores access tokens in NSUserDefaults, but the cache data in NSCachesDirectory. Class

    interfaceVKStorage .

    Refer to the documentation more often if you have any questions or if you doubt something:
    image

    Data caching



    When implementing the query caching mechanism, I wanted to get something convenient, simple and flexible.
    The class is responsible for caching user requests VKCachedData.
    The class instance is initialized by the directory in which request caches will be stored (in this case, the directory path must be unique for each user).

    What actions can be carried out:
    • Add certain data for the specified NSURL to the cache (there were several reasons to use NSURL rather than NSURLRequest, and the main reason was the fact that all requests are sent to the VK using the GET + method, no additional headers are sent, POST requests are not cached)
      Current view subject to revision and amendment
    • Add specific data for the specified NSURL to the cache with the specified lifetime.
      Possible values ​​for cache lifetime:
      typedefenum
      {
          VKCachedDataLiveTimeNever = 0,
          VKCachedDataLiveTimeOneMinute = 60,
          VKCachedDataLiveTimeThreeMinutes = 3 * 60,
          VKCachedDataLiveTimeFiveMinutes = 5 * 60,
          VKCachedDataLiveTimeOneHour = 1 * 60 * 60,
          VKCachedDataLiveTimeFiveHours = 5 * 60 * 60,
          VKCachedDataLiveTimeOneDay = 24 * 60 * 60,
          VKCachedDataLiveTimeOneWeek = 7 * 24 * 60 * 60,
          VKCachedDataLiveTimeOneMonth = 30  * 24 * 60 * 60,
          VKCachedDataLiveTimeOneYear = 365 * 24 * 60 * 60,
      } VKCachedDataLiveTime;
      


      By default, all requests have a cache lifetime of one hour.
    • Delete cache for specified NSURL
    • Removing the cache directory
    • Delete all caches (without deleting the directory in which the data is located)
    • Get cached data according to the specified one NSURL(you can process the returned data in standard mode or offline)


    During development, I encountered the following problem: if at each new authorization the user updates his access token, then each time the request cache will be stored under a different name (the cache name is an MD5 hash of the query string), although the request is logically the same. therefore, when you call again, the data will be overwritten or re-requested from the network.
    The solution turned out to be an exception token access NSURLwhen saving data to the cache. Thus, the same requests, but with different user access tokens, will have one cache file.

    Now I will describe why and why the feature was introducedofflineMove(offline query mode): I imagined a usual situation when there is no network, but there is data in the cache, which means that you need to return it so that you do not enter any additional error messages or a simple nil return. A feature of the offline mode is the fact that even if the requested cache data is out of date (their lifetime has expired), they will be returned and they will not be deleted until the network appears and the next same request updates the data.

    If you do not need to use query caching, then set the request cache lifetime to VKCachedDataLiveTimeNever.

    Each request contains a field cacheLiveTimethat is the lifetime of the data cache of only the current request. By default, the data cache lifetime is set to one hour.

    Caching Images, Audio, Video

    As such, there is no separate method for caching images / audio / video, but this can be easily circumvented as follows (we will show by example):
    NSUInteger currentUserID = [VKUser currentUser].accessToken.userID;
        VKStorageItem *item = [[VKStorage sharedStorage]
                                          storageItemForUserID:currentUserID];
        NSString *mp3Link = @"https://mp3.vk.com/music/pop/j-lo.mp3";
        NSURL *mp3URL = [NSURL URLWithString:mp3Link];
        NSData *mp3Data = //mp3 data from request
        [item.cachedData addCachedData:mp3Data
                                forURL:mp3URL
                              liveTime:VKCachedDataLiveTimeOneMonth];
    


    The specified track will be stored for a week, either until the system clears the cache folder for free space, or you yourself do not.

    Connector



    The main role VKConnectoris to obtain a custom access token and store it in the store.

    You can start the process of obtaining a custom access token as follows:

    [[VKConnector sharedInstance]startWithAppID:@"12345" permissions:@[@"friends", @"wall", @"groups"]];
    

    After calling this method, the following authorization window will appear in front of the user:

    image

    After the user enters his data and presses "Enter":

    image

    The window will disappear with smooth animation. User authorization

    video .

    The connector allows you to log out the last authorized user using the method logout.

    VKConnectorallows the programmer to monitor at what stage the user’s authorization is now, whether the authorization window will be displayed, whether the window will be hidden, whether the access token has been updated or not, whether the access token is outdated or not, etc. For details, see VKConnectorDelegate.

    It is also worth noting that when a user is reauthorized, his local access token (located in the repository) is updated and saved for further requests.

    Inquiries



    Requests are, in my opinion, the most interesting class implemented (after the data cache :)).

    In general, they allow you to make requests not only to the VKontakte social network (there is no hard link), but also do not exclude convenient methods for working with this particular social network:

    - (instancetype)initWithMethod:(NSString *)methodName
                           options:(NSDictionary *)options;
    

    A description of the method can be found in the documentation.

    Requests are asynchronous and work with delegates. Delegates must comply with a protocol VKRequestDelegatein which only one method is required - a method for processing a server response.
    As optional methods are:
    1. connection error message processing
    2. processing error message parsing server response from JSON format to Foundation object
    3. data download status
    4. data sending status


    Each request has some very useful properties:

    1. Signature
    2. Cache lifetime for current request (cacheLiveTime)
    3. Offline request mode (offlineMode)


    Let's consider each property in more detail:

    1. Signature A
      signature of an object can be any object, either a dictionary of certain related data or just a string. This was implemented with the idea that when a single class processes several requests (getting friends and personal information about each user), it is necessary to distinguish one request from another in some way. Making the signature fixed would be wrong and inconvenient, so it was decided to leave the choice of signature to the programmer.
      It is worth knowing, when making requests from a class VKUser, each request is signed by a selector line of the method that created it.
    2. Cache lifetime for the current request (cacheLiveTime)
      The cache lifetime for this request is determined by this property. Some data changes very often (news feed, user’s wall), which means it would be wrong to use aggressive caching and store data for as long as possible, but other requests, such as a list of user friends, a list of groups, a list of subscribers, etc. live quietly for several days in the cache.
      If a request is made to a certain file / audio recording / video recording, then such things can be stored for a very long time and do not change, so you can use the maximum lifetime of one year ( VKCachedDataLiveTimeOneYear) for them .
    3. Offline request mode ( offlineMode)
      Offline mode directly affects how cache data is returned. In the absence of an Internet connection, it is strongly recommended to use this mode. It will allow you to "extend" the lifetime of data from the cache, which in standard mode should have been deleted.


    When creating a request, its execution does not begin immediately, but after the call start.
    Consider an example:
    VKRequest *infoRequest = [VKRequest requestMethod:@"users.get" options:@{} delegate:self];
    //возможная настройка свойств
    infoRequest.cacheLiveTime = VKCachedDataLiveTimeOneMonth;
    infoRequest.signature = @"Some signature string";
    //какие-то действия
    [infoRequest start]; // запрос стартовал


    You can safely cancel the request if you have a variable that refers to it, or cancel in one of the delegate methods VKRequestDelegate.

    Example:
    [infoRequest start]; // запрос стартовал// какие-то действия// надо отменить запрос
    [infoRequest cancel];
    


    The most advanced method is:
    + (instancetype)requestHTTPMethod:(NSString *)httpMethod
                                  URL:(NSURL *)url
                              headers:(NSDictionary *)headers
                                 body:(NSData *)body
                             delegate:(id <VKRequestDelegate>)delegate;
    


    As you can see, this method allows you to configure a request to the server with the maximum number of significant parameters.
    It may be useful when implementing downloads of audio / video to the server.

    This is what the request description (example) returned by the method looks like description:
    {
        cacheLiveTime = 3600;
        delegate = "<ASAAppDelegate: 0x752c540>";
        offlineMode = NO;
        request = "<NSMutableURLRequest https://api.vk.com/method/users.getFollowers>";
        signature = "followersWithCustomOptions:";
    }
    


    User



    The user class allows you to make requests on behalf of the currently active user.

    Consider several class methods that play an important role when working with multiple users in an application:

    1. + (instancetype)currentUser
    2. + (BOOL)activateUserWithID:(NSUInteger)userID
    3. + (NSArray *)localUsers


    Let's consider in more detail.

    1. + (instancetype)currentUser
      Getting the currently active user. Here is how this method is described in the documentation:
      image
    2. + (BOOL)activateUserWithID:(NSUInteger)userID
      Makes the user with the specified user id active. Useful method if your application plans to connect multiple user accounts.
    3. + (NSArray *)localUsers
      Getting a list of users in the repository. Only user identifiers will be in the array.


    Now let's talk about properties, which also play an important role in how the query results and the queries themselves will be processed.

    • Start executing queries immediately

      By default, all queries begin their execution immediately after calling the method in which they were created. In order to gain control over the start / cancellation of the execution of requests, you must do the following:
      [VKUser currentUser].startAllRequestsImmediately = NO; // работает для всех последующих запросов, а не только для одного
      VKRequest *infoRequest = [[VKUser currentUser] infoWithCustomOptions:@{@"uids": @"1"}];
      // какие-то действия
      [infoRequest start];
      


      If you want to manage only one request, then you can do the following:
      [VKUser currentUser].startAllRequestsImmediately = NO;
      VKRequest *infoRequest = [[VKUser currentUser] infoWithCustomOptions:@{....}];
      [VKUser currentUser].startAllRequestsImmediately = YES;
      //какие-то действия
      [[VKUser currentUser] groupsJoinWithCustomOptions:@{...}]; // выполнение запроса стартует немедленно

    • Offline mode

      Allows you to make all subsequent requests in offline mode, a mode where cache data is not deleted even if it expires.


    An example of getting users in a specific group:
    [VKUser currentUser].delegate = self;
    [[VKUser currentUser] groupsGetMembersWithCustomOptions:@{
        @"group_id": @"1",
        @"count" : @"100",
        @"offset": @"0"
    }];
    


    Documentation



    I always try to keep the documentation up to date and write about the possible features of using classes, methods, properties.
    I believe that without good documentation, the programmer will not have much desire to understand other people's code and generally use the SDK.

    A few screenshots of the current documentation, which will reflect its entirety and integrity:

    image

    image

    image

    image

    In conclusion



    The article, it seems to me, turned out to be quite long, so for now I will dwell on this. I mentioned a lot and tried to describe in such a way that you have a holistic picture.

    I want to note that the project is actively developing and supported.

    You can find the most current version at this link: GitHub ( github.com/AndrewShmig/Vkontakte-iOS-SDK-LV )

    Also popular now: