Viewing the SMP101Appdelegate Files

The SMP101Appdelegate.h and SMP101Appdelegate.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 SMP101Appdelegate files make use of the SUPApplication and SUPDataVault APIs to show how to store and retrieve sensitive data (such as SAP Mobile 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 SAP Mobile Platform user's password is also requested.

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

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 SMP101 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 SMP101 data vault using the PIN as the password, and store the SMP 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 SMP101 data vault");
            [SUPDataVault deleteVault:kSMP101DataVaultID];
        }
        @catch(NSException *e)
        {
            // Ignore any exception
        }
        
        @try {
            NSLog(@"Create new SMP101 data vault and store credentials and a generated encryption key");
            smp101vault = [SUPDataVault createVault:kSMP101DataVaultID withPassword:self.pin withSalt:kSMP101DataVaultSalt]; // creates the vault
            [smp101vault setString:@"password" withValue:self.password];
            if (![smp101vault isLocked])
            {
                [smp101vault lock];
            }
        }
        @catch (NSException *exception) {
            NSLog(@"Exception in creating new SMP101 data vault: %@: %@",[exception name], [exception reason]);
            [self showNoTransportAlert:kSMP101ErrorFailure];
            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:kSMP101ErrorFailure];
            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:kSMP101ErrorBadPin];
            return;
        }
        
    }

This code sample sets up the Application API settings for connection to the SAP Mobile Server and registers with the SAP Mobile 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 {
        smp101vault = [SUPDataVault getVault:kSMP101DataVaultID];
        if ([smp101vault isLocked])
        {
            [smp101vault unlock:self.pin withSalt:kSMP101DataVaultSalt];
        }
        
        // Register callback handlers. This should be done before any other SMP code is called.
        [SMP101SMP101DB 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 = [smp101vault getString:@"password"];
            props.activationCode = nil;
        }
        props.loginCredentials = login;

This code sample does one of two things depending on whether the application has been run before:

// Get the connection profile for the database.
        SUPConnectionProfile *cp = [SMP101SMP101DB getConnectionProfile];
        [cp enableTrace:NO];
        
        // Delete any existing database from previous versions.
        if(self.firstRun && [SMP101SMP101DB databaseExists])
        {
            [SMP101SMP101DB deleteDatabase];
        }
        
        
        // Create the database if required and set the encryption key.
        if(![SMP101SMP101DB databaseExists])
        {
            [SMP101SMP101DB createDatabase];
            // We need to generate a new encryption key to encrypt the DB
            [SMP101SMP101DB generateEncryptionKey];
            // Store the encryption key in the data vault for future use.
            SUPConnectionProfile *cp = [SMP101SMP101DB getConnectionProfile];
            [smp101vault 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 = [smp101vault getString:@"encryptionkey"];
            NSLog(@"Got the encryption key: %@",key);
            [cp setEncryptionKey:key];
        }
        
        // Set the synchronization configuration required to sync with the server.
        SUPConnectionProfile *sp = [SMP101SMP101DB 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:[smp101vault getString:@"password"]];

        
    }
    @catch (SUPPersistenceException * pe) {
        NSLog(@"%@: %@", [pe name],[pe message]);
        [self showNoTransportAlert:kSMP101ErrorFailure];
        return;
    }
    @catch (NSException* e) {
        NSLog(@"%@: %@", [e name],[e reason]);
        [self showNoTransportAlert:kSMP101ErrorFailure];
        return;
    }
    @finally
    {
        if (![smp101vault isLocked])
        {
            [smp101vault lock];
        }
    }
    
    @try {
        // Initialize generated package database class with this application instance.
        [SMP101SMP101DB 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:kSMP101DataVaultID]);
        
    }
    @catch (SUPApplicationTimeoutException* tex)
    {
        NSLog(@"%@: %@", [tex name],[tex message]);
        [self showNoTransportAlert:kSMP101ErrorFailure];
        return;
    }
    @catch (NSException *e)
    {
       // When we are faced with a registration 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:kSMP101ErrorFailure];
        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, theonConnectionStatusChanged:(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 SAP Mobile Server through a Relay Server, then you must provide additional information for the database synchronization profile: