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.

We can help you build your next Swift app in weeks rather than months
Read more about ProcessOne and Swift »

Principles

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 = MobileProvision.read() {
   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.


Let us know what you think 💬


4 thoughts on “Reading iOS Provisioning Profile in your Swift App

  1. Do you have a version of this code for Objective-C? I cann’t found any class use like PropertyListDecoder in ObjC. I want to read the data in the embedded.mobileprovision with ObjC for iOS. Please help me if you have a solution. Thank you so much.

    • // Get path to provisioning profile file and check it exists
      NSString *path = [[NSBundle mainBundle] pathForResource:@”embedded” ofType:@”mobileprovision”];
      if ([path length] == 0 || ![[NSFileManager defaultManager] fileExistsAtPath:path])
      {
      NSLog(@”Warning: provisioning profile doesn’t exist”);
      return;
      }

      // Read entire profile into a string
      NSError *error = nil;
      NSString *string = [NSString stringWithContentsOfFile:path encoding:NSISOLatin1StringEncoding error:&error];
      if (error || [string length] == 0)
      {
      NSLog(@”%@”, error);
      return;
      }

      // Skip binary part at the start of the profile and extract plist
      if (![string hasPrefix:@”<plist"])
      {
      NSScanner *scanner = [NSScanner scannerWithString:string];
      [scanner scanUpToString:@"<plist" intoString:nil];
      NSString *tempString = nil;
      [scanner scanUpToString:@"” intoString:&tempString];
      string = [tempString stringByAppendingString:@””];
      }

      // Convert plist string to data to plist object
      NSData *data = [string dataUsingEncoding:NSISOLatin1StringEncoding];
      NSPropertyListSerialization *plist = [NSPropertyListSerialization
      propertyListWithData:data
      options:NSPropertyListImmutable
      format:nil
      error:&error];
      if (error)
      {
      NSLog(@”%@”, error);
      return;
      }

      // The plist object should be a dictionary
      NSDictionary *dict = (NSDictionary*)plist;
      NSLog(@”%@”, dict);

Leave a Reply to nguyễn thanh trí Cancel Reply


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