iOS Objective C Documentation

Pre requisites

Finotes framework supports iOS projects with minimum deployment target version 8 or above.

1. Sign Up using the button below.
2. Use "Add App" option in dashboard to link iOS app to Finotes.

Sign Up

Current Version 2.5.5


Integration

Step One

You need to add cocoa pods to your project. You can find more information here

Incase, your development language is swift, use the SWIFT documentation for integration.

Step Two

After integrating cocoa pods, add FinotesCore to your Podfile.

Podfile:
pod 'FinotesCore', '2.5.5'

The –repo-update option should be used the first time pod install is run from terminal.

Then install the same by executing the following command from terminal where your Podfile resides.
Here the —repo-update is added incase your local cocoa pods repository is not up to date.

Terminal:
pod install --repo-update

Step Three

You can import the FinotesCore to your code using the import statement below.

Anywhere in Code:
#import <FinotesCore/Fn.h></FinotesCore>

Initialize

You need to call the [Fn initialize:application] function in your appDelegate didFinishLaunchingWithOptions:

AppDelegate:
#import <FinotesCore/Fn.h>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    [Fn initialize:application];
}

Test

Now that the basic integration of Finotes framework is complete,
Lets make sure that the dashboard and SDK are in sync.

Step One

Add
[Fn reportIssueAt:self withDescription:@"iOS TEST Issue" withSeverity:MINOR];
under
[Fn initialize:application withDryRun:NO withVerbose:YES];

Application Class:
#import <FinotesCore/Fn.h>
#import <FinotesCore/Severity.h>


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    [Fn initialize:application withDryRun:NO withVerbose:YES];
    //[Fn reportIssueAt:] allows you to raise custom issues.
    //Refer Custom Issue section by the end of this documentation for more details.
    [Fn reportIssueAt:self withDescription:@"iOS TEST Issue" withSeverity:MINOR];
}

Step Two

Now run the application in a simulator or real iOS device (with active network connection).

Step Three

Once the application opens up, open Finotes dash.
The test issue that we raised should be reported.

In-case the issue is not listed, make sure the right app and platform is selected at the top of the dashboard.
If issue is still not synced in Finotes dashboard, Click Here.

Remember to remove the [Fn reportIssueAt]; call, else every time the app is run, an issue will be reported.

Release Build

Once you are ready to release the application, if you have activated crash reporting using Finotes, you need to back up the dSYM file to symbolicate the crashes as they are reported. Locating dSYM file.

Activity Markers

Activity markers are events that occur in an application during runtime. Extending UIViewControllers from ObservableViewController helps Finotes track application life cycle events.

UIViewController .h files:
@interface ViewController : UIViewController

@end
Changes to
@interface ViewController : ObservableViewController

@end

You can set custom activity markers in the project using [Fn setActivityMarkerAt]. These markers will be shown along with the activity trail when an issue is reported.

Markers are displayed in their chronological order.
Only when an issue is raised, the activity markers are sent to the server.

Call anywhere is you project:
[Fn setActivityMarkerAt:self marker:@"clicked on payment_package_two"];

How activity trail will look like along with reported issue in Finotes dashboard:
AppDelegate:finishLaunchingOptions                          11:19:24:469	45.79% FREE MEMORY 
ViewController:viewDidLoad                                  11:19:24:708	44.39%
ViewController:viewWillAppear                               11:19:27:012	45.19%
ViewController:viewDidAppear                                11:19:28:515	44.53%
ViewController:clicked on payment_package_two               11:20:24:235	55.20%

Network Calls

Finotes will be able to notify of any errors in API calls with just a single line.

If you are using NSURLSession with sharedSession then issues in all REST api calls will be reported automatically.

Shared Session:
NSURLSession *session = [NSURLSession sharedSession];

AFNetworking

Incase you are using AFNetworking, then you need to add the below code in your NSURLSessionConfiguration. The part we are interested is

AFNetworking:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration 
                        defaultSessionConfiguration];
configuration.protocolClasses = [Fn getProtocols:[configuration.protocolClasses mutableCopy] ];
AFHTTPRequestOperationManager

If you try to use ‘AFHTTPRequestOperationManager’, your app might crash. ‘AFHTTPRequestOperationManager’ is outdated in AFNetworking 3.x, we suggest you migrate to ‘NSURLSessionConfiguration’. You can find out, how to migrate to ‘NSURLSessionConfiguration’ here.

AFNetworking:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration 
                        defaultSessionConfiguration];
configuration.protocolClasses = [Fn getProtocols:[configuration.protocolClasses mutableCopy] ];

Incase, you need more clarity on getting notified of network errors, Please initiate a chat with our development team directly using chat widget at the bottom right corner.
We will help you overcome any roadbloacks that you may have.

Privacy (Optional feature)

As Finotes reports API call issues, each issue is tagged with corresponding request response headers, request body and assosiated parameters.
If header fields contain any sensitive data, Finotes provides a global and easy mechanism to mask such header fields using maskHeaders in info.plist file as shown in code snippet.
You may provide 1 or more header keys in the 'maskHeaders' field.

Info.plist:

Open info.plist as Source Code, then add the below snippet

<key>MaskHeaders</key>
    <array>
    <string>Header-Key</string>
    <string>Another-Header-Key</string>
    </array>
Use case:

Lets say API calls from the app has header field 'X-Key' which contains the authentication token.
It can be masked by providing the 'X-Key' in the field as shown above, masked header fields are filtered out from the app itelf as is not sent to the Finotes dashboard, if any issues are raised.
The maskHeaders field is case insensitive and is optional.

Global Exceptions

In-order to catch uncaught exceptions that causes app to force close, use [Fn catchExceptions].

Application Class below init() line:
#import <FinotesCore/Fn.h>


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    [Fn initialize:application];
    [Fn catchExceptions];
}

Low Memory Reporting

You may extend the UIViewController classes from ObservableViewController. This will report any UIViewController level memory issues that may arise in the application.

UIViewController .m files:
@interface ViewController : UIViewController

@end
Change to
@interface ViewController : ObservableViewController

@end

Caught Exceptions

Any exceptions that may have already been caught using @try{}@catch{} needs to be reported as they might prevent the application from crashing, but at the same time can make app unstable if gone unreported.

Reporting caught exception:
@try{
    [self fetchUserDetails];
}@catch(NSException *exception){
    [Fn reportExceptionAt:self withException:exception 
                        withSeverity:FATAL];
}

Custom Issue

You can report custom issues using the [Fn reportIssueAt:] API.

Any where in the project:
//Payment gateway delegate methods.
-(void) paymentCompleted:(NSString *) userIdentifier forType:(NSInteger) type{

}

-(void) paymentFailed:(NSString *) userIdentifier forReason:(NSString *) reason{
    
    [Fn setActivityMarkerAt:self marker:[NSString stringWithFormat:@"User id %@", userIdentifier]];

    [Fn reportIssueAt:self withDescription:
                [NSString stringWithFormat:@"Payment failed for %@", reason] 
            withSeverity:FATAL];
            
}
Use case:

In cases where the fail situations can be anticipated, they may be reported using [Fn reportIssueAt].
You may pass a string as parameter to the anticipated issue.
As in custom exceptions, you will be able to make use of activity markers to aid reproducing the issue when reported.

Function call

Finotes will report all return value issues, exceptions and execution delays that may arise during function execution using [Fn call].

Regular function call:

    [self getUserNameFromDb:@"123-sd-12"]
}

-(NSString *) getUserNameFromDb:(NSString *) userId {
    NSString *userName = [[User findById:userId] name];
    return userName;
}
Function call via Finotes:
#import <FinotesCore/Observer.h>
#import <FinotesCore/Fn.h>


    [Fn call:@selector(getUserNameFromDb:) target:self withParameters:@"123-sd-12"];
}

-(NSString *) getUserNameFromDb:(NSString *) userId {
    NSString *userName = [[User findById:userId] name];
    return userName;
}

Notes:
1. You replace the old method of function invocation to the Finotes based mecahnism for main functions in your iOS project.
2. Finotes will report an issue, if the said function returns a NULL value or takes more than 1000 milliseconds for its execution or throws any exceptions even if caught using try{}catch{} block over the function call.
3. The function execution is seamless like the original method of invocation.
4. Near zero overhead in using Finotes based function invocation.
5. The function parameters that were passed to it during its invocation will be shown along with the issue in Finotes dashboard if any raised.


Observe fields


You can make use of expectedExecutionTime, severity, expectNull fields in Observer parameter of

