Skip to content

Latest commit

 

History

History
241 lines (177 loc) · 9.73 KB

README.md

File metadata and controls

241 lines (177 loc) · 9.73 KB

Prince of Versions

Bitrise GitHub CocoapodsCarthage compatible Swift Package Manager compatible Cocoapods platforms

PoV

Library checks for updates using configuration from some resource.

Features

  • Load update configuration from network resource
  • Use predefined parser for parsing update configuration in JSON format
  • Make asynchronous loading and use callback for notifying result

Requirements

  • iOS 11.0+
  • macOS 10.13+
  • Xcode 14.0+

Installation

The easiest way to use Prince of versions in your project is using the CocaPods package manager.

CocoaPods

See installation instructions for CocoaPods if not already installed

To integrate the library into your Xcode project specify the pod dependency to your Podfile:

platform :ios, '11.0'
use_frameworks!

pod 'PrinceOfVersions'

or

platform :osx, '10.13'
use_frameworks!

pod 'PrinceOfVersions'

run pod install

pod install

Carthage

For the Carthage installation and usage instruction, you can check official quick start documentation.

To integrate the library into your Xcode project, specify it in your Cartfile:

github "infinum/ios-prince-of-versions"

Run carthage update.

Swift Package Manager

To install Prince of Versions from the Swift Package Manager, you should:

For more information, check Swift Package Manager .

JSON File

For JSON file details and formatting, read JSON specification.

Usage

Loading from network resource

Getting all data

  let princeOfVersionsURL = URL(string: "https://pastebin.com/raw/0MfYmWGu")!

  PrinceOfVersions.checkForUpdates(
      from: princeOfVersionsURL,
      completion: { [unowned self] response in
          switch response.result {
          case .success(let updateResultData):
              print("Update version: \(updateResultData.updateVersion)")
              print("Installed version: \(updateResultData.updateInfo.installedVersion)")
              print("Update status: \(updateResultData.updateStatus)")
          case .failure:
              // Handle error
              break
          }
      }
  )

Request cache policy

When checking for updates, be it for AppStore or other sources, you can provide a cachePolicy parameter. The cachePolicy parameter determines which request cache policy will be used for network requests.

The initial value for the default URLSession configuration uses .useProtocolCachePolicy, which shouldn't be the default behavior for Prince of Versions; we want to refresh the data from the server every time. That's why we defaulted the value to .reloadIgnoringLocalCacheData. If you want to change the default behavior, you can always provide a different cache policy that suits your needs.

Adding-requirements

For each requirement key listed in a configuration, there should exist a requirement check closure. If you don't provide it, the requirement will be considered as not met, and the whole configuration will be discarded. However, if you provide requirement check, but JSON doesn't contain requirement key for your check, the check will be ignored.

If the JSON contains required_os_version key under requirements, the library itself will handle checking if that requirement is met. You don't need to provide a closure.

Here is the example of how to add requirement check closures.

let options = PoVRequestOptions()

options.addRequirement(key: "region") { (value) -> Bool in
    guard let value = value as? String else { return false }
    // Check OS localisation
    return value == "hr"
}

options.addRequirement(key: "bluetooth") { (value) -> Bool in
    guard let value = value as? String else { return false }
    // Check device bluetooth version
    return value.starts(with: "5")
}

let princeOfVersionsURL = URL(string: "https://pastebin.com/raw/0MfYmWGu")!

PrinceOfVersions.checkForUpdates(from: princeOfVersionsURL, options: options, completion: { [unowned self] response in
    switch response.result {
    case .success(let updateResultData):
        print("Update version: \(updateResultData.updateVersion)")
        print("Installed version: \(updateResultData.updateInfo.installedVersion)")
        print("Update status: \(updateResultData.updateStatus)")
    case .failure:
        // Handle error
        break
    }
})

If you consider following JSON example and requirement checks added in the example above, the first configuration will be considered as not appropriate since requirement check for free-memory is not defined. However, all requirements in the second configuration are met and its values will be returned.

...
      {
         "required_version":"1.2.3",
         "last_version_available":"1.9.0",
         "notify_last_version_frequency":"ALWAYS",
         "requirements":{
            "required_os_version":"8.0.0",
            "region":"hr",
            "bluetooth":"5.0",
            "free-memory":"80MB"
         },
      },
      {
         "required_version":"1.2.3",
         "last_version_available":"2.4.5",
         "notify_last_version_frequency":"ALWAYS",
         "requirements":{
            "required_os_version":"12.1.2",
            "region":"hr",
            "bluetooth":"5.0"
         },
      }
...

Automatic check with data from the App Store

If you don't want to manage the JSON configuration file required by checkForUpdates, you can use checkForUpdateFromAppStore. This method will automatically get your app BundleID and it will return version info fetched from the App Store.

However, updateStatus result can only assume values UpdateStatus.noUpdateAvailable and UpdateStatus.newUpdateAvailable. It is not possible to check if update is mandatory by using this method and data provided by the AppStore.

PrinceOfVersions.checkForUpdateFromAppStore(
    trackPhaseRelease: false,
    notificationFrequency: .once,
    completion: { result in
        switch result {
        case .success(let appStoreResult):
            print("Update version: \(appStoreResult.updateVersion)")
            print("Installed version: \(appStoreResult.updateInfo.installedVersion)")
            print("Update status: \(appStoreResult.updateStatus)")
        case .failure:
            // Handle error
        }
})

It is possible to define update notification frequency with the parameter notificationFrequency. If you set the parameter value to NotificationType.once, only the first time this methods is called, it will return UpdateStatus.newUpdateAvailable if a new version exists, every subsequent call it will return UpdateStatus.noUpdateAvailable for that specific version. If described behaviour doesn't suit your needs, you can always set this parameter to NotificationType.always and have updateStatus as UpdateStatus.newUpdateAvailable when a new version is available.

Multiple targets

If your application has multiple targets you might need more than one JSON configuration file. If that is the case, do not forget to set a different URL for each target.

Security certificate pinning

If you use certificate pinning for secure communication with the server holding your JSON version file, put the certificate in the app Resource folder (make sure that the certificate has one these extensions: ".cer", ".CER", ".crt", ".CRT", ".der", ".DER"). Prince Of Versions will look for all the certificates in the main bundle. Then set the shouldPinCertificates parameter to true in the loadConfiguration method call.

let url = URL(string: "https://pastebin.com/raw/0MfYmWGu")
PrinceOfVersions.checkForUpdates(from: url, shouldPinCertificates: true) { (response) in
    switch response.result {
    case .success(let result):
        if let latestVersion = result.updateInfo.latestVersion {
            print("Is minimum version satisfied: ", latestVersion)
        }
    case .failure(let error):
        print(error.localizedDescription)
    }
}

Privacy

PrinceOfVersions does not collect any user data. We have provided a privacy manifest file that can be included in your app.

Contributing

Feedback and code contributions are very much welcome. Just make a pull request with a short description of your changes. By making contributions to this project you give permission for your code to be used under the same license.

Credits

Maintained and sponsored by Infinum.