Viewing the SUP101Appdelegate Files

The SUP101Appdelegate.h and SUP101Appdelegate.m files are created when you create the Xcode project; however, you deleted the automatically generated versions and replaced them with the ones added from the source code ZIP file.

The SUP101Appdelegate files make use of the SUPApplication and SUPDataVault APIs to show how to store and retrieve sensitive data (such as Sybase Unwired Platform credentials) using a PIN.

The applicationDidFinishLaunching method checks to see if the application has been run before, then prompts the device user for a PIN to unlock the application; the Sybase Unwired Platform user's password is also requested.

Control passes to the initializeSUP101 method. This code sample does one of two things, depending on whether the application has been run before:

SUPDataVault *sup101vault = nil;
SUPDataVault *messagingvault = nil;

// Make sure to set the application identifier same as the project name. This is case sensetive.
// Setting the identifer first is essential to getting any information from the SUPApplication class
// about registration, connection and context.

SUPApplication* app = [SUPApplication getInstance];
if (!SUPApplication.applicationIdentifier)
{
app.applicationIdentifier = @"SUP101";
}

if(self.firstRun)
{
NSLog(@"Running the app for the first time.");



// If the application is being run for the first time, we do the following:
// 1. Remove the messaging data vault created by earlier versions of the application, if it exists.
// 2. Remove the SUP101 data vault created by earlier versions of the application, if it exists.
// 3. Create the messaging vault using the PIN as the password, leaving it unlocked for use by the messaging layer.
// 4. Create the SUP101 data vault using the PIN as the password, and store the SUP username/password credentials 
// and a database encryption key in the vault.
// 
@try
{ 
NSLog(@"Delete preexisting messaging vault");
[SUPDataVault deleteVault:kMessagingDataVaultID];
}
@catch(NSException *e)
{ 
// Ignore any exception
}
@try {
NSLog(@"Delete preexisting SUP101 data vault");
[SUPDataVault deleteVault:kSUP101DataVaultID];
}
@catch(NSException *e)
{ 
// Ignore any exception
}

@try {
NSLog(@"Create new SUP101 data vault and store credentials and a generated encryption key");
sup101vault = [SUPDataVault createVault:kSUP101DataVaultID withPassword:self.pin withSalt:kSUP101DataVaultSalt]; // creates the vault
[sup101vault setString:@"password" withValue:self.password];
if (![sup101vault isLocked])
{
[sup101vault lock];
}
}
@catch (NSException *exception) {
NSLog(@"Exception in creating new SUP101 data vault: %@: %@",[exception name], [exception reason]);
[self showNoTransportAlert:kSUP101ErrorFailure];
return;
}
@try {
NSLog(@"Create new messaging vault and leave it unlocked");
messagingvault = [SUPDataVault createVault:kMessagingDataVaultID withPassword:self.pin withSalt:kDVStandardSalt];
}
@catch (NSException *exception) {
NSLog(@"Exception in creating new messaging data vault: %@: %@",[exception name], [exception reason]);
[self showNoTransportAlert:kSUP101ErrorFailure];
return;
}

}
else
{
// If the application has been run before, we get the PIN from the user, and use it to unlock the existing messaging data vault
// (otherwise the messaging layer cannot start).
NSLog(@"App has been run before.");
@try {
NSLog(@"Unlock messaging vault");
messagingvault = [SUPDataVault getVault:kMessagingDataVaultID];
if ([messagingvault isLocked])
{
[messagingvault unlock:self.pin withSalt:kDVStandardSalt];
}
}
@catch (NSException *exception) {
NSLog(@"Exception unlocking messaging data vault: %@: %@",[exception name],[exception reason]);
[self showNoTransportAlert:kSUP101ErrorBadPin];
return;
}

}

This code sample sets up the Application API settings for connection to the Unwired Server and registers with the Unwired Server.

// Add the observer to listen for ON_REGISTER_SUCCESS or ON_CONNECT_SUCCESS for the first run or
// subsequent runs respectively. Also for ON_CONNECT_FAILURE, and ON_REGISTER_FAILURE. Refer to the comments in registerObserverForCallbackNotifications.
// The observer must be added before the call to registerApplication, but after applicationIdentifier is
// set and the messaging vault unlocked. (AppIdentifier being set and the vault being unlocked are prerequisites to
// calling if ([SUPApplication registrationStatus] == SUPRegistrationStatus_REGISTERED) which is used in registerObserverForCallbackNotifications.

[self.viewController registerObserverForCallbackNotifications];

