Consumer Wallet

SDK Documentation

The Horizon Wallet SDK for iOS makes it quick and easy to build an excellent payment experience in your iOS app. We provide a powerful workflow and APIs that enables your UI to complete the full customer experience.

Consumer Wallet SDK has been built as a private pod.
Minimum deployment target: iOS 11.0.
In order to be able to use Wallet SDK in projects the first step is to install cocoapods:
sudo gem install cocopods.

How to add horizonWalletSDK to the project

  1. Create a Podfile in project using this command:
    pod init
  2. Within Podfile put at the top:
    source 'https://development.targit.at/horizon/cocoapods-specs'
  3. Enter next command in terminal in order to fetch specs files:
    pod repo add horizon-cocoapods-specs 'https://development.targit.at/horizon/cocoapods-specs'
  4. Below this line, for specific app target put:
    pod 'horizonWalletSDK'
  5. Our SDK uses AFNetworking library 2.6 version so in order to be able to submit the app on AppStore add next pre_install script in Podfile:
# Workaround to remove all UIWebView references from AFNetworking(later AFNetworking should be migrated to the latest version)
pre_install do |installer|
  puts 'pre_install begin....'
  dir_af = File.join(installer.sandbox.pod_dir('AFNetworking'), 'UIKit+AFNetworking')
  Dir.foreach(dir_af) {|x|
    real_path = File.join(dir_af, x)
    if (!File.directory?(real_path) && File.exists?(real_path))
      if((x.start_with?('UIWebView') || x == 'UIKit+AFNetworking.h'))
        File.delete(real_path)
        puts 'delete:'+ x
      end
    end
  }
  puts 'end pre_install.'
end
  1. In order to be able to run app on M1 machines on iOS simulators add next post_install script in Podfile:
post_install do |installer|

  # Path CocoaPods targets build settings
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|

    config.build_settings['SWIFT_VERSION'] = '5.0'
    config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
    
    end
  end
end
  1. Run pod install.

Afterwards, use .xcworkspace file instead of .xcodeproj.

How to update horizonWalletSDK in the project

  1. Run pod update command.

How to use horizonWalletSDK in the project

There are 3 main clients in SDK which should be instantiated from the project level in order to be able to use SDK.
If one of them is missing (not configured), the app will crash.
Main clients are:

  1. AccountDataClient
  2. WalletClient
  3. PaymentClient

They can be configured via horizonWalletSDK class.
horizonWalletSDK class is the main class in SDK used for setup:
AccountDataClient, WalletClient and PaymentClient.

Before instantiating AccountDataClient we need to instantiate 2 clients which should be injected in AccountDataClient:

  1. IdentityClient
  2. IdentityVerificationClient.

IdentityClient
This client handles all registrations and account activations. With this client we can request to start the registration procedure, set first pin, activate pin, set touch id and etc...

Instantiating IdentityClient:

@property (nonatomic, strong, readwrite) IdentityClient *identityClient;
@property (nonatomic, strong, readwrite) TouchIDSupport *touchIDSupport;

self.touchIDSupport = [TouchIDSupport new];
[self.touchIDSupport start];

self.identityClient = [IdentityClient sharedInstanceWallet];
self.identityClient.codeSettingsConvenience = [IdentityClientCodeSettingConveniences conveniencesWithIdentityClient:self.identityClient touchIDSupport:self.touchIDSupport];

[self.identityClient start];

Usage of IdentityClient

With this client registration and restoration of a user can be started, a pin code can be set, the app can be locked and unlocked and touch/face ID can be used.

In order to disable locking device you can simple use these methods:

- (void)deactivatePin;
- (BOOL)setTouchIDOn:(BOOL)on error:(NSError **)error;

// Examples of calling
[self.identityClient setTouchIDOn:NO error:nil];
[self.identityClient deactivatePin];

IdentityVerificationClient
This client handles the verification of identity, so when the user registers in the app, he needs to confirm (verify) his identity.

Instantiating IdentityVerificationClient:

@property (nonatomic, strong, readwrite) IdentityVerificationClient *identityVerificationClient;

self.identityVerificationClient = [[IdentityVerificationClient alloc] initWithIdentityClient:self.identityClient];

Cache
Our SDK also supports caching. There are two different types: persistent and temporary.
Cache will later be used for injecting in different clients: AccountDataClient, WalletClient, and etc...

Instantiating Cache:

@property (nonatomic, strong, readwrite) Cache *cache;

// Depends if we need to use persistent cache or temporary cache
if ([[NSUserDefaults standardUserDefaults] boolForKey:KKWApplicationConfigurationFeaturePersistentCacheEnabled]) {
    self.cache = [Cache persistentCache];
} else {
    self.cache = [Cache temporaryAnonymousCache];
}

Registration and reactivation of a consumer

We provide a straight forward registration process and support the a reactivation of a wallet as well. The consumer receives a registration code per SMS and a link per mail.

This shows how the app could look like:

Registration process can be started with one of these two methods:

- (void)requestStartRegistrationProcedure;
- (void)requestStartPinlessRegistrationProcedure;

Usually second one should be use if you want to start registration with disabled pin code.

Next step is to setup user data and start registration process with those that and invitation code.
Invitation code is optional here.
You can use first two methods, or third one that is shortcut for first two methods.

- (void)prepareWalletUserData:(WalletUserData *)walletUserData;
- (void)registerWithInvitationCode:(NSString *)invitationCode;

- (void)registerWithWalletUserData:(WalletUserData *)walletUserData invitationCode:(NSString *)invitationCode; // short-cut for the above two

You can skip invitation code step with:

- (void)cancelEnteringInvitationCode;

Next step is to send puk code to server that is received on phone number entered from first step.

- (void)requestRegistrationWithPuk:(NSString *)puk;

User also need to confirm his email in order to activate account.
After this step, wallet activation is called automatically and identity client is formed. User can access to the app.
If user didn't confirm email yet, you can always check activation of account calling method:

- (void)retryCheckActivationAgain;

After this you continue with sending user email and then confirming puk code

- (void)requestRestorationPukWithEmail:(NSString *)email;
- (void)requestRestorationWithPuk:(NSString *)puk;

Restoration process is similar like registration process.
Only difference is first step, where you send only email.
You start restoration process with one of those two methods(same principle as for registration):

- (void)requestPinlessRestoration;
- (void)requestRestoration;

After this reactivation step is called automatically but also you can handle it from universal link.

- (void)reactivateWithReactivationToken:(NSString *)reactivationToken;
- (void)reactivatePinlessWithReactivationToken:(NSString *)reactivationToken;

Add Payment Methods

with our SDK the consumer is able to add multiple methods of payment to your app. The following example will focus on adding a credit card.

WalletClient
This client handles everything related to credit cards. For example: adding credit cards, removing credit cards, updating credit cards, fetch all credit cards for authenticated user.

In order to instantiate WalletClient we need to instantiate a few other clients, CustomStatusMessageManager and NetworkReachability:

  1. BonusProgramClient
  2. GoldProgramMembershipsClient
  3. CouponProgramClient
  4. DailyTokenClient
    Instantiation of those clients you can found below on topics Handling of backend messages and network status and Loyalty Program**

Instantiating:

@property (nonatomic, strong, readwrite) WalletClient *walletClient;

self.walletClient = [[WalletClient alloc] initWithIdentityClient:self.identityClient identityVerificationManager:self.identityVerificationClient bonusProgramClient:self.bonusProgramClient goldProgramMembershipsClient:self.goldProgramMembershipsClient couponProgramClient:self.couponProgramClient customStatusMessageManager:self.customStatusMessageManager dailyTokenClient:self.dailyTokenClient cache:self.cache];
self.walletClient.networkReachability = self.networkReachability;
[WalletClientSDK.sharedInstance setupWalletClient:self.walletClient];

[self.walletClient start];

Usage of WalletClient

With this client you can get, add, remove and update credit card.

You can retrieve and get user wallet, credit cards with this method:

- (id<Cancellable>)enqueueGetWalletWithCompletion:(WalletClientCompletion)completion;

Update and remove credit card can be done with those two methods(api calls):

- (id<Cancellable>)enqueueUpdateCard:(PaymentCard *)card withStatus:(BOOL)status cardName:(NSString *)cardName completion:(CardActivationCompletion)completion;
- (id<Cancellable>)enqueueRemoveCardWithID:(KKW_ID)cardID completion:(CardRemoveCompletion)completion;

Add credit card process is more complex and can be done with next flow.
First you need to execute api call and send credit card details data to server. You can do it with this method:

- (void)enqueueAddPaymentCardWithID:(KKW_ID)cardTypeID cardholder:(NSString *)cardholder cardNumber:(NSString *)cardNumber cvc:(NSString *)cvc expDate:(NSString *)expDate completion:(WalletClientAddCardCompletion)completion;

From this api call AddCreditCardPayload object will be stored in paymentPayload property.
You use data from this property to finish add credit card process.
In this class you have PaymentDetails object that handle data for 3DS of credit card.
You can retrieve those that with this example:

[WalletClient sharedInstance].paymentPayload.paymentData

Check property card3DSNotEnrolled to determinate if credit card need to pass 3DS flow.
If yes you need to load POST request in web view with url from redirectionUrl property.
Body parameters for this request you can get from method(you need to pass boundary):
Example for boundary(string): "----WebKitFormBoundary7MA4YWxkTrZu0gW"

- (NSMutableData *)getJsonBodyDataWithBoundary:(NSString *)boundary;

You need to add header value for this request also:

request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

To handle result of web view POST request and to finish add credit card process you have to do next:

  • You need to fetch "MD" and "PaRes" parameters from response of web view request(in code snippet example we fetch those parameters calling JS script).
  • You will be redirected on url from this property postDataTermUrl.
    Example of web view listener method:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        if let url = webView.url?.absoluteString, let termUrl = paymentDetails?.postDataTermUrl {
            if url == termUrl { // Continue only if you are redirected on term url(postDataTermUrl)
                let jsCode = "var values={};" +
                    "var form = document.getElementsByTagName('form').length > 0 ? document.getElementsByTagName('form')[0] : null;" +
                    "console.log('RESULT 1='+form.elements);" +
                    "function results(form) {" +
                    "for(var i=0 ; i< form.elements.length; i++){" +
                    "   values[form.elements[i].name] = form.elements[i].value;" +
                    "}" +
                    "return values;" +
                    "}" +
                    "if (form) results(form);"
                
                self.webView.evaluateJavaScript(jsCode, completionHandler: { (result, error) in
                    if let dictionary = result as? NSDictionary {
                        guard let md = dictionary.value(forKey: "MD") as? String, let paRes = dictionary.value(forKey: "PaRes") as? String else {
                            // TODO: Display error
                            return
                        }
                        // TODO: Execute add credit card with parameters md and paRes
                    }
                })
            }
        }
    }

Finally you can call last api call and finish the add credit cards process.
The parameters for this api call you should have retrieved from the previous step.
You also pass PaymentDetails as parameter retrieved from add credit card api call from the first step.
You can now finish the process by calling this method from WalletClient:

- (void)enqueueExecuteAddPaymentCardWithPaymentDetails:(PaymentDetails *)paymentDetails md:(NSString *)md paRes:(NSString *)paRes completion:(WalletClientAddCardCompletion)completion;

Payment Process

Our SDK allows a simple and intuitive payment process. The consumer can select the payment method of choice and add a tip to the payment. This is what it could look like in the app:

PaymentClient
This client handles everything related to payments.

Instantiating:

@property (nonatomic, strong, readwrite) PaymentClient *paymentClient;

self.paymentClient = [PaymentClient instanceWithIdentityClient:self.identityClient dailyTokenClient:self.dailyTokenClient bonusProgramClient:self.bonusProgramClient paymentCardIDProvider:self.walletClient]; // is 'restarted' in RootViewController
[WalletClientSDK.sharedInstance setupPaymentClient:self.paymentClient];

Usage of PaymentClient and ManualConnectionDecider

This client and decider is used for payment process.
In order to follow bluetooth activity for payment, bonus program redemption, coupon redemption, you will need to initialise and form ManualConnectionDeciderProtocol object. With this protocol you can track and confirm bluetooth activity and connection with other devices.
Example of init:

NSSet *deciderSet = [NSSet setWithArray:@[
            [[self.paymentClient fusionTracker] manualConnectionDecider],
            [self.bonusRedemptionClient manualConnectionDecider],
            [self.goldRedemptionClient manualConnectionDecider],
            [self.couponRedemptionClient manualConnectionDecider]
        ]];

id<ManualConnectionDeciderProtocol> manualConnectionDecider = [ManualConnectionDeciderCollection collectionWithManualConnectionDeciders:deciderSet];

We pass this decider to our view that handle user actions for pairing with another device in order to pay, redeem bonus or coupon program.
You need to track ManualConnectionDeciderState in KVO controller in order to display proper view and handle next user actions.
Example:

self.paymentClientManualConnectionDecider = [[self.paymentClient fusionTracker] manualConnectionDecider];
        
@weakify(self);
[self.KVOControllerNonRetaining observe:self keyPath:@keypath(self.paymentClientManualConnectionDecider.state) options:NSKeyValueObservingOptionNew block:^(id observer, id object, NSDictionary *change) {
    dispatch_async(dispatch_get_main_queue(), ^{
        @strongify(self);

        ManualConnectionDeciderState state = self.paymentClientManualConnectionDecider.state;
        if (state == ManualConnectionDeciderStateWaitingForCandidate) {
            [self dismissPaymentIfNeeded];
        } else if (state == ManualConnectionDeciderStateAccepted) {
            WalletPaymentViewControllerNew *paymentViewController = (WalletPaymentViewControllerNew *)self.paymentNavigationController.topViewController;
            [paymentViewController startPaymentIfPossible];
        }
        NSLog(@"ManualConnectionDeciderState: %ld", state);
    });
}];

[self.KVOControllerNonRetaining observe:self keyPath:@keypath(self.paymentClientManualConnectionDecider.candidate) options:NSKeyValueObservingOptionNew block:^(id observer, id object, NSDictionary *change) {
    dispatch_async(dispatch_get_main_queue(), ^{
        @strongify(self);

        PeripheralTracking *tracking = NSOBJECT_DYNAMIC_CAST(self.paymentClientManualConnectionDecider.candidate, PeripheralTracking);
        KKW_ID sessionID = (KKW_ID)tracking.peripheralMetaData.additionalIdentifier.longLongValue;

        if (sessionID > 0 && self.paymentNavigationController == nil) {
            [self.identityClient.requestManager enqueueGetPaymentStateWithPosSessionID: (KKW_SessionID)sessionID
                                                                            completion:^(PaymentStatePayload *payload, NSError *requestError) {

                [self.paymentClientManualConnectionDecider startDeciding];
                [self showPaymentIfNecessaryWithPaymentOrder:payload.paymentOrder merchant:payload.merchant animated:YES];
            }];
        }
    });
}];

API that you can use for this protocol:

// API for view, can be called on main queue (may be async)
- (void)startDeciding;
- (void)decideForCandidate;
- (void)decideAgainstCandidate;
- (void)restart; // restart after completion

Call startDeciding method when you want to take ownership of current candidate for pairing.
decideForCandidate method should be called when user accept connection with device, for example accept payment or redemption of bonus program.
decideAgainstCandidate should be called when user denied connection.

In order to get merchant info about the payment we need to call getPaymentState API and in the response we need to tell ManualConnectionDecider object to start deciding and show payment screen.

[self.identityClient.requestManager enqueueGetPaymentStateWithPosSessionID: (KKW_SessionID)sessionID
                                                                                    completion:^(PaymentStatePayload *payload, NSError *requestError) {
                        
    [self.paymentClientManualConnectionDecider startDeciding];
    [self showPaymentIfNecessaryWithPaymentOrder:payload.paymentOrder merchant:payload.merchant animated:YES];
}];

When user wants to execute payment(click on "Pay" button or something else) we first need to tell ManualConnectionDecider to decide for candidate using next method:

[self.paymentClientManualConnectionDecider decideForCandidate];

We can observe state of ManualConnectionDecider object using next code and if it's accepted then we need to start connection to payment session:

[self.KVOControllerNonRetaining observe:self keyPath:@keypath(self.paymentClientManualConnectionDecider.state) options:NSKeyValueObservingOptionNew block:^(id observer, id object, NSDictionary *change) {
    dispatch_async(dispatch_get_main_queue(), ^{
        @strongify(self);

        ManualConnectionDeciderState state = self.paymentClientManualConnectionDecider.state;
        if (state == ManualConnectionDeciderStateWaitingForCandidate) {
            [self dismissPaymentIfNeeded];
        } else if (state == ManualConnectionDeciderStateAccepted) {
            WalletPaymentViewControllerNew *paymentViewController = (WalletPaymentViewControllerNew *)self.paymentNavigationController.topViewController;
            [paymentViewController startPaymentIfPossible]; // connect to payment session
        }
        NSLog(@"ManualConnectionDeciderState: %ld", state);
    });
}];

