Training
Learning path
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Important
Visual Studio App Center is scheduled for retirement on March 31, 2025. While you can continue to use Visual Studio App Center until it is fully retired, there are several recommended alternatives that you may consider migrating to.
App Center Distribute will let your users install a new version of the app when you distribute it via App Center. With a new version of the app available, the SDK will present an update dialog to the users to either download or postpone the new version. Once they choose to update, the SDK will start to update your application.
Note
There are a few things to consider when using in-app updates:
Note
In the 4.0.0
version of App Center breaking changes were introduced. Follow the Migrate to App Center SDK 4.0.0 and higher section to migrate App Center from previous versions.
Important
App Center SDK doesn't support multiple window apps that were introduced in iOS 13.
Follow the Get started section if you haven't configured the SDK in your application.
The App Center SDK is designed with a modular approach – you only need to integrate the modules of the services that you're interested in.
If you're integrating App Center into your app via Cocoapods, add the following dependency to your podfile and run pod install
.
pod 'AppCenter/Distribute'
Add the following dependency to your Cartfile
to include App Center Distribute.
# Use the following line to get the latest version of App Center
github "microsoft/appcenter-sdk-apple"
# Use the following line to get the specific version of App Center
github "microsoft/appcenter-sdk-apple" ~> X.X.X
Run carthage update
.
Open your application target's General settings tab. Drag and drop the AppCenterDistribute.framework file from the Carthage/Build/iOS folder to the Linked Frameworks and Libraries section in XCode.
Drag and drop AppCenterDistributeResources.bundle from AppCenterDistribute.framework into XCode's Project Navigator.
A dialog will appear, make sure your app target is checked. Then click Finish.
https://github.com/microsoft/appcenter-sdk-apple.git
.If you don't want to use Cocoapods, you can integrate the modules by copying the binaries into your project. Follow the steps below:
Note
App Center SDK supports the use of XCframework
. If you want to integrate XCframeworks into your project, download the AppCenter-SDK-Apple-XCFramework.zip from the releases page and unzip it. Resulting folder contents aren't platform-specific, instead it contains XCframeworks for each module. They can be integrated the same way as usual frameworks, as described below.
Download the App Center SDK frameworks provided as a zip file.
Unzip the file and you'll see a folder called AppCenter-SDK-Apple/iOS that contains different frameworks for each App Center service. The framework called AppCenter
is required in the project as it contains code that's shared between the different modules.
[Optional] Create a subdirectory for 3rd-party libraries.
Open Finder and copy the unzipped AppCenter-SDK-Apple/iOS folder into your project's folder at the location where you want it.
Add the SDK framework to the project in Xcode:
App Center only uses the specific modules you invoke in your application. You must explicitly call each of them when starting the SDK.
Open the project's AppDelegate.m file in Objective-C or AppDelegate.swift file in Swift and add the following import statements:
@import AppCenter;
@import AppCenterDistribute;
import AppCenter
import AppCenterDistribute
Add Distribute
to your start:withServices:
method to start App Center Distribute service.
Insert the following line to start the SDK in the project's AppDelegate.m class for Objective-C or AppDelegate.swift class for Swift in the didFinishLaunchingWithOptions
method.
[MSACAppCenter start:@"{Your App Secret}" withServices:@[[MSACDistribute class]]];
AppCenter.start(withAppSecret: "{Your App Secret}", services: [Distribute.self])
Make sure you've replaced {Your App Secret}
in the code sample above with your App Secret. Also check out the Get started section if you haven't configured the SDK in your application.
URL types
by clicking the '+' button next to "Information Property List" at the top. If Xcode displays your Info.plist as source code, refer to the tip below.Item 0
) and change the type to Dictionary.Item 0
, add a URL Schemes
key and change the type to Array.URL Schemes
key, add a new entry (Item 0
).URL Schemes
> Item 0
, change the value to appcenter-{APP_SECRET}
and replace {APP_SECRET}
with the App Secret of your app.Tip
If you want to verify that you modified the Info.plist correctly, open it as source code. It should contain the following entry with your App Secret instead of {APP_SECRET}
:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>appcenter-{APP_SECRET}</string>
</array>
</dict>
</array>
By default, Distribute uses a public distribution group. If you want to use a private distribution group, you'll need to explicitly set it via updateTrack
property.
MSACDistribute.updateTrack = MSACUpdateTrackPrivate;
Distribute.updateTrack = .private
Note
The default value is UpdateTrack.public
. This property can only be updated before the AppCenter.start
method call. Changes to the update track aren't persisted when the application process restarts, thus if the property isn't always updated before the AppCenter.start
call, it will be public, by default.
After this call, a browser window will open up to authenticate the user. All the subsequent update checks will get the latest release on the private track.
If a user is on the private track, it means that after the successful authentication, they'll get the latest release from any private distribution groups they're a member of. If a user is on the public track, it means that they'll get the latest release from any public distribution group.
By default, the SDK automatically checks for new releases:
If you want to check for new releases manually, you can disable automatic check for update. To do this, call the following method before the SDK start:
[MSACDistribute disableAutomaticCheckForUpdate];
Distribute.disableAutomaticCheckForUpdate()
Note
This method must be called before the AppCenter.start
method call.
Then you can use the checkForUpdate
API which is described in the following section.
[MSACDistribute checkForUpdate];
Distribute.checkForUpdate()
This sends a request to App Center and display an update dialog in case there's a new release available.
Note
A manual check for update call works even when automatic updates are enabled. A manual check for update is ignored if another check is already being done. The manual check for update won't be processed if the user has postponed updates (unless the latest version is a mandatory update).
You can easily provide your own resource strings if you want to localize the text displayed in the update dialog. Look at this strings file. Use the same string name/key and specify the localized value to be reflected in the dialog in your own app strings files.
You can customize the default update dialog's appearance by implementing the DistributeDelegate
protocol. You need to register the delegate before starting the SDK as shown in the following example:
[MSACDistribute setDelegate:self];
Distribute.delegate = self;
Here is an example of the delegate implementation that replaces the SDK dialog with a custom one:
- (BOOL)distribute:(MSACDistribute *)distribute releaseAvailableWithDetails:(MSACReleaseDetails *)details {
// Your code to present your UI to the user, e.g. an UIAlertController.
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:@"Update available."
message:@"Do you want to update?"
preferredStyle:UIAlertControllerStyleAlert];
[alertController
addAction:[UIAlertAction actionWithTitle:@"Update"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
[MSACDistribute notifyUpdateAction:MSACUpdateActionUpdate];
}]];
[alertController
addAction:[UIAlertAction actionWithTitle:@"Postpone"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[MSACDistribute notifyUpdateAction:MSACUpdateActionPostpone];
}]];
// Show the alert controller.
[self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
return YES;
}
func distribute(_ distribute: Distribute, releaseAvailableWith details: ReleaseDetails) -> Bool {
// Your code to present your UI to the user, e.g. an UIAlertController.
let alertController = UIAlertController(title: "Update available.",
message: "Do you want to update?",
preferredStyle:.alert)
alertController.addAction(UIAlertAction(title: "Update", style: .cancel) {_ in
Distribute.notify(.update)
})
alertController.addAction(UIAlertAction(title: "Postpone", style: .default) {_ in
Distribute.notify(.postpone)
})
// Show the alert controller.
self.window?.rootViewController?.present(alertController, animated: true)
return true;
}
In case you return YES
/true
in the above method, your app should obtain user's choice and message the SDK with the result using the following API.
// Depending on the user's choice, call notifyUpdateAction: with the right value.
[MSACDistribute notifyUpdateAction:MSACUpdateActionUpdate];
[MSACDistribute notifyUpdateAction:MSACUpdateActionPostpone];
// Depending on the user's choice, call notify() with the right value.
Distribute.notify(.update);
Distribute.notify(.postpone);
If you don't call the above method, the releaseAvailableWithDetails:
-method will repeat whenever your app is entering to the foreground.
In cases when the SDK checks for updates and doesn't find any updates available newer than the one currently used, a distributeNoReleaseAvailable:
from MSACDistributeDelegate
delegate callback is invoked. This allows you to execute custom code in such scenarios.
Here are examples which show how to display alert UI when no updates are found:
- (void)distributeNoReleaseAvailable:(MSACDistribute *)distribute {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil
message:NSLocalizedString(@"No updates available", nil)
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDefault handler:nil]];
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
}
func distributeNoReleaseAvailable(_ distribute: Distribute) {
let alert = UIAlertController(title: nil, message: "No updates available", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.window?.rootViewController?.present(alert, animated: true)
}
You can enable and disable App Center Distribute at runtime. If you disable it, the SDK won't provide any in-app update functionality but you can still use Distribute service in App Center portal.
[MSACDistribute setEnabled:NO];
Distribute.enabled = false
To enable App Center Distribute again, use the same API but pass YES
/true
as a parameter.
[MSACDistribute setEnabled:YES];
Distribute.enabled = true
The state is persisted in the device's storage across application launches.
Note
This method must only be used after Distribute
has been started.
You can also check if App Center Distribute is enabled or not:
BOOL enabled = [MSACDistribute isEnabled];
var enabled = Distribute.enabled
Note
This method must only be used after Distribute
has been started, it will always return false
before start.
If in private mode, App Center Distribute will open up its UI/browser at application start. While this is an expected behavior for your end users, it could be disruptive for you during the development stage of your application. We don't recommend initializing Distribute
for your DEBUG
configuration.
#if DEBUG
[MSACAppCenter start:@"{Your App Secret}" withServices:@[[MSACAnalytics class], [MSACCrashes class]]];
#else
[MSACAppCenter start:@"{Your App Secret}" withServices:@[[MSACAnalytics class], [MSACCrashes class], [MSACDistribute class]]];
#endif
#if DEBUG
AppCenter.start(withAppSecret: "{Your App Secret}", services: [Analytics.self, Crashes.self])
#else
AppCenter.start(withAppSecret: "{Your App Secret}", services: [Analytics.self, Crashes.self, Distribute.self])
#endif
Implement the DistributeDelegate
protocol and register the delegate as shown in the following example:
[MSACDistribute setDelegate:self];
Distribute.delegate = self;
The distributeWillExitApp:
delegate method will be called right before the app gets terminated for the update installation:
- (void)distributeWillExitApp:(MSACDistribute *)distribute {
// Perform the required clean up here.
}
func distributeWillExitApp(_ distribute: Distribute) {
// Perform the required clean up here.
}
Note
For in-app updates to work, an app build should be downloaded from the link. It won't work if installed from an IDE or manually.
The in-app updates feature works as follows:
This feature will ONLY work with builds that are distributed using App Center Distribute service. It won't work when the debugger is attached or if the iOS Guided Access feature is turned on..
Once you integrate the SDK, build a release version of your app and upload it to App Center, users in that distribution group will be notified for the new release via an email.
When each user opens the link in their email, the application will be installed on their device. It's important that they use the email link to install the app - App Center Distribute doesn't support in-app-updates for apps that have been installed from other sources (e.g. downloading the app from an email attachment). When an application is downloaded from the link, the SDK saves important information from cookies to check for updates later, otherwise the SDK doesn’t have that key information.
If the application sets the track to private, a browser will open to authenticate the user and enable in-app updates. The browser won't open again as long as the authentication information remains valid even when switching back to the public track and back to private again later. If the browser authentication is successful, the user is redirected back to the application automatically. If the track is public (which is the default), the next step happens directly.
SFSafariViewController
will open within the app to authenticate the user. It will close itself automatically after the authentication succeeded.A new release of the app shows the in-app update dialog asking users to update your application if it's:
CFBundleShortVersionString
orCFBundleShortVersionString
but a higher value of CFBundleVersion
.Tip
If you upload the same ipa a second time, the dialog will NOT appear as the binaries are identical. If you upload a new build with the same version properties, it will show the update dialog. The reason for this is that it's a different binary.
You need to upload release builds (that use the Distribute module of the App Center SDK) to the App Center Portal to test in-app updates, increasing version numbers every time.
CFBundleShortVersionString
) of your app.Tip
Have a look at the information on how to utilize App Center Distribute for more detailed information about Distribution Groups etc. While it's possible to use App Center Distribute to distribute a new version of your app without adding any code, adding App Center Distribute to your app's code will result in a more seamless experience for your testers and users as they get the in-app update experience.
The App Center SDK uses swizzling to improve its integration by forwarding itself some of the application delegate's methods calls. Method swizzling is a way to change the implementation of methods at runtime. If for any reason you don't want to use swizzling (e.g. because of a specific policy) then you can disable this forwarding for all App Center services by following the steps below:
AppCenterAppDelegateForwarderEnabled
key and set the value to 0
. This disables application delegate forwarding for all App Center services.openURL
callback in the project's AppDelegate
file.- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// Pass the url to MSACDistribute.
return [MSACDistribute openURL:url];
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
// Pass the URL to App Center Distribute.
return Distribute.open(url)
}
Training
Learning path
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization