Best Practices for iOS Apps
Feb 27, 2018
When developing iOS apps, use these best practices to improve compatibility between XenMobile 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 XenMobile. 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 XenMobile 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 XenMobile policies and so should be handled accordingly.
|Object Class||Selector Name|
Redirect Runtime Interfaces
XenMobile provides UI Pin Prompt interaction so you don’t have to do it in your app.
To ensure XenMobile readiness, it is suggested that you don’t redirect or substitute Objective-C runtime selectors since XenMobile 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 XenMobile redirects:
|Object Class Name||Selector Name|
Data Encryption and iOS 9
Apps wrapped with MDX Toolkit 10.0.x will not run on iOS 9. Developers must re-wrap ISV apps with MDX Toolkit 10.2. Users must install the upgraded apps before upgrading their devices to iOS 9. If users try to open on iOS 9 any apps that were wrapped with MDX Toolkit 10.0.x, they will not be able to upgrade those apps and must reinstall a version of those apps wrapped with MDX Toolkit 10.2.
As a result of changes in iOS 9, MDX encryption is incompatible with iOS9 for data downloaded to an iOS 9 device from a wrapped app. Apple requires a device passcode to encrypt all app data on the device using iOS file encryption. You can choose from the following options to protect data:
- By default, wrapped apps will require a PIN or passcode on an iOS 9 device.
- In addition to requiring a PIN or passcode, you can also specify a minimum data protection class that is used for the app data unless a higher protection level is already specified in iOS.
To support the iOS level of protection, MDX Toolkit 10.2 includes a new policy, Device passcode, which requires a PIN or passcode on an iOS 9 device. By default, this policy is On. The policy applies on a per-app basis and can be used whether you run XenMobile in MDM or MAM mode.
Apps wrapped with MDX Toolkit 10.2 use MDX encryption for Sqlite databases and keychain only. Sqlite databases are the underlying foundation for the more complex Apple Core Data Persistent Storage model. The other Apple Core Data models rely on file objects in the Apple file system in the app sandbox.
Other policies and iOS 9:
- The user entropy feature, which is enabled through the Encrypt secrets using Passcode key, is not affected by iOS 9. The keychain and secure vault on the device are not affected.
- On iOS 9 devices, the Enable encryption policy now enables database and keychain encryption only. For older iOS devices, the Enable encryption policy continues to also enable MDX file encryption.
- For additional protection on devices with a device passcode enabled, the MDX App SDK also include a higher level of iOS encryption for files that those apps store on the device. iOS file encryption has several data protection levels. The new Minimum data protection class policy lets you specify a protection class that is used for the app data unless a higher protection level is already specified in iOS. The policy values are:
Complete unless open – If a file is open when a device locks, the file continues to be available to the app. This value corresponds to NSFileProtectionCompleteUnlessOpen. Default value.
Complete – When a device locks, files become unavailable. This value corresponds to NSFileProtectionComplete.
Until first unlock – When a device restarts, until the user unlocks the device for the first time, files are locked and can’t be read. This value corresponds to NSFileProtectionCompleteUntilFirstUserAuthentication.
None – Files have no special protections and can be read from or written to at any time. This value corresponds to NSFileProtectionNone.
Important: Developers, be sure to test wrapped apps that perform background processing, such as content refreshes on a locked device or background syncs.
This policy is hidden. To make the policy visible in XenMobile, open the policy_metadata.xml file for the app (in Applications/Citrix/MDXToolkit/data) and, in the MinimumDataProtectionClass section, change the value of PolicyHidden to false. After you wrap your app, the policy appears when you add the app to XenMobile.
The user experience:
- After a user upgrades to an app wrapped with MDX Toolkit 10.2 and then starts the app, MDX prompts the user to create a device passcode, if none exists. MDX then decrypts existing MDX-encrypted files and uses iOS file encryption to secure the files.
- If users try to open on iOS 9 any apps that were wrapped with MDX Toolkit 10.0.x, they will not be able to upgrade those apps and must reinstall a version of those apps wrapped with MDX Toolkit 10.2.
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 XenMobile 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 XenMobile 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 XenMobile 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 XenMobile. This technique has been successful in all apps tested with XenMobile 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.
XenMobile 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 XenMobile.
Apple SQLite databases are encrypted by XenMobile 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. XenMobile 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
XenMobile substitutes an instance of the private XenMobile SecureViewController class for instances of the Apple Objective-C QLPreviewController object class at runtime. XenMobile 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 XenMobile encryption. This file mode flag is removed from the list of modes when processed by XenMobile.
Encryption User Entropy
One XenMobile 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 XenMobile client property, Encrypt secrets using Passcode, adds user entropy. You configure that client property, which is disabled by default, in the XenMobile 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:
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:
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 XenMobile 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 NetScaler 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 NetScaler Gateway.
- 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 XenMobile:
- Apps developed with Xamarin cross platform development environment are supported. Citrix does not officially declare support for other cross platrom development environments due to insuffivient 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 XenMobile administrator must configure the policy in the XenMobile 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.
- XenMobile 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.
Best Practices for iOS Apps
In this article
- MDX App SDK Framework and Wrapping
- Use Explicit App IDs
- Don’t Block the Main Thread
- Write Robust Code
- Redirect Runtime Interfaces
- Data Encryption and iOS 9
- Ensure Data Encryption Compatibility
- Encryption User Entropy
- Data Containment Compatibility
- Icon File Support
- Networking and micro VPN
- Third Party Library Support