In order to connect to payment session we need to call next method on PaymentClient

- (void)connectToPaymentSession;

Last step of execution of payment should be calling PaymentClient method(pass confirm parameter and tip).
This method could be executed in onHostConnectedCallback method on PaymentClient*, or later by some user action(click on button for example). onHostConnectedCallback** method inform us that devices are connected and ready for execution of payment.

paymentClient?.onHostConnectedCallback = { [weak self] in
    guard let self = self else { return }
    self.paymentClient?.setOrderConfirmedByUser(true, tip: self.tip)
}

If PaymentClient enters at state PaymentClientStateCompletedWithError, that means some error occurred. You can display the error message and then you should restart PaymentClient and ManualConnectionDecider
Example:

self.paymentClient.humanizedError // Get error from this property

[self.paymentClient restart]; // Restart payment client
[self.paymentClient.fusionTracker.manualConnectionDecider restart]; // restart decider

If client enters at state PaymentClientStateAcquiringPaymentExecution, that means the payment process is started successfully and you can display to user payment animation for example.
After that when client enters at state PaymentClientStateCompleted, the payment process is finished, you can display message or view to user and finish ui part for payment success.
You can also display info regarding bonus program and points earned with this payment.
Take this data from bonusProgramMembership property of PaymentClient.
At the end you should also restart client.

[self.paymentClient restart]; // Restart payment client

Last step is the notification that is send when payment is finished, PaymentClientFinishedAPaymentNotification.
You should already subscribe to this notification in init phase of payment client. Check Start Observing Payment and Redemption at the top of document.

Show user data, transactions and details

The following use cases are focusing on displaying and updating the user as well as presenting transactions and their details.

AccountDataClient
This client handles everything account-related in SDK.
In example you can:
Get account data using the method:

- (id<Cancellable>)enqueueGetAccountData:(void (^)(WalletUserData *walletUserData, NSError *error))completion;

Set account data using the method:

- (void)enqueueSetAccountDataWithWalletUserData:(WalletUserData *)walletUserData completion:(void (^)(WalletUserData *walletUserData, NSError *error))completion;

Instantiating AccountDataClient:

@property (nonatomic, strong, readwrite) AccountDataClient *accountDataClient;

self.accountDataClient = [AccountDataClient accountDataClientWithIdentityClient:self.identityClient identityVerificationManager:self.identityVerificationClient cache:self.cache];
[WalletClientSDK.sharedInstance setupAccountDataClient:self.accountDataClient];

self.identityVerificationClient.accountDataClient = self.accountDataClient;

Usage of AccountDataClient
With this client wallet user data can be retrieved and updated.

- (id<Cancellable>)enqueueGetAccountData:(void (^)(WalletUserData *walletUserData, NSError *error))completion;
- (void)enqueueSetAccountDataWithWalletUserData:(WalletUserData *)walletUserData completion:(void (^)(WalletUserData *walletUserData, NSError *error))completion;

WalletTransactionsClient
This client handles everything related to transactions, for example getting transactions, transaction details etc...

Instantiating:

@property (nonatomic, strong, readwrite) WalletTransactionsClient *transactionsClient;

self.transactionsClient = [WalletTransactionsClient clientWithIdentityClient:self.identityClient cache:self.cache];

Loyalty Program

An additional feature of the SDK is the loyalty program which enables you to integrate bonus points for your consumers.

BonusProgramClient
This client handles everything that is related to the bonus program.

Instantiating:

@property (nonatomic, strong, readwrite) BonusProgramClient *bonusProgramClient;

self.bonusProgramClient = [BonusProgramClient bonusProgramClientWithIdentityClient:self.identityClient cache:self.cache];

GoldProgramMembershipsClient
This client handles everything related to the gold program.

Instantiating:

@property (nonatomic, strong, readwrite) GoldProgramMembershipsClient *goldProgramMembershipsClient;

self.goldProgramMembershipsClient = [[GoldProgramMembershipsClient alloc] initWithIdentityClient:self.identityClient cache:self.cache];

CouponProgramClient
This client handles everything related to the coupon program.

