GithubHelp home page GithubHelp logo

pseudomuto / retired Goto Github PK

View Code? Open in Web Editor NEW
4.0 2.0 3.0 71 KB

A simple framework to help recommend/force app updates and sunset old versions

License: MIT License

Swift 96.06% Objective-C 1.62% Ruby 2.32%

retired's Introduction

Retired (iOS)

Carthage compatible Version License Platform Tests

A simple framework to help recommend/force app updates and sunset old versions

Installation

Carthage

Add the following to your Cartfile:

github "pseudomuto/Retired" ~> 3.0

Cocoapods

Add this to your Podfile:

pod "Retired", "~> 3.0"

Swift Package Manager

Add the dependency in your Package.swift file:

import PackageDescription

let package = Package(
  ...
  ...
  dependencies: [
    .Package(url: "https://github.com/pseudomuto/Retired.git", majorVersion: 3)
  ],
  ...
  ...
)

Usage

The Versions File

You'll need to host a JSON file on a server somewhere that defines options like whether or not an update is required, recommended or not necessary.

The file also defines the messaging to be displayed in each case. For example, if the user has version 1.0 installed (and the file below is used), when the you call Retire.check the supplied message in the completion block will be the forced one.

If they're running 1.1, you'd get the recommended message, and if they're running 2.0 no update would be required.

Here's an example of a versions file:

{
  "messaging": {
    "forced": {
      "title": "App Update Required",
      "message": "A new version of the app is available. You need to update now",
      "continueButtonText": "Let's do this"
    },
    "recommended": {
      "title": "App Update Available",
      "message": "A new version is available. Want it?",
      "continueButtonText": "I want it",
      "cancelButtonText": "No thanks"
    }
  },
  "versions": [
    { "version": "1.0", "policy": "force" },
    { "version": "1.1", "policy": "recommend" },
    { "version": "2.0", "policy": "none" }
  ]
}

There are two types of objects here; message and version.

message

  • title - The title of the alert (e.g. New Version Available)
  • message - The message to be displayed (e.g. There's a new version available)
  • continueButtonText - The label for the button that links to the app store
  • cancelButtonText - The (optional) label for the cancel button (intended for recommended updates only)

version

  • version - The version of the app (pulled from CFBundleShortVersionString)
  • policy - One of force, recommend or none

Checking Status in Your App

I don't wanna tell you how to handle displaying alerts or anything, but here's what I did in the example app (if you open the workspace you'll see it in AppDelegate.swift).

First, I made an extension on Message

extension Message {
  func presentInController(controller: UIViewController?) {
    let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
    alert.addAction(UIAlertAction(title: continueButtonText, style: .Default, handler: goToAppStore))

    if cancelButtonText != nil {
      alert.addAction(UIAlertAction(title: cancelButtonText, style: .Cancel, handler: nil))
    }

    controller?.presentViewController(alert, animated: true, completion: nil)
  }

  private func goToAppStore(action: UIAlertAction) {
    UIApplication.sharedApplication().openURL(iTunesURL)
  }
}

Then, in applicationDidFinishLaunching:withOptions, I configured Retired with the URL to the versions file:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  let versionURL              = NSURL(string: "https://example.com/versions.json")!
  let intervalBetweenRequests = 60 * 60 * 24 // one day between recommended app updates

  Retired.configure(versionURL, suppressionInterval: intervalBetweenRequests)
  return true
}

Finally, in applicationDidBecomeActive, I query the status and show a message if necessary:

func applicationDidBecomeActive(application: UIApplication) {
  // you should catch the error in production apps
  try! Retired.check() { updateRequired, message, error in
    guard updateRequired else { return }

    // handle error (non 200 status or network issue)

    if let message = message {
      message.presentInController(application.keyWindow?.rootViewController)
    }
  }
}

LICENSE

Copyright (c) 2016 pseudomuto [email protected]

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

retired's People

Contributors

pseudomuto avatar karlhungus avatar

Stargazers

 avatar Sally Ahmed avatar Francesco Dulio avatar Matteo Crippa avatar

Watchers

James Cloos avatar  avatar

retired's Issues

displaying on main thread, success and failure

In the instructions you might want to tell people to dispatch display on the main thread:

       dispatch_async(dispatch_get_main_queue()) {
          message.presentInController(rootViewController)
        }

I don't have conclusive proof that this is a problem (haven't seen an error, but am told by someone who knows ios better than me ๐Ÿ˜„ @hweetty)

We also ran into a problem where we only want to load more of the app further if retired says ๐Ÿ‘ , but don't want to if it fails. This means that we dispatch requests to the server for data before retired has finished so we can display our main screen, and we run into ๐Ÿ” and ๐Ÿณ problems where we'd like to force update but retired happens after that initial load (https://github.com/Shopify/frenzy-ios/pull/351).

So ideally we'd see something like this

1 . Load app
2. retired check

  1. none -> continue
  2. forced -> do alert display and ๐Ÿ’ฉ the ๐Ÿ›
  3. recommended -> display alert and whatnot

Pros:

  • you can pretty be sure that people will be forced to update without doing your code
    Cons:
  • slower

I'll try to pr these if you think they make sense.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.