Best Practices for iOS Apps

When developing iOS apps, use these best practices to improve compatibility between Citrix Endpoint Management and mobile apps for iOS devices.

MDX App SDK Framework and Wrapping

If your app uses the MDX App SDK Framework, then you must use the matching MDX Toolkit version for wrapping. A version mismatch between these two components might cause improper operation.

To prevent such a mismatch, wrap the app as an ISV app and specify an app mode of Premium or General. That lets you deliver a pre-wrapped app. As a result, your customer won’t need to wrap the app, thus avoiding use of a mismatched MDX Toolkit. For details about ISV wrapping, see Wrapping iOS Mobile Apps in the MDX Toolkit documentation.

Use Explicit App IDs

If your iOS Developer Enterprise account does not support wildcard App IDs, be sure to create an explicit App ID for each app you plan to wrap with the MDX Toolkit and create a provisioning profile for each App ID.

Don’t Block the Main Thread

You should not use blocking code when running on the main thread. This is an Apple guideline, but it is even more crucial with Citrix Endpoint Management. Some actions may take more time in a managed app or may even block further thread execution. File, database, and network operations are examples of operations which might block the currently running thread when issued and should be avoided on the main thread.

Write Robust Code

In particular, you should write apps following the best practices as documented in the Apple programming guides, such as the Apple Application Programming Guide.

Use only Apple published interfaces.

Always check return values from all API calls and handle any exceptions which may occur as a side effect of an API call, to ensure graceful error recovery or graceful termination of the app. While this is a common programming best practice, it is especially important for managed apps.

Various APIs that you’d expect to always work will fail if the underlying functionality has been blocked due to Citrix Endpoint Management policies. Examples would include any of the capabilities described earlier:

  • Networking APIs fail as if there is no network available.
  • Sensor APIs, such as GPS and camera, return null or throw an exception.

The following Objective-C runtime selectors will return nil if the underlying functionality has been blocked due to Citrix Endpoint Management policies and so should be handled accordingly.

Object Class Selector Name
AVCaptureDevice devicesWithMediaType:
MFMailComposeViewController init:
MFMessageComposeViewController initWithNibName:bundle:
NSFileManager URLForUbiquityContainerIdentifier:
NSUbiquitousKeyValueStore defaultStore:
PHPhotoLibrary sharedPhotoLibrary:
UIImagePickerController availableCaptureModesForCameraDevice:
UIPasteboard dataForPasteboardType:
  valueForPasteboardType:
  items:
  dataForPasteboardType:inItemSet:
  valuesForPasteboardType:inItemSet:
UIPopoverController initWithContentViewController:
UINavigationController ctxInitWithRootViewController:
  ctxPopToViewController:animated:

Redirect Runtime Interfaces

Citrix Endpoint Management provides UI Pin Prompt interaction so you don’t have to do it in your app.

To ensure Citrix Endpoint Management readiness, it is suggested that you don’t redirect or substitute Objective-C runtime selectors since Citrix Endpoint Management swizzles the underlying methods of several object class selectors to control and/or modify the runtime behavior of an app. The following table lists the Objective-C class selectors which Citrix Endpoint Management redirects:

Object Class Name Selector Name
NSURLProtectionSpace serverTrust
NSURLAuthenticationChallenge sender
NSURLConnection sendSynchronousRequest:returningResponse:error:
  initWithRequest:delegate:startImmediately:
  initWithRequest:delegate:
  connectionWithRequest:delegate:
NSURLConnectionDelegate connection:canAuthenticateAgainstProtectionSpace:
  connection:didReceiveAuthenticationChallenge:
  connection:willSendRequestForAuthenticationChallenge:
NSURLSessionConfiguration defaultSessionConfiguration
  ephemeralSessionConfiguration
ALAssetsLibrary authorizationStatus
AVAudioRecorder record
  prepareToRecord
  recordForDuration:
  recordAtTime:
  recordAtTime:ForDuration:
AVAudioSession recordPermission
AVCaptureDevice devices
  devicesWithMediaType:
AVAsset assetWithURL:
AVURLAsset initWithURL:options:
  URLAssetWithURL:options:
AVPlayerItem playerItemWithAsset:
  initWithURL:
  playerItemWithURL:
AVPlayer playerWithPlayerItem:
  initWithPlayerItem:
  initWithURL:
CLLocationManager startUpdatingLocation
UIScrollView setContentOffset:
MFMailComposeViewController canSendMail
  init
MFMessageComposeViewController canSendText
  initWithNibName:bundle:
NSFileManager URLForUbiquityContainerIdentifier:
NSUbiquitousKeyValueStore defaultStore
PHPhotoLibrary authorizationStatus
QLPreviewController setDataSource:
  canPreviewItem:
QLPreviewControllerDataSource numberOfPreviewItemsInPreviewController:
  previewController:previewItemAtIndex:
SLComposeViewController isAvailableForServiceType:
UIActivityViewController initWithActivityItems:applicationActivities:
  setExcludedActivityTypes:
UIApplication openURL:
  canOpenURL:
  setApplicationIconBadgeNumber:
UIDocument closeWithCompletionHandler:
  contentsForType:error:
UIDocumentInteractionController interactionControllerWithURL:
  setURL:
  setDelegate:
  presentPreviewAnimated:
  presentOpenInMenuFromBarButtonItem:animated:
  presentOpenInMenuFromRect:inView:animated:
  presentOptionsMenuFromBarButtonItem:animated:
  presentOptionsMenuFromRect:inView:animated:
UIDocumentMenuViewController initWithDocumentTypes:inMode:
UIImage imageNamed:
UIImagePickerController setSourceType:
  takePicture
  startVideoCapture
  isSourceTypeAvailable:
  isCameraDeviceAvailable:
  isFlashAvailableForCameraDevice:
  availableCaptureModesForCameraDevice:
  setMediaTypes
UINavigationController ctxInitWithRootViewController:
  ctxPushViewController:animated:
  ctxPopToViewController:animated:
UIPasteboard generalPasteboard
  pasteboardWithName:create:
  pasteboardWithUniqueName
  setValue:forPasteboardType:
  setData:forPasteboardType:
  setItems:
  addItems:
  dataForPasteboardType:
  valueForPasteboardType:
  numberOfItems
  pasteboardTypes
  pasteboardTypesForItemSet:
  containsPasteboardTypes:
  containsPasteboardTypes:inItemSet:
  items
  itemSetWithPasteboardTypes:
  dataForPasteboardType:inItemSet:
  valuesForPasteboardType:inItemSet:
  string
  strings
  URL
  URLs
  image
  images
  color
  colors
UIPopoverController initWithContentViewController
UIPrintInteractionController isPrintingAvailable
  presentAnimated:completionHandler:
  presentFromBarButtonItem:animated:completionHandler:
  presentFromRect:inView:animated:completionHandler:
UIViewController presentViewController:animated:completion:
UIWebView loadRequest:
  setDelegate:
UIWebViewDelegate webView:shouldStartLoadWithRequest:navigationType:
  webViewDidStartLoad:
  webViewDidFinishLoad:
  webView:didFailLoadWithError:
UIWindow makeKeyAndVisible
UIApplicationDelegate applicationDidFinishLaunching:
  application:didFinishLaunchingWithOptions:
  application:willFinishLaunchingWithOptions:
  applicationWillResignActive:
  applicationDidEnterBackground:
  applicationWillEnterBackground:
  applicationDidBecomeActive:
  applicationWillTerminate:
  application:openURL:sourceApplication:annotation:
  application:handleOpenURL:
  applicationProtectedDataWillBecomeUnavailable:
  applicationProtectedDataDidBecomeAvailable:
  application:performFetchWithCompletionHandler:
  application:handleEventsForBackgroundURLSession:completionHandler:
  application:didReceiveLocalNotification:
  application:didReceiveRemoteNotification:
  application:didReceiveRemoteNotification:fetchCompletionHandler:
  application:didRegisterForRemoteNotificationsWithDeviceToken:
  application:didFailToRegisterForRemoteNotificationsWithError:
  applicationSignificantTimeChange:
  application:shouldAllowExtensionPointIdentifier:
QLPreviewController allocWithZone:

Ensure Data Encryption Compatibility

One of the primary features of MDX is that all persisted data is transparently encrypted. You don’t need to modify your app to gain this functionality and, in fact, you can’t directly avoid it. The Citrix Endpoint Management administrator has the ability to disable encryption either selectively or entirely, but not the app.