[Fn call: target: observer:observer withParameters: ];

to control the issue reports from a function.

expectedExecutionTime

Incase, we have a function that may take more than 1000 milliseconds(default value) for execution then use this field in Observer to provide an ideal execution time.
Supplying proper values in Observer parameter will help Finotes raise better issue reports.

Observer parameter:
#import <FinotesCore/Observer.h>
#import <FinotesCore/Fn.h>



    Observer *observer =  [[Fn observe] expectedExecutionTime:1400];
    NSString *userName = [Fn call:@selector(getUserNameFromDb:) target:self 
                        observer:observer withParameters:@"123-sd-12"];
}

-(NSString *) getUserNameFromDb:(NSString *) userId {
    NSString *userName = [[User findById:userId] name];
    return userName;
}

expectNull

If function returns an object and return value could be NULL, then set this field to true to prevent Finotes from raising an issue when function returns NULL.
By default field is false, and issue will be raised if function returns NULL.

severity

Sets severity level of issues reported from a function using this field.
All issues raised from a function will have the same severity level, set to it using Observer parameter.
By default severity is MAJOR.

Feature Tracking

Finotes has the ability to invoke code level functions and report any issues that may arise from it.

Feature tracking allows developers to track a particular feature in iOS app by chaining 2 or more functions invoked by Finotes.
Lets take the example of Chat feature in a typical iOS application.
The function at the time of clicking the send button 'sendChat' and 'onChatSent' success function after the items as been added to the cart needs to be invoked using Finotes.
The Finotes looks for 'onChatSent' function execution after the execution of 'sendChat', if the 'onChatSent' is not executed within in 10000 milliseconds then a corresponding issue will be raised.

Chat:
#import <FinotesCore/Observer.h>
#import <FinotesCore/Fn.h>


    - (void) sendChatClicked:(UITapGestureRecognizer *)recognizer {

        // Here function 'onChatSent:' is 
        // expected to be called in under '10000' milliseconds.
        Observer *observer =  [[[Fn observe] expectedChainedExecutionTime:10000]  
                nextFunctionSignature:
                    @selector(onChatSent:) 
                inClass:[self class]];
        [Fn call:@selector(sendChat:) target:self observer:observer withParameters:chatMessage];
    }

    - (Boolean) sendChat:(NSString *) message {
        if([self isValid:message]){
            [self syncMessage:message];
        }
        return false;
    }

    - (void) onChatSent:(NSString *)chatMessageId {
        [self chatSyncConfirmed:chatMessageId];
    }

Notes:
1. Here both functions 'sendChat' and 'onChatSent' are invoked using Finotes.
2. Using 'nextFunctionSignature' and 'inClass' fields in Observer parameter the functions are chained.
3. Here 'nextFunctionSignature' is the signature of the second function and 'inClass' is the class where the second function is defined.
4. 'expectedChainedExecutionTime' in first function 'sendChat' overrides time needed to execute second function after execution of first function.


Observer fields


You can make use of nextFunctionSignature, inClass, expectedChainedExecutionTime fields in Observer parameter to chain 2 or more functions.

expectedExecutionTime

Overrides time needed to execute second function after execution of first function.
By default the time between function executions is set to 2000 milliseconds.

nextFunctionSignature

Signature of the second function that is to be chained with the current function.

inClass

Class where second function is defined that is to be chained with the current function.

Listen for Issue

You can listen for and access every issue in realtime using the Fn.listenForIssue() API.
You need to add the listener in your AppDelegate class.

AppDelegate
   [Fn listenForIssues:@selector(issueFound:) atTarget:self];
}

(void) issueFound:(Issue *) issue {

}

You will be provided with an Issue object that contains all the issue properties that are being synced to the server, making the whole process transparent.
This callback is triggered right after an issue occurrence.

DryRun

During development, you can set the dryRun mode, so that the issues raised will not be sent to the server. Every other feature except the issue sync to server will work as same.

AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [Fn initialize:application withDryRun:YES withVerbose:NO];
}

When preparing for production release, you need to unset the DryRun flag.

VerboseLog

You can toggle logging using third parameter.
Activating verbose will print all logs in LogCat including error and warning logs.

Application Class:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [Fn initialize:application withDryRun:NO withVerbose:YES];
}