Reading iOS Provisioning Profile in your Swift App

In this short post, I will describe how to a read provisioning profile from iOS mobile app to discover some apps metadata.

The mobile provisioning profile is a file embedded by XCode when you build and package your application. It contains several pieces of information that can be useful for your app. For example, you can get the Apple push environment to use, either sandbox for development apps or production for store or Testflight production builds.


Getting and reading the mobile provisioning file

The mobile provision file is embedded in the app. You can read it from the main bundle. You first need to read the path of that file from the main bundle:

let profilePath: String? = Bundle.main.path(forResource: "embedded",
                                            ofType: "mobileprovision")

And then you can try reading the file into an string:

let profileString = try? NSString.init(contentsOfFile: profilePath,
                                       encoding: String.Encoding.isoLatin1.rawValue)

Extracting the metadata plist

The provisioning profile contains a plist file that exposes some app metadata. However, the plist string is embedded in a larger binary file. The easiest way to extract the plist is to read only the XML part of the file. This can be done as follows:

// Skip binary part at the start of the mobile provisionning profile
let scanner = Scanner(string: profileString as String)
guard scanner.scanUpTo("<plist", into: nil) != false else { return nil }

// ... and extract plist until end of plist payload (skip the end binary part.
var extractedPlist: NSString?
guard scanner.scanUpTo("</plist>", into: &extractedPlist) != false else { return nil }

guard let plist = extractedPlist?.appending("</plist>").data(using: .isoLatin1) else { return nil }

Parsing the plist string

You can finally parse the plist strong to get the plist content into a MobileProvision struct, using Swift decodable protocol, introduced in Swift 4:

let decoder = PropertyListDecoder()
do {
   let provision = try decoder.decode(MobileProvision.self, from: plist)
   // Do something with the data
} catch let err {
   // Handle parsing error

Putting it all together

Here is the full code with the MobileProvision struct implementing the Decodable protocol:

You can use the code from your mobile app as follows:

var sandbox: Bool
if let provision = {
   print("We need to use Sandbox")
   sandbox = provision.entitlements.apsEnvironment == .development ? true : false

That’s it. Your application is now able to discover if it should use APNS in development or production mode automatically, without having to rely on defining a DEBUG build environment variable.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.