This is one of the more heavyweight aspects of MDX and requires an understanding of the following points:

  • File encryption is present for all native code that runs in managed processes.

    The file data encryption implementation supports all native code and not just code for apps using the Apple frameworks and the Apple Objective-C runtime. Any file data encryption implemented within and solely for the Objective-C runtime can be easily subverted.

  • Some framework APIs, such as AVPlayer class, UIWebView class, and QLPreviewController, are actually implemented by iOS service processes in a different execution context than the user’s managed app process.

    These service processes are unable to decrypt MDX encrypted file data, so the managed app must provide the service process with a temporary unencrypted copy of the data which is subsequently deleted by the managed app after 5 seconds. It is important that you are aware of the limitation when using these classes because we lose containment control of the data provided to these classes due to Apple implementation of these specific classes.

  • Memory mapping is problematic for Citrix Endpoint Management encryption since it relies on app calling file I/O system call interfaces.

    Once a file is memory mapped, the I/O requests for the file are managed outside of the context of the user app bypassing Citrix Endpoint Management encryption. All POSIX mmap(2) calls by a managed app are mapped as MAP_PRIVATE and MAP_ANON and not associated with any file description. An attempt is made to read in all the mapped data during the mmap call if a file description is specified to fault in all the data since any subsequent paging in of data by the operating system will result in reading encrypted data without it being decrypted by Citrix Endpoint Management. This technique has been successful in all apps tested with Citrix Endpoint Management since the amount of data that is memory mapped is small with no memory page reclaims happening within the app.

  • Encryption adds measurable overhead. Developers should optimize disk I/O to prevent performance degradation. As an example, if you are repeatedly reading and writing the same information, you might want to implement an app level cache.

  • Citrix Endpoint Management only encrypts instances of the Apple libsqlite.dylib . If the application directly links with and/or embeds an private version of the libsqlite.dylib , the databases instances of that private library will not be encrypted by Citrix Endpoint Management.

  • Apple SQLite databases are encrypted by Citrix Endpoint Management using the SQLite Virtual File System layer.

    Performance can be an issue. The standard database cache size is 2000 pages or 8 megabytes. If your database is large, a developer may need to specify SQLite pragma to increase the database cache size. In Objective-C Core Data Framework, the SQLite pragma can be added as an option dictionary when adding the Persistent Store object to the Persistent Store Controller object.

  • SQLite WAL mode is not supported since the library is relinked to file I/O interfaces and internally uses memory mapping extensively.

  • NSURLCache DiskCache is implemented by iOS using a SQLite database. Citrix Endpoint Management disables the disk cache associated since this database is referenced by unmanaged iOS service processes.

  • The following table lists the hardcoded excluded file path name patterns:

       
    .plist Excluded due to access by iOS system processes outside process context.
    .app Legacy substring in the Application Bundle name. This substring will be deprecated because an explicit Application Bundle path is now excluded.
    .db A file with this suffix is not encrypted if the file is not a sqlite database.
    /System/Library File paths that exist within the app bundle sandbox directory and file paths outside the app data sandbox cannot be encrypted. On iOS, the installed app is read only and is in a different directory than the app data files that the app produces and stores when it is run.
    Library/Preferences Files are accessed by iOS directly. Normally only .plist files are present in this directory path.
    /com.apple.opengl/ Files are accessed by iOS directly.
    csdk.db Legacy Citrix SSLSDK sqlite database
    /Library/csdk.sql Citrix SSLSDK sqlite database
    CtxLog_ Citrix log file name prefix
    CitrixMAM.config MDX internal filename
    CitrixMAM.traceLog Legacy MDX internal filename
    CtxMAM.log MDX internal filename
    data.999 MDX internal filename
    CTXWrapperPersistentData MDX internal filename
    /Documents/CitrixLogs MDX log directory
    /Document/CitrixLogs.zip Compressed MDX log directory name
    Any file in the app Bundle directory path Read only directory of app files
  • Citrix Endpoint Management substitutes an instance of the private Citrix Endpoint Management SecureViewController class for instances of the Apple Objective-C QLPreviewController object class at runtime. Citrix Endpoint Management SecureViewController class is derived from the Apple Objective-C UIWebView object class. The QLPreviewController object class natively supports a few file formats which the UIWebView object class doesn’t natively support, such as the audio and pdf types.

  • For best performance, file I/O requests should be issued to file offsets which are a multiple of 4096 bytes and should be issued for a length which is also a multiple of 4096 bytes.

  • The O_NONBLOCK file mode flag is not supported by Citrix Endpoint Management encryption. This file mode flag is removed from the list of modes when processed by Citrix Endpoint Management.

Encryption User Entropy

One Citrix Endpoint Management option for encryption requires the end user to enter a PIN before the encryption key can be generated. This option is called user entropy. It can cause a particular issue for apps.

Specifically, no file or database access can be performed until the user enters a PIN. If such an I/O operation is present in a location that runs before the PIN UI can be displayed, it will always fail.

To ensure that this issue isn’t present in your app, test with user entropy enabled. The Citrix Endpoint Management client property, Encrypt secrets using Passcode, adds user entropy. You configure that client property, which is disabled by default, in the Citrix Endpoint Management console under Configure > Settings > More > Client Properties.

Data Containment Compatibility

  • Any remote view controllers will not have security containment (for example, data encryption; copy, cut, and paste policy blocking; and so on) because a remote view controller runs in a different process context than the MDX-managed app.
  • The Copy action is only action supported from UIResponder. Other actions, such as Cut and Delete, are not supported.
  • Airdrop is only intercepted at the UI level, not at a lower level.
  • MFI and Bluetooth are not intercepted.

Icon File Support

MDX wrapping requires the presence of at least one icon that can be used as the springboard icon or app icon. App developers can add their icons to the Asset Catalog, or use the CFBundleIcons or CFBundleIconFiles keys in Info.plist.

The MDX Toolkit will pick the first one from the list of known plist locations in Info.plist:

  • CFBundleIcons
  • CFBundlePrimaryIcon
  • CFBundleIconFiles
  • UINewsstandIcon
  • CFBundleDocumentTypes

If none of those keys is found in Info.plist, the MDX Toolkit will identify one of the following icons in the root folder of the app bundle:

  • Icon.png
  • Icon-60@2x.png
  • Icon-72.png
  • Icon-76.png

Networking and micro VPN

MDX currently manages only those networking calls issued directly by an app. Some DNS queries are issued directly by the Apple framework and so are not managed by MDX.

Several Citrix Endpoint Management policy options are available to administrators for networking. The Network access policy prevents, permits or redirects app network activity as follows:

  • By default, the network is completely blocked for an app. If the Network access policy is set to Blocked, networking APIs used by your app will fail. Per the previous guideline, you should gracefully handle such a failure.
  • If the Network access policy is set to Unrestricted, all network calls go directly and are not tunneled.
  • If the Network access policy is set to Tunneled to the internal network, all network calls are tunneled through the Citrix Gateway. The tunneling under this policy is controlled by the Preferred VPN mode policy.

The Preferred VPN mode policy sets the initial mode for connections that tunnel to the internal network:

  • If the Preferred VPN mode policy is set to Secure browse, the http/https URL is rewritten. Secure browse can tunnel only http and https traffic. A significant advantage of secure browse is single sign on (SSO) for http and https traffic and also PKINIT authentication. On Android, secure browse has low setup overhead and is thus the preferred option for web browsing type of operations.
  • If the Preferred VPN mode policy is set to Full VPN tunnel, all traffic from the managed app is tunneled through Citrix Gateway.

Limitations:

  • WkWebView is not supported.
  • Users cannot play videos hosted on internal websites in iOS wrapped MDX apps because the videos play in a media player process on the device that MDX does not intercept.
  • NSURLSession background download (NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier) is not supported.
  • We block UDP traffic if the Network access policy is set to Blocked. We don’t tunnel UDP traffic if the Network access policy is set to Tunneled to the internal network.
  • MDX-wrapped apps cannot instantiate a socket server that listens for inbound connections. However, MDX-wrapped apps can use a client socket to connect to a server.

Third Party Library Support

Some app frameworks have compatibility issues with Citrix Endpoint Management:

  • Apps developed with Xamarin cross platform development environment are supported. Citrix does not officially declare support for other cross platrom development environments due to insufficient examples of use and testing.
  • SQLCipher doesn’t work with encryption because it uses memory mapping. One solution is to not use SQLCipher. A second solution is to exclude the database file from encryption using an encryption exclusion policy. A Citrix Endpoint Management administrator must configure the policy in the Citrix Endpoint Management console.
  • App and third party libraries which link directly to OpenSSL libcrypto.a and libssl.a libraries can result in link error due to missing symbols and link errors due to multiple symbol definition.
  • Apps requiring support for Apple Push Notification Service will need to follow specific steps which Apple requires.
  • Citrix Endpoint Management explicitly sets the SQLite database version to 1 in order to disable Write Ahead Logging (WAL) file and memory mapped file support within SQLite databases. Any attempt to directly access SQLite interfaces in SQLite version 2 or version 3 will fail.