iOS Enterprise Provisioning Profile Expiration

Enterprise Distribution Provisioning Profile Expiration

So generating a new provisioning profile will not invalidate any of the apps out there on devices. Simply generate the new provisioning profile, build a new version of the app with the new provisioning profile, and just make sure all your users / testers update to the new version of the app.

Alternatively, you could generate the provisioning profile and then distribute the profile to all the devices through MDM (if you're using an MDM solution) or by email (not a great experience). Basically the app will continue to run as long as the new provisioning profile gets on the device before the old one expires, whether that's through MDM, manually, or by installing a new version of the app with the provisioning profile in the .app payload. Or if your users download any app with the new provisioning profile, assuming that provisioning profile is set up with a wildcard app ID, that will also correct it (see information about that here: https://stackoverflow.com/a/29121777/3708242).

Basically, you need to do something before the provisioning profile expires (the sooner the better) and get that new provisioning profiles on the device (through one of the options above).

Expired Provisioning-profiles update

So, unfortunately, none of the existing deployed apps will run now, so you will not be able to use the self-updating logic in the app to correct this. This is up to the developers to keep track of expiring profiles and certificates and ensure they get updated as needed.

All of the information below assumes you are using an Enterprise Distribution Profile to build these iOS apps.

You should note is that there are two things that can expire: the provisioning profile and the certificate.

Expiring Provisioning Profile:

Typically the provisioning profile expiring is easier to deal with, as you only need to get a new profile on the device. Technically, doing a new build with a new provisioning profile will do this, but there are other ways. For example, if these are managed, company devices, you can typically use the MDM software to push a new profile to the devices, without requiring a new .ipa (app binary) to be installed on the device). Also, if you use wildcard app ids in your provisioning profile, installing another device with a newer provisioning profile will also work (although this is a bit unorthodox). Long story, short: You need to get the new profile on the device. At this point, that is likely through you informing users they need to go re-download a new version of the app.

Expiring Certificate

If the certificate used to code sign the application is expiring, you will need to generate a new binary with the new certificate. There are ways to resign an existing ipa, but if you have the source code, it is easier to just re-build with the new certificate. The good news is that the certificate only expires every 3 years for an enterprise distribution certificate (vs. every 1 year for the provisioning profile). So this is not needed as often. But this will certainly require you to re-create a new binary signed with the new certificate.

Preventing This From Recurring

If you rely on the app to check for updates and self update, you need to make sure a new version gets published well enough in advance that users will launch the app in the time between the new version being released, and the profile or cert expiration. This length of time depends on your app. If it's a corporate app that people use daily, you can probably get by with 2 or 3 weeks (for people who are out of the office). If it's seldom used, I would consider deploying a new version, with a new provisioning profile at least 3-6 months in advance of the old one expiring. This takes planning and reminders to ensure you don't miss the timing window.

Also of note, if you are using automatic code signing, you lose some control over when a new profile is generated and used, as well as the certificates. That's why I recommend for enterprise apps to use manual code signing settings to allow you to be very explicit with which provisioning profiles are used, as well as the cert. Also, delete all older profiles from the Mac when doing a build to ensure you are using the right profile (you can have many profiles on the Mac for the same application at any given time. You can find them here: https://stackoverflow.com/a/45642752/3708242). It's risky to assume Xcode will pick the most recent one.

Checking for provisioning profile expiration

Here is a python script that will abort the build if the provisioning profile expires in less than 15 days. This script is meant to be run as a build phase script.

Note that this script will also work when run as part of an Xcode Bot integration.

#!/usr/bin/python

import glob, os, plistlib, subprocess, sys
from os import path
from datetime import datetime

def read_mobileprovision(mobileprovision_path):
# From http://stackoverflow.com/questions/6398364/parsing-mobileprovision-files-in-bash/10490095#10490095
return plistlib.readPlist(subprocess.Popen(['security', 'cms', '-D', '-i', mobileprovision_path], stdout=subprocess.PIPE).stdout)

if os.environ['PLATFORM_NAME'] != 'iphoneos':
sys.exit(0)

provisioning_profiles_dir = '/Library/Developer/XcodeServer/ProvisioningProfiles' if os.environ['USER'] == '_xcsbuildd' else path.expanduser('~/Library/MobileDevice/Provisioning Profiles')
provisioning_profile_uuid = os.environ['EXPANDED_PROVISIONING_PROFILE']
mobileprovision_path = path.join(provisioning_profiles_dir, provisioning_profile_uuid + ".mobileprovision")
if not path.exists(mobileprovision_path):
for mobileprovision in glob.iglob(path.join(provisioning_profiles_dir, "*.mobileprovision")):
if read_mobileprovision(mobileprovision)['UUID'] == provisioning_profile_uuid:
mobileprovision_path = mobileprovision
break

print(mobileprovision_path)

expiration_date = read_mobileprovision(mobileprovision_path)['ExpirationDate']
print("Expiration Date: {}".format(expiration_date))

remaining_days = (expiration_date - datetime.now()).days
print("Remaining Days: {}".format(remaining_days))

if remaining_days < 15:
sys.exit("error: Provisioning Profile {} is expiring in {} days.".format(mobileprovision_path, remaining_days))

iOS Enterprise App Distribution – Provisioning Profile expired

Despite this being a MAC OS X prov checker, it applies all the same to iOS too:

https://github.com/LigeiaRowena/ProvisioningInfo

Personally, that information shouldn't bother your users. You should have a clear record of when they expire, and notify the users via push notifications and/or some form of REST api for expiration dates.

Ideally, the best way to handle this is to periodically (at least once a year) push out an update with nothing more than a new embedded mprov.

Do you specifically need your users to notify you as to when your provisioning profiles are expiring?

But in terms of reading the plist file:

[NSDictionary dictionaryWithContentsOfFile:@"path/to/file.plist"]

This also seems to be a previously answered question at:

Get the EXPIRATION date of a Provisioning Profile at Run-time?

but to reiterate the code:

- (NSString*) getExpiry{

NSString *profilePath = [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"];
// Check provisioning profile existence
if (profilePath)
{
// Get hex representation
NSData *profileData = [NSData dataWithContentsOfFile:profilePath];
NSString *profileString = [NSString stringWithFormat:@"%@", profileData];

// Remove brackets at beginning and end
profileString = [profileString stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""];
profileString = [profileString stringByReplacingCharactersInRange:NSMakeRange(profileString.length - 1, 1) withString:@""];

// Remove spaces
profileString = [profileString stringByReplacingOccurrencesOfString:@" " withString:@""];

// Convert hex values to readable characters
NSMutableString *profileText = [NSMutableString new];
for (int i = 0; i < profileString.length; i += 2)
{
NSString *hexChar = [profileString substringWithRange:NSMakeRange(i, 2)];
int value = 0;
sscanf([hexChar cStringUsingEncoding:NSASCIIStringEncoding], "%x", &value);
[profileText appendFormat:@"%c", (char)value];
}

// Remove whitespaces and new lines characters
NSArray *profileWords = [profileText componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

//There must be a better word to search through this as a structure! Need 'date' sibling to <key>ExpirationDate</key>, or use regex
BOOL sibling = false;
for (NSString* word in profileWords){
if ([word isEqualToString:@"<key>ExpirationDate</key>"]){
NSLog(@"Got to the key, now need the date!");
sibling = true;
}
if (sibling && ([word rangeOfString:@"<date>"].location != NSNotFound)) {
NSLog(@"Found it, you win!");
NSLog(@"Expires: %@",word);
return word;
}
}

}

return @"";
}

Renewing an expiring Enterprise provisioning profiles, and other aggravations

First thing that you want to do is delete all of those extra provisioning profiles that you created through trial and error. Just totally remove them from the organizer. The difference between developer provisioning profiles and distribution provisioning profiles is that developer profiles will only work on devices that are registered with that developer profile, meaning test devices. You would not be able to sign an app with a developer profile and then put it on any device, only devices that you have registered to work with that profile. In the distribution zone you will have app store distribution and Ad Hoc distribution. App store refers to the Apple App Store which you must submit your app to apple for that. Ad Hoc distribution allows developers who have enterprise accounts to distribute to any device via the internet or other methods.

I would need more information when you say that compile fails with distribution but generally speaking, you would click the product tab and then click on archive. When the archiving is complete and the archive window pops up, you would click on the button that says Distribution in the bottom right corner. You would then click on the Save for Enterprise or Ad-Hoc deployment option. You choose your distribution code signing identity when asked which identity to use and hit next. Here comes the tricky part: On the next section where you are choosing where to save the app, you click on the option, save for Enterprise distribution. There are two fields that need to be filled in here, the first is an application url, this is the exact url where you will be hosting the ipa file, for example http://www.somewebsiteyouown.com/myApplication.ipa
The second is the ApplicationTitle which will just be your app title: myApplication.
This process will generate for you a plist and an ipa file, you put thos both on the server and link to the plist from a button or link on a webpage. The plist is like the instructions on where the ipa file is and what to do with it.



Related Topics



Leave a reply



Submit