@try {
sup101vault = [SUPDataVault getVault:kSUP101DataVaultID];
if ([sup101vault isLocked])
{
[sup101vault unlock:self.pin withSalt:kSUP101DataVaultSalt];
}

// Register callback handlers. This should be done before any other SUP code is called.
[SUP101SUP101DB registerCallbackHandler:[CallbackHandler getInstance]];
[app setApplicationCallback:[ApplicationCallbackHandler getInstance]];


// Setup the connection properties and login credentials required for registration.
SUPConnectionProperties* props = app.connectionProperties;
[props setServerName:self.serverName];
[props setPortNumber:[self.serverPort intValue]];
[props setUrlSuffix:@""];
[props setFarmId:self.farmID];

SUPLoginCredentials* login = [SUPLoginCredentials getInstance];
if(self.manualRegistration)
{
login.username = self.connectionName;
login.password = nil;
props.activationCode = self.activationCode;
}
else
{
login.username = self.userName;
login.password = [sup101vault getString:@"password"];
props.activationCode = nil;
}
props.loginCredentials = login;

This code sample does one of two things depending on whether the application has run previously:
  • If the application is running for the first time, the sample creates the SUP101 database, generates an encryption key, and stores it in the data vault.
  • If the application has run previously, the sample retrieves the encryption key from the data vault, and sets it in the connection profile so the database can be reused.
// Get the connection profile for the database.
SUPConnectionProfile *cp = [SUP101SUP101DB getConnectionProfile];
[cp enableTrace:NO];

// Delete any existing database from previous versions.
if(self.firstRun && [SUP101SUP101DB databaseExists])
{
[SUP101SUP101DB deleteDatabase];
}


// Create the database if required and set the encryption key.
if(![SUP101SUP101DB databaseExists])
{
[SUP101SUP101DB createDatabase];
// We need to generate a new encryption key to encrypt the DB
[SUP101SUP101DB generateEncryptionKey];
// Store the encryption key in the data vault for future use.
SUPConnectionProfile *cp = [SUP101SUP101DB getConnectionProfile];
[sup101vault setString:@"encryptionkey" withValue:[cp getEncryptionKey]];
}
else
{
// When we are create the database from scratch, we set the database encryption key in generateEncryptionKey.
// If we were using the database from a previous run of the app and not creating it each time, an application should
// run the code below instead to successfully access a previously encrypted database by retrieving the encryption key
// from the datavault and setting it in the connection profile.
NSString *key = [sup101vault getString:@"encryptionkey"];
NSLog(@"Got the encryption key: %@",key);
[cp setEncryptionKey:key];
}

// Set the synchronization configuration required to sync with the server.
SUPConnectionProfile *sp = [SUP101SUP101DB getSynchronizationProfile];
[sp setDomainName:@"default"];
[sp enableTrace:YES];
// by default the AsyncReplay is enabled. We will turn it off. This will make the next syncrhonization a blocking call.
[sp setAsyncReplay:NO];
[sp setUser:self.userName];
[sp setPassword:[sup101vault getString:@"password"]];


}
@catch (SUPPersistenceException * pe) {
NSLog(@"%@: %@", [pe name],[pe message]);
[self showNoTransportAlert:kSUP101ErrorFailure];
return;
}
@catch (NSException* e) {
NSLog(@"%@: %@", [e name],[e reason]);
[self showNoTransportAlert:kSUP101ErrorFailure];
return;
}
@finally
{
if (![sup101vault isLocked])
{
[sup101vault lock];
}
}

@try {
// Initialize generated package database class with this application instance.
[SUP101SUP101DB setApplication:app];

if ([SUPApplication registrationStatus] != SUPRegistrationStatus_REGISTERED)
{
// Register the application with the server.
[app registerApplication:300];
}
else
{
// already registered, start connection.
[app startConnection:300];
}

// Update the value of self.firstRun, We have created the vault and registered with server at this point.
self.firstRun = (![MessagingClientLib isMessagingDBExist] ||
![SUPDataVault vaultExists:kSUP101DataVaultID]);

}
@catch (SUPApplicationTimeoutException* tex)
{
NSLog(@"%@: %@", [tex name],[tex message]);
[self showNoTransportAlert:kSUP101ErrorFailure];
return;
}
@catch (NSException *e)
{
// When we are faced with a registeration error or connection error, the 'onRegistrationStatusChanged'
// or on 'onConnectionStatusChanged' callbacks are triggered in which we send the ON_CONNECT_FAILURE
// notification or the ON_REGISTER_FAILURE notification to handle it
// and show the alert window to the user.So we don't have to do it again here.
// For all other failures, other than the timeout exception above , we will handle it here.
if ([SUPApplication registrationStatus] == SUPRegistrationStatus_REGISTRATION_ERROR)
{
return;
}
if ([SUPApplication connectionStatus] == SUPConnectionStatus_CONNECTION_ERROR)
{
return;
}

NSLog(@"%@: %@", [e name],[e reason]);
[self showNoTransportAlert:kSUP101ErrorFailure];
return;
}

When you run the application for the first time, the ON_REGISTER_SUCCESS notification is registered, and for subsequent runs, the ON_CONNECT_SUCCESS notification is registered. In the above code snippet, the call to the registerObserverForCallbackNotifications method (in SubscribeController) registers the appropriate observer depending on whether or not you are running the application for the first time.

If the application is running for the first time, registerStatus is not SUPRegistrationStatus_REGISTERED, so [app registerApplication:300] is called to start a connection with the server and register the application. If the registration is successful, the onRegistrationStatusChanged:(SUPRegistrationStatusType)registrationStatus:(int32_t)errorCode :(NSString*)errorMessage callback is called, resulting in an ON_REGISTER_SUCCESS notification being posted. Upon receiving this notification, the observer for the ON_REGISTER_SUCCESS notification calls onConnectSuccess:(NSNotification *)notification in the SubscribeController. This enables the Synchronize button in the application, allowing you to initiate a sync with the server.

For subsequent runs, since the application is already registered, registerStatus is SUPRegistrationStatus_REGISTERED, and the call to [app registerApplication:300] just starts a connection with the server. In this case, when the connection is successful, the onConnectionStatusChanged:(SUPConnectionStatusType)connectionStatus:(int32_t)errorCode :(NSString*)errorMessage callback is called, resulting in an ON_CONNECT_SUCCESS notification being posted. Upon receiving this notification, the observer for the ON_CONNECT_SUCCESS notification calls onConnectSuccess:(NSNotification *)notification in the SubscribeController. This enables the Synchronize button in the application, allowing you to initiate a sync with the server.

The process above ensures that you initiate a sync with the server only after a registration (and a connection) is made for the first run. For all other runs you need to initiate the sync only after you make a connection.

If you are connecting to the Unwired Server through a Relay Server, then you must provide additional information for the database synchronization profile: