-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
672 additions
and
88 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
## Introduction | ||
|
||
The TestFlight SDK allows you to track how beta testers are testing your application. Out of the box we track simple usage information, such as which tester is using your application, their device model/OS, how long they used the application, and automatic recording of any crashes they encounter. | ||
|
||
The SDK can track more information if you pass it to TestFlight. The Checkpoint API is used to help you track exactly how your testers are using your application. Curious about which users passed level 5 in your game, or posted their high score to Twitter, or found that obscure feature? See "Checkpoint API" down below to see how. | ||
|
||
The SDK also offers a remote logging solution. Find out more about our logging system in the "Remote Logging" section. | ||
|
||
|
||
## Requirements | ||
|
||
The TestFlight SDK requires iOS 4.3 or above, the Apple LLVM compiler, and the libz library to run. | ||
|
||
## Integration | ||
|
||
1. Add the files to your project: File -> Add Files to " " | ||
1. Find and select the folder that contains the SDK | ||
2. Make sure that "Copy items into destination folder (if needed)" is checked | ||
3. Set Folders to "Create groups for any added folders" | ||
4. Select all targets that you want to add the SDK to | ||
|
||
2. Verify that libTestFlight.a has been added to the Link Binary With Libraries Build Phase for the targets you want to use the SDK with | ||
1. Select your Project in the Project Navigator | ||
2. Select the target you want to enable the SDK for | ||
3. Select the Build Phases tab | ||
4. Open the Link Binary With Libraries Phase | ||
5. If libTestFlight.a is not listed, drag and drop the library from your Project Navigator to the Link Binary With Libraries area | ||
6. Repeat Steps 2 - 5 until all targets you want to use the SDK with have the SDK linked | ||
|
||
3. Add libz to your Link Binary With Libraries Build Phase | ||
1. Select your Project in the Project Navigator | ||
2. Select the target you want to enable the SDK for | ||
3. Select the Build Phases tab | ||
4. Open the Link Binary With Libraries Phase | ||
5. Click the + to add a new library | ||
6. Find libz.dylib in the list and add it | ||
7. Repeat Steps 2 - 6 until all targets you want to use the SDK with have libz.dylib | ||
|
||
4. Get your App Token | ||
|
||
1. If this is a new application, and you have not uploaded it to TestFlight before, first register it here: [https://testflightapp.com/dashboard/applications/create/](https://testflightapp.com/dashboard/applications/create/). | ||
|
||
Otherwise, if you have previously uploaded your app to TestFlight, go to your list of applications ([http://testflightapp.com/dashboard/applications/](http://testflightapp.com/dashboard/applications/)) and click on the application you are using from the list. | ||
|
||
2. Click on the "App Token" tab on the left. The App Token for that application will be there. | ||
|
||
5. In your Application Delegate: | ||
|
||
1. Import TestFlight: `#import "TestFlight.h"` | ||
|
||
2. Launch TestFlight with your App Token | ||
|
||
In your `-application:didFinishLaunchingWithOptions:` method, call `+[TestFlight takeOff:]` with your App Token. | ||
|
||
-(BOOL)application:(UIApplication *)application | ||
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { | ||
// start of your application:didFinishLaunchingWithOptions | ||
|
||
[TestFlight takeOff:@"Insert your Application Token here"]; | ||
|
||
// The rest of your application:didFinishLaunchingWithOptions method | ||
// ... | ||
} | ||
|
||
3. To report crashes to you we install our own uncaught exception handler. If you are not currently using an exception handler of your own then all you need to do is go to the next step. If you currently use an Exception Handler, or you use another framework that does please go to the section on advanced exception handling. | ||
|
||
|
||
## Uploading your build | ||
|
||
After you have integrated the SDK into your application you need to upload your build to TestFlight. You can upload your build on our [website](https://testflightapp.com/dashboard/builds/add/), using our [desktop app](https://testflightapp.com/desktop/), or by using our [upload API](https://testflightapp.com/api/doc/). | ||
|
||
|
||
## Basic Features | ||
|
||
### Session Information | ||
|
||
View information about how often users use your app, how long they use it for, and when they use it. You can see what type of device the user is using, which OS, which language, etc. | ||
|
||
Sessions automatically start at when the app becomes active and end when the app resigns active. Sessions that start shortly after an end continue the session instead of starting a new one. | ||
|
||
NB: Sessions do not start when `takeOff:` is called, `takeOff:` registers callbacks to start sessions when the app is active. | ||
|
||
For **beta** users, you can see who the users are if they have a TestFlight account and their device is registered with TestFlight. | ||
|
||
|
||
### Crash Reports | ||
|
||
The TestFlight SDK automatically reports all crashes (beta and prod) to TestFlight's website where you can view them. Crash reports are sent **at** crash time. TestFlight will also automatically symbolicate all crashes (if you have uploaded your dSYM). For **beta** apps, on the site, you can see which checkpoints the user passed before the crash and see remote logs that were sent before the crash. | ||
|
||
|
||
### Beta In App Updates | ||
|
||
If a user is using a **beta** version of your app and that user has permission to install it; an in app popup will ask them if they would like to install the update. If they tap "Install", the new version is installed from inside the app. | ||
|
||
NB: For this to work, you must increment your build version before uploading. Otherwise the new and old builds will have the same version number and we won't know if the user needs to update or is already using the new version. | ||
|
||
To turn this off set this option before calling `takeOff:` | ||
|
||
[TestFlight setOptions:@{ TFOptionDisableInAppUpdates : @YES }]; | ||
|
||
|
||
## Additional Features | ||
|
||
### Checkpoints | ||
|
||
When a tester does something you care about in your app, you can pass a checkpoint. For example completing a level, adding a todo item, etc. The checkpoint progress is used to provide insight into how your testers are testing your apps. The passed checkpoints are also attached to crashes, which can help when creating steps to replicate. Checkpoints are visible for all beta builds. | ||
|
||
[TestFlight passCheckpoint:@"CHECKPOINT_NAME"]; | ||
|
||
Use `passCheckpoint:` to track when a user performs certain tasks in your application. This can be useful for making sure testers are hitting all parts of your application, as well as tracking which testers are being thorough. | ||
|
||
Checkpoints are meant to tell you if a user visited a place in your app or completed a task. They should not be used for debugging purposes. Instead, use Remote Logging for debugging information (more information below). | ||
|
||
NB: Checkpoints are only recorded during BETA sessions. | ||
|
||
|
||
### Custom Environment Information | ||
|
||
In **beta** builds, if you want to see some extra information about your user, you can add some custom environment information. You must add this information before the session starts (a session starts at `takeOff:`) to see it on TestFlight's website. NB: You can only see this information for **beta** users. | ||
|
||
[TestFlight addCustomEnvironmentInformation:@"info" forKey:@"key"]; | ||
|
||
You may call this method as many times as you would like to add more information. | ||
|
||
|
||
### User Feedback | ||
|
||
In **beta** builds, if you collect feedback from your users, you may pass it back to TestFlight which will associate it with the user's current session. | ||
|
||
[TestFlight submitFeedback:feedback]; | ||
|
||
Once users have submitted feedback from inside of the application you can view it in the feedback area of your build page. | ||
|
||
|
||
### Remote Logging | ||
|
||
Remote Logging allows you to see the logs your app prints out remotely, on TestFlight's website. You can see logs for **beta sessions**. | ||
|
||
To use it, simply replace all of your `NSLog` calls with `TFLog` calls. An easy way to do this without rewriting all your `NSLog` calls is to add the following macro to your `.pch` file. | ||
|
||
#import "TestFlight.h" | ||
#define NSLog TFLog | ||
|
||
Not only will `TFLog` log remotely to TestFlight, it will also log to the console (viewable in a device's logs) and STDERR (shown while debugging) just like NSLog does, providing a complete replacement. | ||
|
||
For even better information in your remote logs, such as file name and line number, you can use this macro instead: | ||
|
||
#define NSLog(__FORMAT__, ...) TFLog((@"%s [Line %d] " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__) | ||
|
||
Which will produce output that looks like | ||
|
||
-[MyAppDelegate application:didFinishLaunchingWithOptions:] [Line 45] Launched! | ||
|
||
NB: Logs are only recorded during sessions. | ||
|
||
**Custom Logging** | ||
|
||
If you have your own custom logging, call `TFLog` from your custom logging function. If you do not need `TFLog` to log to the console or STDERR because you handle those yourself, you can turn them off with these calls: | ||
|
||
[TestFlight setOptions:@{ TFOptionLogToConsole : @NO }]; | ||
[TestFlight setOptions:@{ TFOptionLogToSTDERR : @NO }]; | ||
|
||
|
||
## Advanced Notes | ||
|
||
### Checkpoint API | ||
|
||
When passing a checkpoint, TestFlight logs the checkpoint synchronously (See Remote Logging for more information). If your app has very high performance needs, you can turn the logging off with the `TFOptionLogOnCheckpoint` option. | ||
|
||
|
||
### Remote Logging | ||
|
||
All logging is done synchronously. Every time the SDK logs, it must write data to a file. This is to ensure log integrity at crash time. Without this, we could not trust logs at crash time. If you have a high performance app, please email [email protected] for more options. | ||
|
||
|
||
### Advanced Session Control | ||
|
||
Continuing sessions: You can adjust the amount of time a user can leave the app for and still continue the same session when they come back by changing the `TFOptionSessionKeepAliveTimeout` option. Change it to 0 to turn the feature off. | ||
|
||
Manual Session Control: If your app is a music player that continues to play music in the background, a navigation app that continues to function in the background, or any app where a user is considered to be "using" the app even while the app is not active you should use Manual Session Control. Please only use manual session control if you know exactly what you are doing. There are many pitfalls which can result in bad session duration and counts. See `TestFlight+ManualSessions.h` for more information and instructions. | ||
|
||
|
||
### Advanced Exception/Signal Handling | ||
|
||
An uncaught exception means that your application is in an unknown state and there is not much that you can do but try and exit gracefully. Our SDK does its best to get the data we collect in this situation to you while it is crashing, but it is designed in such a way that the important act of saving the data occurs in as safe way a way as possible before trying to send anything. If you do use uncaught exception or signal handlers, install your handlers before calling `takeOff:`. Our SDK will then call your handler while ours is running. For example: | ||
|
||
/* | ||
My Apps Custom uncaught exception catcher, we do special stuff here, and TestFlight takes care of the rest | ||
*/ | ||
void HandleExceptions(NSException *exception) { | ||
NSLog(@"This is where we save the application data during a exception"); | ||
// Save application data on crash | ||
} | ||
/* | ||
My Apps Custom signal catcher, we do special stuff here, and TestFlight takes care of the rest | ||
*/ | ||
void SignalHandler(int sig) { | ||
NSLog(@"This is where we save the application data during a signal"); | ||
// Save application data on crash | ||
} | ||
|
||
-(BOOL)application:(UIApplication *)application | ||
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { | ||
// installs HandleExceptions as the Uncaught Exception Handler | ||
NSSetUncaughtExceptionHandler(&HandleExceptions); | ||
// create the signal action structure | ||
struct sigaction newSignalAction; | ||
// initialize the signal action structure | ||
memset(&newSignalAction, 0, sizeof(newSignalAction)); | ||
// set SignalHandler as the handler in the signal action structure | ||
newSignalAction.sa_handler = &SignalHandler; | ||
// set SignalHandler as the handlers for SIGABRT, SIGILL and SIGBUS | ||
sigaction(SIGABRT, &newSignalAction, NULL); | ||
sigaction(SIGILL, &newSignalAction, NULL); | ||
sigaction(SIGBUS, &newSignalAction, NULL); | ||
// Call takeOff after install your own unhandled exception and signal handlers | ||
[TestFlight takeOff:@"Insert your Application Token here"]; | ||
// continue with your application initialization | ||
} | ||
|
||
You do not need to add the above code if your application does not use exception handling already. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// | ||
// TestFlight+AsyncLogging.h | ||
// libTestFlight | ||
// | ||
// Created by Jason Gregori on 2/12/13. | ||
// Copyright (c) 2013 TestFlight. All rights reserved. | ||
// | ||
|
||
/* | ||
When logging, it is important that logs are written synchronously. In the event of a crash, all logs that happened before the crash are gauranteed to be on disk. If they were written asynchronously and a crash occurs, you might lose some very valuable logs that might have helped fixed the crash. | ||
However, because TFLog waits until writing to disk is complete, it takes a while. If you have a very high preformance app that can't afford to wait for logs, these functions are for you. | ||
USE THESE, BUT KNOW YOU RISK LOSING SOME LOGS AT CRASH TIME | ||
*/ | ||
|
||
#import "TestFlight.h" | ||
|
||
|
||
|
||
#if __cplusplus | ||
extern "C" { | ||
#endif | ||
void TFLog_async(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); | ||
void TFLogv_async(NSString *format, va_list arg_list); | ||
#if __cplusplus | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// | ||
// TestFlight+ManualSessions.h | ||
// libTestFlight | ||
// | ||
// Created by Jason Gregori on 5/16/13. | ||
// Copyright (c) 2013 TestFlight. All rights reserved. | ||
// | ||
|
||
/* | ||
YOU ARE STRONGLY ADVISED NOT TO USE THESE METHODS unless you know exactly what you are doing. By using these you take on the responsibility of ensuring your session data is reported accurately. | ||
The way TestFlight normally does sessions is to automatically start them at app launch, app did become active, and app will enter foreground and end them at app will resign active, app did enter background, or app will terminate. | ||
If your app is a music player that continues to play music in the background, a navigation app that continues to function in the background, or any app where a user is considered to be "using" the app even while the app is not active, this file is for you. | ||
Usage | ||
----- | ||
1. Add this file to your project. | ||
2. Set the manual sessions option to true **before** calling `takeOff:` | ||
[TestFlight setOptions:@{ TFOptionManualSessions : @YES }]; | ||
3. Use the manually start/end session methods to control you sessions. | ||
Pitfalls | ||
-------- | ||
When using manual sessions in the background, you must always be aware of the fact that iOS may suspend your app at any time without any warning. You must end your session before that happens. If you do not, the session will continue and include all the time the app was suspended in it's duration if the app is brought back from suspension. This will lead to very inaccurate session lengths and counts. | ||
On app termination: For the most accurate sessions, try to end your session if you know the app is about to terminate. If you do not, the session will still be ended on the next launch, however, it's end time will not be exact. In that case, the end time will be within 30 seconds of the correct time (session information is saved every 30 seconds and when a checkpoint is sent). | ||
Sessions do not continue across termination if you do not end a session before termination. | ||
On crashes: Do not worry about ending sessions in the event of a crash. Even manual sessions are automatically ended in the event of a crash. | ||
Continuing sessions: If a session is started without 30 seconds of the last session ending (and their was no termination between the sessions), the last session will continue instead of a new session starting. This is the case in manual and automatic sessions. You may change the timeout or turn this feature off using the `TFOptionSessionKeepAliveTimeout` option. | ||
*/ | ||
|
||
#import "TestFlight.h" | ||
|
||
|
||
|
||
extern NSString *const TFOptionManualSessions; // Defaults to @NO. Set to @YES before calling `takeOff:` in order to use manual session methods. | ||
|
||
|
||
@interface TestFlight (ManualSessions) | ||
|
||
// these methods are thread safe | ||
+ (void)manuallyStartSession; | ||
+ (void)manuallyEndSession; | ||
|
||
@end |
Oops, something went wrong.