Instantiating:

@property (nonatomic, strong, readwrite) CouponProgramClient *couponProgramClient;

self.couponProgramClient = [CouponProgramClient couponProgramClientWithIdentityClient:self.identityClient cache:self.cache];

DailyTokenClient
This client handles everything related to the daily token. This means it is used for refreshing the token on a daily basis.

Next is instantiating redemption clients:

@property (nonatomic, strong, readwrite) DailyTokenClient *dailyTokenClient;

self.dailyTokenClient = [DailyTokenClient dailyTokenClientWithIdentityClient:self.identityClient cache:self.cache];

Bonus Redemption Client

@property (nonatomic, strong, readwrite) RedemptionClient *bonusRedemptionClient;

self.bonusRedemptionClient = [RedemptionClient redemptionClientForBonusRedemptionWithIdentityClient:self.identityClient dailyTokenClient:self.dailyTokenClient bonusProgramClient:self.bonusProgramClient];

Gold Redemption Client

@property (nonatomic, strong, readwrite) RedemptionClient *goldRedemptionClient;

self.goldRedemptionClient = [RedemptionClient redemptionClientForGoldRedemptionWithIdentityClient:self.identityClient dailyTokenClient:self.dailyTokenClient bonusProgramClient:self.bonusProgramClient];

Coupon Redemption Client

@property (nonatomic, strong, readwrite) RedemptionClient *couponRedemptionClient;

self.couponRedemptionClient = [RedemptionClient redemptionClientForCouponRedemptionWithIdentityClient:self.identityClient dailyTokenClient:self.dailyTokenClient bonusProgramClient:self.bonusProgramClient];

PaymentAndRedemptionClientCoordinator
This coordinator handles payments and redemptions.

Instantiating:

@property (nonatomic, strong, readwrite) PaymentAndRedemptionClientCoordinator *paymentAndRedemptionClientCoordinator;

self.paymentAndRedemptionClientCoordinator = [[PaymentAndRedemptionClientCoordinator alloc] initWithPaymentClient:self.paymentClient bonusRedemptionClient:self.bonusRedemptionClient goldRedemptionClient:self.goldRedemptionClient couponRedemptionClient:self.couponRedemptionClient walletClient:self.walletClient networkReachability:self.networkReachability bonusProgramClient:self.bonusProgramClient identityClient:self.identityClient];
[self.paymentAndRedemptionClientCoordinator start];

Usage of BonusProgramClient
This client is handling bonus program related stuff: participate to some bonus program, get list of all bonus programs, get list of participating bonus program, update bonus program membership and etc...

Instantiating BonusProgramClient:

@property (nonatomic, strong, readwrite) BonusProgramClient *bonusProgramClient;

self.bonusProgramClient = [BonusProgramClient bonusProgramClientWithIdentityClient:self.identityClient cache:self.cache];

To get all bonus programs use property allBonusProgramsVehicle on BonusProgramClient:

@property (nonatomic, readonly) BonusProgramsVehicle *allBonusProgramsVehicle;

To get participating bonus programs use property participatingBonusProgramsVehicle on BonusProgramClient:

@property (nonatomic, readonly) BonusProgramsVehicle *participatingBonusProgramsVehicle;

To fetch fresh bonus programs(ignoring cache) use updateBonusProgramMembershipsWithCompletion method on BonusProgramClient:

- (void)updateBonusProgramMembershipsWithCompletion:(nullable void (^)(void))completion;

To fetch bonus programs if needed(if cache is not fresh) use updateBonusProgramMembershipsIfNeeded method on BonusProgramClient:

- (void)updateBonusProgramMembershipsIfNeeded;

To update bonus program membership with some state use next method on BonusProgramClient:

- (void)updateBonusProgramMembership:(BonusProgramMembership *)bonusProgramMembership withParticipationState:(BonusProgramMembershipState)state completionHandler:(void (^)(BonusProgramMembership *, NSError *))completionHandler;

Handling of backend messages and network status

CustomStatusMessageManager
This manager handles the custom message from the backend.
It parses the data from backend and tells the client to show alerts or some kind of alert or notification in the app which should be shown to the user.

Instantiating:

@property (nonatomic, strong, readwrite) CustomStatusMessageManager *customStatusMessageManager;

self.customStatusMessageManager = [CustomStatusMessageManager new];

NetworkReachability
Handles network status.

Instantiating:

@property (nonatomic, strong, readwrite) NetworkReachability *networkReachability;

self.networkReachability = [NetworkReachability sharedInstance];

RequestProxyClientCoordinator

Instantiating:

@property (nonatomic, strong, readwrite) RequestProxyClientCoordinator *requestProxyClientCoordinator;

self.requestProxyClientCoordinator = [[RequestProxyClientCoordinator alloc] initWithProxyClientConnectors:@[
  (id<ProxyClientConnector>)self.paymentClient.connector,
  (id<ProxyClientConnector>)self.bonusRedemptionClient.connector,
  (id<ProxyClientConnector>)self.goldRedemptionClient.connector,
  (id<ProxyClientConnector>)self.couponRedemptionClient.connector
]];

self.requestProxyClientCoordinator.shouldUseProxyDueToNetworkProblem = ^BOOL {
  return [NetworkReachability sharedInstance].reachabilityStatus != NetworkReachabilityStatusFast;
};
self.identityClient.requestManager.requestProxyClientCoordinator = self.requestProxyClientCoordinator;
[self.requestProxyClientCoordinator configureRequestProxyClient];

Observers

At the end we need to add several observers in order to complete our communication with SDK:

Start Observing Application

#pragma mark - Observe Application

- (void)startObservingApplication
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleApplicationWillEnterForegroundNotification2:) name:ApplicationWillEnterForegroundNotification(2) object:nil];
}

- (void)handleApplicationWillEnterForegroundNotification2:(NSNotification *)notification
{
    [self.touchIDSupport handleApplicationWillEnterForeground];
    [self.walletClient handleApplicationWillEnterForegroundAfterBackgroundTime:[notification.userInfo[ApplicationWillEnterForegroundNotificationDurationInBackgroundKey] doubleValue]];
}

Start Observing Identity Client

#pragma mark - IdentityClient Observation

- (void)startObservingIdentityClient
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleIdentityClientDidInvalidateIdentityNotification:) name:IdentityClientDidInvalidateIdentityNotification object:self.identityClient];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleIdentityClientIdentityDidGetReadyNotification:) name:IdentityClientIdentityDidGetReadyNotification object:nil];
}

- (void)handleIdentityClientDidInvalidateIdentityNotification:(NSNotification *)notification
{
    [self.cache reset:^{
        [self.bonusProgramClient reset];
        [self.goldProgramMembershipsClient reset];
        [self.transactionsClient reset];
        [self.walletClient reset];
        [self.identityVerificationClient reset];
        [self.customStatusMessageManager reset];
        [self.accountDataClient reset];
        [self.dailyTokenClient reset];
    }];
}

- (void)handleIdentityClientIdentityDidGetReadyNotification:(NSNotification *)notification
{
    [self.walletClient handleIdentityClientIdentityDidGetReady];
}

Start Observing Network

- (void)startObservingNetwork
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNetworkMightWorkAgainNotification:) name:NetworkMightWorkAgainNotification object:nil];
}

- (void)handleNetworkMightWorkAgainNotification:(NSNotification *)notification
{
    [self.transactionsClient handleNetworkMightWorkAgain];
    [self.walletClient handleNetworkMightWorkAgain];
    [self.merchantMapClient handleNetworkMightWorkAgain];
    [self.bonusProgramClient handleNetworkMightWorkAgain];
}

Start Observing Payment and Redemption

- (void)startObservingPaymentAndRedemption
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePaymentClientFinishedAPaymentNotification:) name:PaymentClientFinishedAPaymentNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleRedemptionClientFinishedARedemptionNotification:) name:RedemptionClientFinishedARedemptionNotification object:nil];
}

- (void)handlePaymentClientFinishedAPaymentNotification:(NSNotification *)notification
{
    [self.transactionsClient handlePaymentClientFinishedAPayment];
    [self.walletClient handlePaymentClientFinishedAPayment];
}

- (void)handleRedemptionClientFinishedARedemptionNotification:(NSNotification *)notification
{
    [self.walletClient handleRedemptionClientFinishedARedemption];
}

In dealloc just simply stop observing:

- (void)stopObserving
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [self.customStatusMessageManager stopObserving];
    [self.walkthroughPresenter stopObservingNotifications];
}

Did this page help you?