iOS Objective C Documentation

Prerequisites for Integration

  1. Register with Finotes using the 'Get Started' button in https://finotes.com and login to dashboard.
  2. Use "Add App" to link iOS application to Finotes.
  3. Integrate Finotes framework to your application.
  4. Test your integration.

Current Version 4.2.1

Change log


How to Integrate

Step One

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

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

Step Two

Integrating both FinotesCore and FinotesDebug

To leverage the capabilities of both FinotesCore and FinotesDebug,

Podfile:
pod 'FinotesCore', '4.2.1', :configuration => ['Release']
pod 'FinotesDebug', '4.2.1', :configuration => ['Debug']


FinotesDebug framework contains features in FinotesCore and:

1. Ability to track shorter framerate issues.

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>

Initializing Finotes

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];
}

Testing Integration

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

Step One

Add [Fn test]; after [Fn initialize:application];

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


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

    [Fn test];
}

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 the issue is still not synced in Finotes dashboard, Click Here.

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

Now, Finotes is all set to report any memory related issues or crashes (crash reporting will be activated only in release build) if they occur in your application.

Things to take care in Release Build

Once you are ready to release the application, you need to back up the dSYM file to symbolicate the crashes as they are reported. Locating dSYM file.

Data Points Collected

Finotes framework automatically collects multiple data points inorder to help developers get indepth information on the issues reported.
Head over to iOS Data Points page to explore more on the type of data points collected by the framework.

Detect memory leaks

Finotes framework can detect all UIViewController level leaks automatically with just the basic integration.
Incase the basic integration is not complete, head over to How To Integrate section.

With the auto tracking capabilities of Finotes framework, the need to extend UIViewControllers from ObservableViewController is eliminated. We have deprecated the API ObservableViewController and will be removed in a future version.

Deprecated:
@interface LoginViewController : ObservableViewController //Deprecated

@end

Track Network Calls

Finotes is capable of reporting HTTP(s) based network errors automatically with just the basic integration.
Incase the basic integration is not complete, head over to How To Integrate section.

With the auto tracking capabilities of Finotes framework, the need to call the following APIs are eliminated. We have deprecated these APIs and will be removed in a future version.

Deprecated:
[Fn registerDefaultProtocolMonitor]; //deprecated
Deprecated:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration 
                            defaultSessionConfiguration];
[Fn getProtocols:[configuration.protocolClasses mutableCopy] ]; //deprecated

Manually Track Network Calls

Finotes provides explicit API to track network call issues.

Anywhere in code:
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

    [Fn onNetworkCallCompletedWithRequest:request andResponse:(NSHTTPURLResponse *)response andResponseData:data withOptionalErrorMessage:error ? [error localizedDescription] : nil];

}];
[dataTask resume];
                    

Privacy (Optional feature)

As Finotes reports API call issues, each issue is tagged with corresponding request response headers, request body and associated 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:

Let us 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 itself as is not sent to the Finotes dashboard, if any issues are raised.
The maskHeaders field is case insensitive and is optional.

Dynamic Path Component

When API call issues are reported, different urls are created as separate ticket.
This can cause large number of tickets generated for the same API incase the url contains an id or any other dynamic path component.

Info.plist

Use URLPatterns key in info.plist to specify the urls that contains dynamic path component.
Wrap the corresponding dynamic path component or id inside '{}'.

Whitelisting domains

Using the ObservableDomains key in Info.plist file, domains can be whitelisted. Once set only HTTP(s) calls made to the whitelisted domains will be tracked by the Framework.

Info.plist

Setting Domain timeout

Setting domain timeout is an extension of whitelisting domains. Developers can set timeout to whitelisted domains using the ObservableDomains key as comma separated value.

The timeout value should be in milliseconds. Once the value is set if any of the HTTP(s) calls to the domain takes more than the set amount of time, an issue report will be raised.

Info.plist

Crash Reporting

With basic integration, Finotes will track and report uncaught exceptions to Finotes dashboard automatically.
Incase the basic integration is not complete, head over to How To Integrate section.

Block Finotes from Reporting Crashes

In case developers want to prevent Finotes from reporting uncaught exceptions that causes app to force close, add key PreventCrashReporting to the info.plist file.

Info.plist
Deprecated:

Flag PreventCrashes is now deprecated (replaced by PreventCrashReporting) and will be removed in a future version.

Report low memory warnings

With basic integration, Finotes will track and report system level low memory warnings to Finotes dashboard automatically.
Incase the basic integration is not complete, head over to How To Integrate section.

With the auto tracking capabilities of Finotes framework, the need to extend UIViewControllers from ObservableViewController is eliminated. We have deprecated the API ObservableViewController and will be removed in a future version.

Deprecated:
@interface LoginViewController : ObservableViewController //Deprecated

@end

Track screen loading delay

With basic integration, Finotes will track and report screen loading delays to Finotes dashboard automatically.
By default, if a screen takes more than 4 seconds to load then it will be raised as a bug report.
Incase the basic integration is not complete, head over to How To Integrate section.

Developers can set custom time to track screen loading delays using ScreenLoadDelayInSeconds key in the info.plist file. Once set, if any of the app screen takes more than the set amount of time to load, it will be raised as a bug report.

Info.plist

With the auto tracking capabilities of Finotes framework, the need to extend UIViewControllers from ObservableViewController is eliminated. We have deprecated the API ObservableViewController and will be removed in a future version.

Deprecated:
@interface LoginViewController : ObservableViewController //Deprecated

@end

Report Try..Catch Exceptions

Starting from version 4.1.0 all NSExceptions that may have already been caught using @try{}@catch{} are now automatically reported.

API call reportExceptionAt is now deprecated and will be removed in a future version.
Deprecated:
[Fn reportExceptionAt:self withException:exception withSeverity:FATAL]; //Deprecated

Tracking NSErrors

Starting from version 4.1.0 all NSErrors that are generated are now automatically reported with the basic integration.
Incase the basic integration is not complete, head over to How To Integrate section.

Report Custom Issues

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 withShortDescription:@"Payment failed" withDescription:reason];
    
}
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.

Track Function Calls

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 mechanism 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.

Track Feature failures

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.
Let us 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.

Track Frame rate issues

This feature is automatically activated.
An issue report will be sent to the dashboard when a UI thread block is detected by the framework. The issue report will have the stack trace of the main thread to aid developers to pin point the exact line causing the issue.

Set custom frame rate threshold

Developers can set custom frame rate threshold with the API setFrameRateThreshold before [Fn initialize:] API.

AppDelegate Class:
#import <FinotesCore/Fn.h>

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

    [Fn setFrameRateThreshold:2.0];
    [Fn initialize:application];
}

Once a custom threshold value (in seconds) is set and if the UI thread gets blocked for more than the threshold value, a corresponding issue report will be sent to the Finotes dashboard.

Supported threshold values are between 0.016 seconds (16 milliseconds) to 5 seconds (5000 milliseconds) in FinotesDebug (debug flavour) and between 0.25 seconds (250 milliseconds) to 5 seconds (5000 milliseconds) in FinotesCore (release flavour).

Default frame rate threshold is 0.25 seconds (250 milliseconds) in debug flavour and 1 second (1000 milliseconds) in release flavour.

The deprecated API enableFrameRateDetection will be removed in future version of the framework.

Deprecated:
[Fn enableFrameRateDetection];  //deprecated

Setting custom Activity Markers

Activity markers are events that occur in an application during runtime. Finotes framework automatically captures lifecycle events.

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"];


Debug level Activity Markers

You can set debug level custom activity markers in the project using [Fn setActivityMarkerForDebugAt]. These markers will be shown along with the activity trail when an issue is reported in the debug builds of the app.

Call anywhere is you project:
[Fn setActivityMarkerForDebugAt:self marker:@"logout tapped"]

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%

Map user or device

Once the user login is complete, you can set any custom user identifier with finotes, This identifier will be tagged with all issue reports raised in Finotes dashboard.
If this API is invoked multiple times, the latest identifier will be used with each issue report.

Anywhere in code:
[Fn setCustomId:userId];
Deprecated:
[Fn updateUserDataWithUniqueIdentifier:userId]; //deprecated

Setting Location Coordinates

Finotes do not access user location data automatically. Framework provides a single line API that allows developers to update location data manually.
Once this API is called, every issue reported by Finotes will have location data tagged.

Anywhere in code:
[Fn updateLocation:clLocationCoordinates];

Issue callback listener (Optional)

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.

Whitelisting Crash Reports

Developers can whitelist crash reporting by adding WhitelistCrashes key in info.plist file.
Once whitelisted, only exceptions that are listed in info.plist will be reported by Finotes.

Info.plist

Enable Finotes Logs

You can activate internal Finotes logging using log() API.
Activating log() API will print all logs generated by the Framework in LogCat including error and warning logs.

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

    [Fn log];
    [Fn initialize:application];
}