1. Help Center
  2. Phrase Over the Air (OTA)

iOS SDK Installation Instructions

Learn how to install the Over the Air SDK for iOS.


Phrase Over the Air for iOS lets you update translations in your iOS app without having to release it every single time.

By including our SDK, your app will check for updated translations in Phrase regularly and download them in the background.

Install the SDK

You can install the SDK manually, via Swift Package Manager, Carthage or Cocoa Pods:

Swift Package Manager

To install the SDK as a Swift Package Manager Package, add the public repository URL (https://github.com/phrase/ios-sdk/). Xcode will handle everything else automatically.


Add the following line into your Cartfile:

binary "https://raw.githubusercontent.com/phrase/ios-sdk/master/PhraseSDK.json" ~> 3.0.0

Run carthage update and add the PhraseApp.framework  to your project by following the steps mentioned in the Carthage documentation.

Cocoa Pods

Add the following line into your Podfile:

pod 'PhraseSDK'

Run pod install for installing Phrase. If you are new to CocoaPods read the Getting Started guide for further instructions.

Manual Installation

  1. Download the latest release from https://github.com/phrase/ios-sdk/releases 
  2. Add PhraseSDK.framework in Xcode as linked binary to your target.
  3. The Apple store will reject your app if it includes simulator binaries. Therefore, a script to strip the extra binaries needs to be run before you upload the app. To do this, go to Build Phases and add a Run Script section by clicking the + symbol. Copy and paste the following script:
    for ARCH in $ARCHS
    lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
    rm "${EXTRACTED_ARCHS[@]}"


Import PhraseSDK:

import PhraseSDK

Initialize the SDK by calling the following code:

  distributionID: <Distribution ID>,
environmentSecret: <Environment Secret>

To update your localization files simply call Phrase.shared.updateTranslations() 

Note: This method will raise an exception if you did not set up the SDK properly

We recommend to simply call both functions within your AppDelegate in the applicationDidFinishLaunchingWithOptions  method.


Integrate the SDK into your Objective-C application:

@import PhraseSDK;

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
[[Phrase shared] setDebugMode:true]; // Optional

[[Phrase shared] setupWithDistributionID:@"Your Distribution ID"
environmentSecret:@"Your Environment Secret"];

// OR:
// [[Phrase shared] setupWithDistributionID:@"Your Distribution ID"
// environmentSecret:@"Your Environment Secret"
// timeout:10];

// Update translations using callback block:
[[Phrase shared] updateTranslationsWithCompletionHandler:^(BOOL updated, NSError* error){
NSLog(@"Updated: %@", updated ? @"true" : @"false");

if (error) {
NSLog(@"Domain: %@ Code: %ld Message: %@", error.domain, (long)error.code, error.localizedDescription);
} else {
NSLog(@"No error");

// Translate via bundle proxy:
NSString *translation = NSLocalizedString(@"layouts.application.about", @"");
NSLog(@"NSLocalizedString via bundle proxy: %@", translation);

// OR:
// Translate using fallback method:
NSString *otherTranslation = [[Phrase shared]
localizedStringForKey:@"layouts.application.about" value:NULL table:NULL];
NSLog(@"Phrase.shared localizedStringForKey: %@", otherTranslation);

// OR:
// [[Phrase shared] updateTranslationsWithCompletionHandler:NULL]; // ignore result and errors (not recommended)

// [...] Your other code

return YES;

Disable Swizzling

  • In case you want to disable swizzling you can set PhraseSDKMainBundleProxyDisabled to YES  in Info.plist 
  • Please note: When swizzling is disabled, the updated translations will not be displayed anymore. However, the translation will still be synced if updateTranslations is called and the user can access them with the method Phrase.localizedString().

App version handling

To determine which release should be returned the SDK requires a semantic version of the app. Otherwise the translations will not be updated. The SDK tries to get a semantic version the following way:

  • CFBundleShortVersionString  will be used if it is semantic 
  • If not, it uses CFBundleVersion if it is semantic
  • If both are not semantic it uses a combination (CFBundleShortVersionString.CFBundleVersion )

In case CFBundleShortVersionString  is missing completely or we are unable to create a semantic version together with CFBundleVersion the SDK throws PhraseSetupError.appVersionNotSemantic 


In case you want to handle successful translation updates you can attach a callback handler:

Phrase.shared.updateTranslations { result in
            switch result {
            case .success(let updated):
            case .failure:

Making updates visible

Usually, the updated translations will be automatically visible to the user the next time app launches. If you want to enforce the new translations to be visible immediately, you need to handle this yourself, e.g. by reloading the ViewController on a successful callback:

func reloadRootViewController() {
  DispatchQueue.main.async {
    let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    appDelegate.window?.rootViewController = storyboard.instantiateInitialViewController()

Note: This does not work for Storyboards

Debug Mode

If you need further information you can enable the debug mode to get additional logging of the PhraseSDK.framework  into the console:
Phrase.shared.debugMode = true 

Set timeout for requests

You can set a timeout for the requests against Phrase by calling:

  distributionID: <Distribution ID>,
  environmentSecret: <Environment Secret>,
  timeout: <Double>

The default timeout is 10 seconds.

Note: Connections that are taking longer than 10 seconds will be closed by our servers.

Provide manual language override

In case you don't want to use the system language as the locale, you can set a different locale in the init  call. The locale code needs to be present in a release from Phrase:

distributionID: <Distribution ID>,
environmentSecret: <Environment Secret>,
timeout: <Double>, // must be set when using localeOverride (default is 10 seconds)
localeOverride: <String>


In case new translations cannot be fetched from Phrase via the SDK we will always use the latest translation files that the installation received. If the App never received new files from Phrase it will use the compiled translation files of your app. This prevents errors in case of any technical difficulties or networking errors. Therefore we recommend keeping your translation files that are compiled into the app up to date with every release.


The SDK will communicate with the Phrase Over the Air service in order to check for updates and includes the following details with each request:

  • Device identifier (e.g. "F3AFCB10-80A2-84CB-94C0-27F5EF58876D". Unique for this app and therefore does not allow tracking a specific device.)
  • App version (e.g. "1.2.0")
  • Last update of the translation file (e.g. "1542187679")
  • SDK version (e.g. "1.0.0")
  • Locale (e.g. "de-DE")
  • File format (e.g. "strings")
  • Client (e.g. "ios")
  • Distribution ID (ID of your distribution in Phrase)
  • Environment secret (to distinguish between development from production)


The SDK is closed source and can thus not be viewed or modified. We do provide the possibility for audits in case this is a requirement of your organization. Please contact us for more details on code audits.


Translations are not updated

  • Confirm that the distribution id and environment secret are correct.
  • Check whether you created a release on Phrase for your current app version
  • Updated translations are visible automatically after the next app launch. Try reloading the ViewController to make changes appear immediately.

The wrong version of translations are used

  • Check on Phrase whether you do have a release with the latest translations and the current app version.