Handling Provisioning Updates

When customers upload a new Application Configuration Profile to the SAP Mobile Platform server, the application has to fetch the new configuration as soon as possible.

Therefore, app developers must check whether a new ACP is available. To check it, fetch the ACP bundle ID from the server and compare it with the one previously stored on the client (if any). Whenever a new ACP version is available, the application has to download it, and pass the compressed data to the Extensibility Framework. Implement the ACP check and download logic so that it executes whenever the app is started or becomes active.

This example implements the logic required to check for, fetch and store ACP bundles:
/**
 * Checks whether a new ACP version is available on the SMP server
 * @return the updated ACP bundle ID if a new ACP has been uploaded to the SMP server or nil otherwise
 */
-(NSString*) getUpdatedACPBundleID:(SMPAppSettings*)appSettings_in currentBundleID:(NSString*)bundleID_in
{
    NSString* newBundleID = nil;
    // get current bundle name from SMP server
    NSError* error = nil;
    
    newBundleID = [appSettings_in getConfigProperty:@"d:CustomizationBundleId" error:&error];
    
    if( error )
    {
        NSLog(@"Could not fetch ACP bundle ID. %@", error.description);
    }
    else
    {
        // check whether a new ACP is available by comparing the stored bundle ID with the fetched one
        if ( [newBundleID isEqualToString:bundleID_in] )
        {
            NSLog(@"No %@ ACP available on SMP server.", newBundleID ? @"" :@"new");
        }
        else
        {
            NSLog(@"New ACP available on SMP server with ID %@. ", newBundleID);
        }
    }
    
    return newBundleID;
}

/**
 * Updates the local ACP bundle if a new version is available on the SMP server
 * @remark Call this whenever the application becomes active, usually after a succesful login
 */
-(void) fetchACPFromSMP
{
    // initialize SMP connection
    SMPClientConnection* clientConn = [SMPClientConnection initializeWithAppID:self.applicationId
                                                                        domain:@"default"
                                                              secConfiguration:self.securityConfig];
    // [clientConn enableHTTP:self.enableHTTP];
    [clientConn setConnectionProfileWithUrl:self.applicationUrl];
    [clientConn setApplicationConnectionID:self.appConnId];
    
    // check whether there is a new ACP on the SMP server
    // get application settings from SMP
    SMPAppSettings* appSettings = [SMPAppSettings initializeWithConnection:clientConn userName:_userName password:_pwd];
    
    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
    //get previously stored bundle version if any
    NSString* currentBundleID = [userDefaults objectForKey:@"CustomizationBundleId"];
    
    // check for new ACP version on the server
    NSString* newBundleID = [self getUpdatedACPBundleID:appSettings currentBundleID:currentBundleID];
    if( newBundleID )
    {
        // fetch the udpated ACP bundle
        NSError* error = nil;
        NSData* acpData = [appSettings getCustomizationResourceBundleWithCustomizationResource:newBundleID error:&error];
        
        if( error )
        {
            NSLog(@"Could not fetch ACP bundle. %@", error.description);
        }
        else if( acpData )
        {
            // unzip and store ACP bundle
            [self storeCustomConfiguration:acpData];
            
            // update bundle id in user defaults
            [userDefaults setObject:newBundleID forKey:@"CustomizationBundleId"];
            [userDefaults synchronize];
        }
        else
        {
            UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:@"Warning!" message:[NSString stringWithFormat:@"Could not get application bundle with SMP. Error:%@", [error description] ] delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil] autorelease];
            [self performSelectorOnMainThread:@selector(showAlertView:) withObject:alertView waitUntilDone:NO];
        }
    }
}

/**
 * Uncompresses and stores the compressed resource payload
 * @remark Changes won't be reflected till the next application start.
 * @see loadMAFExtConfig
 */
- (void) storeCustomConfiguration:(NSData*)customResourceData
{
    // write out temporary because the zipmodule works only on disk files
#warning adapt compressed payload name to your app specific one
    NSString *tmpFilePath = [[NSTemporaryDirectory() stringByExpandingTildeInPath] stringByAppendingPathComponent:@"zippedBundle.tar"];
    [customResourceData writeToFile:tmpFilePath atomically:YES];
    // pass the compressed configuration data
    // MAF will decompress it and place it in the predefined directory
    [[MAFCore sharedInstance] passConfigurationBundle:tmpFilePath];
    
    [[[[UIAlertView alloc] initWithTitle: NSLocalizedString(@"Configuration change", nil)
                                 message: NSLocalizedString(@"New configuration from SMP has been downloaded.", nil)
                                delegate:nil
                       cancelButtonTitle:NSLocalizedString(@"Ok", nil)
                       otherButtonTitles:nil, nil] autorelease] show];
}

The new configuration is applied when the Extensibility Framework gets initialized after executing the above logic. See Loading the Library.

Note: The APIs used to check and fetch the ACP are synchronous, therefore it is recommended to execute these methods in the background, so that it does not block the main UI thread. This example shows how to do it using Grand Central Dispatch (GCD):
dispatch_queue_t ACPProvisioningQueue = dispatch_queue_create("ACPProvisioningQueue", DISPATCH_QUEUE_SERIAL);

dispatch_async(ACPProvisioningQueue, ^{
    [self fetchACPFromSMP];
});
    
dispatch_release(ACPProvisioningQueue);

GCD automatically creates an autorelease pool per queue. However, if you span a thread using NSThread, NSOperation or performSelectorInBackground, you need create an NSAutoreleasePool for that thread.

Consider using the MAF Reuse Logon Manager and the MAF Logon UI.