Get Started With Engine

This document will walk you through a brief example of an Engine-enabled Hello World app.

Create a New Project

  1. First things first, make sure you have the latest version of Xcode and launch it. At the time of this writing, the latest is Version 8.2.1 (8C1002).
  2. Create a new project. Choose the template Single View Application under iOS and hit next.

  • Name your project “EngineTest”, accept all of the other defaults, and hit next.
  • Choose a convenient place to put the new project and hit create.

Add Engine Libraries to your App

  1. Follow our installation docs until (but not including) Initializing Engine section, and then come back here.

Import Engine

  1. Open AppDelegate.h
  2. Underneath the existing import for #import <UIKit/UIKit.h>, add the import for Engine:
#import <UIKit/UIKit.h>
#import "FactualEngine.h"

Initialize Engine

  1. Open AppDelegate.m
  2. In didFinishLaunchingWithOptions, you are going to initialize Engine:
- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    [[FactualEngine sharedEngine]
      startWithApiKey:@"Your API key goes here!"
      acceptedTosDate:[NSDate date]];

    return YES;


  • You’ll need to enter the API key from the garage into startWithApiKey.
  • You can put an arbitrary URL into acceptedTosUrl for now, but ultimately this should be a URL pointing to the text of the terms of service that your users are accepting for your app.

Implement a Circumstance Delegate

  1. Open AppDelegate.h again.
  2. Modify the @interface line as follows
@interface AppDelegate : UIResponder <UIApplicationDelegate,
  1. Return to AppDelegate.m, and add the following methods:
// ------ these belong to FactualCircumstanceDelegate ------
// a circumstance was met.
- (void)factualCircumstanceDidOccur:
  (FactualCircumstance *)circumstance {
    [self sayHello:circumstance.identifier];

// something went wrong
- (void)factualCircumstance:
  (FactualCircumstance *)circumstance
    didFailWithError:(NSError *)error {
  NSLog(@"error in circumstance: %@", error);

// some data was generated for debugging purposes.
- (void)factualCircumstance:
  (FactualCircumstance *)circumstance
    didReportDebugInfo:(id)debugInfo {
  NSLog(@"debugInfo: %@", debugInfo);
// ---------------------------------------------------------

// ------ these are here to make our do something ----------
// run an on-demand check
- (void)checkCircumstance {
  NSError *anyError;
  [[FactualEngine sharedEngine]
   evaluateCircumstanceWithId:@"myOnDemand" error:&anyError];

// hello (this is not part of the delegate- it's just a way
// to display that a circumstance was met).
- (void)sayHello:(NSString *)circumstanceId {

  UIAlertController *alert =
                       message:@"circumstance met."

  UIAlertAction *ok =
              handler:^(UIAlertAction * _Nonnull action) {}];

  [alert addAction:ok];

  UIViewController *vc = self.window.rootViewController;
  [vc presentViewController:alert
                   animated:YES completion:nil];
// ---------------------------------------------------------

Create a Circumstance

There is documentation on creating circumstances here. In this case, we’re creating a circumstance that triggers when the user has arrived at an office supply store and a second circumstance against coffee shops, that can be tested when a button is pressed.

  1. In AppDelegate.m, you are going to modify the didFinishLaunchingWithOptions method as follows:
- (BOOL)application:(UIApplication *)application
  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // a primitive little button
    UIButton *button =
      [UIButton buttonWithType:UIButtonTypeCustom];

    [button addTarget:self

    [button setTitle:@"Evaluate Circumstance"

    button.frame = CGRectMake(20.0, 50.0, 300.0, 40.0);
    button.backgroundColor = [UIColor redColor];

    [self.window.rootViewController.view addSubview:button];

    // Initialize Engine
    [[FactualEngine sharedEngine]
      acceptedTosDate:[NSDate date]];

    // ----- notifier model
    // Start background detection to determine when
    // I've arrived at an office supply store.
    [[FactualEngine sharedEngine]
                              expr:@"(at (= category-id 444)))"

    // ----- on-demand model
    // We're going to evaluate this one (same circumstance)
    // on on a button press. It's testing to see if I'm in
    // category 342 (Cafes, Coffee and Tea Houses).
    [[FactualEngine sharedEngine]
                              expr:@"(at (= category-id 342)))"

    return YES;

Note: if you need a really trivial test just to make sure your button is active, you can change “(at (= category-id 342)))” to “(at any-factual-place)”.

Set Location Permission Messaging

You are done coding at this point. Next you need to set some location permissions for your app.

  1. From the Project Navigator in Xcode, open info.plist.
  2. If you hover over Information Property List, you’ll see a small plus symbol (+) in a circle. Click it.
  3. In the resulting pick list menu, scroll down and click on the item “Privacy - Location Usage Description”
  4. After it is added, double click on the corresponding Value entry and enter “My Application needs your location to provide helpful services.” You can enter your own text here if you desire. This is the text that will appear in the permission dialog when users are prompted for access to location by your app.
  5. Repeat, adding the parameter “Privacy - Location When In Use Usage Description”
  6. Repeat again, adding the parameter “Privacy - Location Always Usage Description”

Launch Your App

  1. Pick an simulator target and the click run (the play button).

Your app should launch. That’s it!

This app will detect the circumstance of arriving at an office supply store (passively) or of being at a coffee shop (on-demand, by hitting the red button). You can obviously plug in alternative rules and lat/lngs into the simulator to explore a bit. To plug in alternate lat/lngs, go to Debug -> Location -> Custom Location in the simulator. Note that, if the circumstances you’ve defined have not been met, there will be no output from the app.

In case you need them, here are fully generated versions of the AppDelegate: