iOS SDK

The U Grok It SDK for iOS enables easy integration of RFID functionality into an iOS app. Here are the basics of using the SDK. The SDK requires iOS 8.0 or above (and has been tested up to iOS 12.0.1) and supports both Objective-C and Swift. The SDK works with XCode 10.0.0 (and has worked with previous versions of XCode going back several years, but we do not test compatibility with previous version of XCode.

Downloading and Installation

The SDK is distributed as a ZIP file and includes:

  • include (folder)
    Contains the four header files that define the API, including UgiSwiftBridgingHeader.h for use from Swift
  • libUGrokItApi.a
    Static library file containing the U Grok It functionality. Your project will link with this
  • ApiDemo (folder)
    Contains the ApiDemo sample application that demonstrates use of the API from Objective-C.
  • SwiftApiDemo (folder)
    Contains the SwiftApiDemo sample application that demonstrates use of the API from Swift.
  • ugrokitSdk.xcworkspace
    XCode workspace for building and running the ApiDemo application
  • html (folder)
    The HTML documentation
Download the SDKs
iOS, Android, Cordova, Xamarin
Get Discover Grok from the AppStore
The ApiDemo and SwiftApiDemo sample apps

The sample apps demonstrates use of the API. Opening the ugrokitSdk workspace file opens a workspace containing both sample apps. These can be runn either the iOS simulator or an iOS device.

Integrating the API into an XCode project
Including the library and resource bundle

To integrate the U Grok It API into your app, drag the library file (libUGrokItApi.a) from a Finder window into your project in XCode.

Then click Finish at the dialog box. You can click the checkbox to copy the library file into the project's folder or not, either way works. This library file works both in the iOS simulator and on iOS devices.

Drag the include/ folder from a Finder window into your project in XCode

Drag UgrokItResources.bundle from a Finder window into your project in XCode

Project settings

The application must link with the following libraries. This is set in XCode by clicking on the application in the Project Navigator (on the left), then clicking on the application name under TARGET, then "Build Phases", then "Link Binary with Libraries" and clicking the "+"

  • libz.tbd

In Build Settings, set Other Linker Flags to -ObjC


In Build Settings, set Library Search Paths to $(SRCROOT)/..


Project settings: Swift

For Swift, you must also set Objective-C Bridging Header to UgiSwiftBridgingHeader.h inside the include/ folder


Permissions

For either Objective-C or Swift, edit Info.plist and add a "Privacy - Microphone Usage Description" entry. This is the message iOS will show the user to request permission to use the microphone.

The Ugi singleton object and housekeeping chores
Objective-C

The API is accessed through the Ugi singleton object (Ugi is short for U Grok It). Import Ugi.h:

  #import "Ugi.h"

The singleton object should be explicitly created with the createSingleton. This is usually done in your application's main.c file (which XCode puts in the "Supporting Files" folder):

int main(int argc, char * argv[]) {
  @autoreleasepool {
    [Ugi createSingleton];   // ADD THIS LINE
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}
The singleton object is normally released in applicationWillTerminate:

  [Ugi releaseSingleton];
Swift

The API is accessed through the Ugi singleton object (Ugi is short for U Grok It).

The singleton object should be explicitly created with the createSingleton. This is usually done in your AppDelegate's init method:

  override init() {
    Ugi.createSingleton()
    Ugi.singleton().openConnection()
  }
The singleton object is normally released in applicationWillTerminate

  func applicationWillTerminate(application: UIApplication) {
    Ugi.singleton().closeConnection()
  }
Housekeeping

A production level app needs to do a few housekeeping functions:

  • Region Setting
    A new Grokker must be configured for the region of the world that it will operate in.
  • Firmware Update
    From time to time, we will release firmware updates for the Grokker.

Calling [Ugi createSingleton] as shown above will use standard UI built into the SDK for these functions.

If you want to customize this UI or if you want to be more restrictive about how and when firmware updates are done, you can pass your own configuration delegate object to createSingletonWithConfigurationDelegate: instead of calling createSingleton:

Opening and Closing a connection to the grokker

Communication with the grokker is done via the audio port. For an application that uses U Grok It functionality all the time, this is done in the application delegate's init and applicationWillTerminate methods. For an application that only uses U Grok It occasionally, the connection can be opened and closed at the appropriate points.

Objective-C
    [[Ugi singleton] openConnection];
    [[Ugi singleton] closeConnection];
Swift
    Ugi.singleton().openConnection()
    Ugi.singleton().closeConnection()

openConnection returns immediately, it does not wait for a connection to the grokker to actually be established. If a grokker is connected, the connection takes 400-500ms (just under half a second) for the connection sequence. Your app can get notification of connection state changes by calling addConnectionStateListener in the Ugi singleton object. Usually a state changed method is not needed, using the Inventory methods described below takes care of this.

Inventory

Finding RFID tags is accomplished by running inventory. Once inventory is started, the grokker continually looks for RFID tags and reports them back to the iOS device.

Starting inventory returns a UgiInventory object that holds the results of the inventory. The application can either save the UgiInventory object or can use [Ugi singleton].activeInventory to get to it.

UgiInventory does some useful aggregation of the raw data from the grokker and reports back to your application via an InventoryDelegate object. Inventory can be run either with a configuration built from one of the pre-defined inventory types or with a custom UgiRfidConfiguration object.

The application can tell the grokker to report all RFID tags it finds:

Objective-C
  UgiInventory *inventory = [[Ugi singleton] startInventory:self    // delegate object
                                          withConfiguration:[UgiRfidConfiguration
                        configWithInventoryType:UGI_INVENTORY_TYPE_LOCATE_DISTANCE]];
Swift
  let inventory = Ugi.singleton().startInventory(
    self,
    withConfiguration: UgiRfidConfiguration.configWithInventoryType(UgiInventoryTypes.UGI_INVENTORY_TYPE_LOCATE_DISTANCE))

Or the application can pass a specific tag to find:

Objective-C
  UgiEpc *epc = [UgiEpc epcFromString:@"35fffffff99c70a063405c48"];
  UgiInventory *inventory = [[Ugi singleton] startInventory:self    // delegate object
                                          withConfiguration:[UgiRfidConfiguration
                        configWithInventoryType:UGI_INVENTORY_TYPE_LOCATE_DISTANCE]
                                                    withEpc:epc];       // EPC to find
Swift
  let epc = UgiEpc(fromString: "35fffffff99c70a063405c48")
  let inventory = Ugi.singleton().startInventory(
    self,
    withConfiguration: UgiRfidConfiguration.configWithInventoryType(UgiInventoryTypes.UGI_INVENTORY_TYPE_LOCATE_DISTANCE),
    withEpc: epc)

Or the application can pass an array of tags to find:

Objective-C
  UgiEpc *epc1 = [UgiEpc epcFromString:@"35fffffff99c70a063405c48"];
  UgiEpc *epc2 = [UgiEpc epcFromString:@"35fffffff956734504747454"];
  UgiInventory *inventory = [[Ugi singleton] startInventory:self    // delegate object
                                          withConfiguration:[UgiRfidConfiguration
                        configWithInventoryType:UGI_INVENTORY_TYPE_LOCATE_DISTANCE]
                                       withEpcs:[NSArray arrayWithObjects:epc1, epc2, nil]];
Swift
  let epc1 = UgiEpc(fromString: "35fffffff99c70a063405c48")
  let epc2 = UgiEpc(fromString: "35fffffff956734504747454")
  let inventory = Ugi.singleton().startInventory(
    self,
    withConfiguration: UgiRfidConfiguration.configWithInventoryType(UgiInventoryTypes.UGI_INVENTORY_TYPE_LOCATE_DISTANCE),
    withEpcs: [epc1, epc2])

Inventory runs until the application stops it.

Objective-C
  [[Ugi singleton].activeInventory stopInventoryWithCompletion:^{
    // Code to run when inventory is stopped
  }];
Swift
  Ugi.singleton().activeInventory.stopInventoryWithCompletion {
    // Code to run when inventory is stopped
  }
Inventory Delegate methods

The inventory code reports back to the application via the inventory delegate object. All methods in the inventory delete are optional - the delegate just implements what it needs. The delegate object must implement the UgiInventoryDelegate protocol:

Objective-C
@interface ViewController : UIViewController<UgiInventoryDelegate>
Swift
class ViewController: UgiInventoryDelegate {

Only a subset of the inventory delegate methods are discussed here.

New tag found

When a new tag is found, the delegate is notified via inventoryTagFound (the detailedPerReadData is nil unless the Grokker was told to return detailed per-read data).

Objective-C
- (void) inventoryTagFound:(UgiTag *)tag
   withDetailedPerReadData:(NSArray *)detailedPerReadData {
  // tag was found for the first time
}
Swift
func inventoryTagFound(tag: UgiTag!,
                       withDetailedPerReadData detailedPerReadData: [UgiDetailedPerReadData]?) {
  // tag was found for the first time
}

The UgiTag object contains information about the tag including:

  • Its EPC code
  • The time the tag was first read, the time the tag was most recently read
  • The total number of times this tag has been read
  • A history of how many times this tags has been read in recent time intervals (the default being the number of reads per 500ms going back 10 seconds, but this is configurable)
Subsequent finds of previously found tag

When a tag is found again, the delegate is notified via inventoryTagSubsequentFinds (the detailedPerReadData is nil unless the Grokker was told to return detailed per-read data).

Objective-C
- (void) inventoryTagSubsequentFinds:(UgiTag *)tag numFinds:(int)num
             withDetailedPerReadData:(NSArray *)detailedPerReadData {
  // tag found count more times
}
Swift
func inventoryTagSubsequentFinds(tag: UgiTag!,
                                 numFinds num: Int32,
                                 withDetailedPerReadData detailedPerReadData: [UgiDetailedPerReadData]?) {
  // tag found count more times
}
Tag visibility changed

When a tag is first found, has not been seen for a while (by default 10 seconds, but configurable), or is seen again after not being seen for awhile, the delegate is notified via:

Objective-C
- (void) inventoryTagChanged:(UgiTag *)tag isFirstFind:(BOOL)firstFind {
  if (firstFind) {
    // tag was found for the first time
  } else if (tag.isVisible) {
    // tag was not visible, is now visible again
  } else {
    // tag is no longer visible
  }
}
Swift
func inventoryTagChanged(tag: UgiTag!, isFirstFind firstFind: Bool) {
  if (firstFind) {
    // tag was found for the first time
  } else if (tag.isVisible) {
    // tag was not visible, is now visible again
  } else {
    // tag is no longer visible
  }
}

Usually the delegate either implements inventoryTagChanged, or implements inventoryTagFound (and sometimes inventoryTagSubsequentFinds).

Tag filtering

The delegate can filter which tags are kept track of via:

Objective-C
- (BOOL) inventoryFilter:(UgiEpc *)epc
  if (this tag should be ignored) {
    return YES;
  } else {
    return NO;
  }
}
Swift
func inventoryFilter(epc: UgiEpc!) -> Bool {
  if (this tag should be ignored) {
    return true;
  } else {
    return false;
  }
}

If this method returns YES, the tag is ignored entirely; inventoryTagFound, inventoryTagSubsequentFinds and inventoryTagChanged are never called for it.

List of found tags

While inventory is running, the app can access the list of found tags via the tags property of the UgiInventory object. Usage is typically:

Objective-C
  for (UgiTag *tag in [Ugi singleton].activeInventory.tags) {
    // do something with tag
  }
Swift
  Ugi.singleton().activeInventory.tags.forEach { (tag) in
    // do something with tag
  }
Tag Access (read, write, ...)

Methods in UgiInventory allow tag access for reading, writing and locking. All of these functions work similarly.

Tag programming (changing tag EPC)

While inventory is running, the app can program tags via:

Objective-C
  UgiEpc *oldEpc = [UgiEpc epcFromString:@"1234567890abcdef12345678"];
  UgiEpc *newEpc = [UgiEpc epcFromString:@"35fffffff956734504747454"];
	[[Ugi singleton].activeInventory programTag:oldEpc
                                        toEpc:newEpc
                                 withPassword:UGI_NO_PASSWORD
                                whenCompleted:^(UgiTag *tag, UgiTagAccessReturnValues result) {
                                  if (result == UGI_TAG_ACCESS_OK) {
                                    // tag programmed successfully
                                  } else {
                                    // tag programming was unsuccessful
                                  }
	}];
Swift
  let oldEpc = UgiEpc(fromString: "1234567890abcdef12345678")
  let newEpc = UgiEpc(fromString: "35fffffff956734504747454")
  Ugi.singleton().activeInventory.programTag(
    oldEpc,
    toEpc: newEpc,
    withPassword: UGI_NO_PASSWORD,
    whenCompleted: { (tag, result) in
      if (result == UgiTagAccessReturnValues.UGI_TAG_ACCESS_OK) {
        // tag programmed successfully
      } else {
        // tag programming was unsuccessful
      }
  })

Sometime after the programTag method is called, the completion will be with the success or failure of the programming.

Auto-rotation

Since U Grok It plugs into the iOS device's audio port, the audio port needs to be on the bottom of the Grokker, requiring iPhones before the iPhone 5 to be held upside down. This can easily be accomplished in the View's supportedInterfaceOrientations (or shouldAutorotateToInterfaceOrientation pre-iOS 6), either by custom code or by using a UGI method:

Objective-C
- (NSUInteger)supportedInterfaceOrientations {
  return [[Ugi singleton] supportedInterfaceOrientationsWithAllowRotationOnTablet:YES];
}
Swift
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
  return Ugi.singleton().supportedInterfaceOrientationsWithAllowRotationOnTablet(true)
}
Grokker Configuration
Inventory

The UgiRfidConfiguration object holds the configuration to be used during inventory. Several pre-defined types can be used, defined in the UgiInventoryTypes enum. Values that can be configured include:

  • Power level
    Initial, minimum and maximum power levels can be set. If a range is provided (minimum != maximum), then the power level is varied over this range.
  • Q value
    Initial, minimum and maximum Q values can be set. If a range is provided (minimum != maximum), then the Q value is dynamically adjusted based on the number of tags in range
  • Session
    The inventory session (0, 1, 2, or 3)
  • Power level and sensitivity for writing tags
    The power level and sensitivity used when writing data to tags
  • Sensitivity
    The reader sensitivity

For more detailed information about RFID and configuration, see RFID Configuration

Sounds

The sounds that the grokker makes when tags are found can be configured.

Using the iOS Simulator

To test your app using the iOS simulator (for instance to test devices that you do not have physically, or to take screen shots), you can plug the Grokker into your Mac and it will work with your app running in the iOS simulator. Be sure to plug the Grokker in before running the app, and keep it plugged in, since the iOS simulator does not handle audio devices being plugged and unplugged. On a Macbook (Pro or Air) you can plug the Grokker in directly, on a Mac Mini you will need an adapter cable (the Mac Mini has seperate microphone and speaker jacks).

SDK Internet Usage

The SDK uses the Internet in a few cases, see SDK Internet Usage for details.

Localization

The SDK contains user visible strings for updating firmware, setting region of the world, and UI building blocks. It is localized into Spanish, French and German. For the localized strings to be used, your app must be localized into these languages as well. If you are interested in localizations to other languages, contact us.