Corredor

ウェブ、プログラミングの勉強メモ。

iOS アプリのプロビジョニングプロファイルの有効期限をアプリ内で取得・表示する Swift コード

無料の Apple Developers Program アカウントを使っている場合、iOS にインストールした開発用アプリの有効期限は7日間で切れてしまう。

neos21.hatenablog.com

この有効期限までの残日数を、アプリ内で取得・表示させられないか調べてみた。

検証環境

アプリ内でプロビジョニングプロファイルの有効期限を知る方法

早速だが、以下のようなコードで、プロビジョニングプロファイルの有効期限を取得できる。

import UIKit

class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
  }
  
  // ココでは画面上に置いたボタンをタップした時に実行するよう設定した
  @IBAction func onTapBtn(_ sender: Any) {
    // embedded.mobileprovision ファイルを取得する
    guard let url = Bundle.main.url(forResource: "embedded", withExtension: "mobileprovision") else {
      print("ファイル取得失敗")
      return
    }
    
    // plist としてパースする際にゴミになる箇所をちぎるための処理
    guard let data = try? Data(contentsOf: url),
          let start = "<?xml".data(using: .utf8),
          let end = "</plist>".data(using: .utf8),
          let startRange = data.range(of: start),
          let endRange = data.range(of: end) else {
      print("ファイル準備失敗")
      return
    }
    
    // 余計な場所をちぎり plist から「ExpirationDate」キーの値を抜き出す
    let range = Range(uncheckedBounds: (lower: startRange.lowerBound, upper: endRange.upperBound))
    let body = data.subdata(in: range)
    guard let dictionary = try? PropertyListSerialization.propertyList(from: body, options: [], format: nil),
          let plist = dictionary as? [String: Any],
          let expireDate = plist["ExpirationDate"] as? Date else {
        print("plist 変換失敗")
        return
    }
    
    // ExpirationDate の値を日付形式に整形する
    let dateFormat = DateFormatter()
    dateFormat.locale = Locale.current
    dateFormat.timeZone = TimeZone.current
    dateFormat.dateFormat = "yyyy-MM-dd"
    print("期限日 (YYYY-MM-DD)", dateFormat.string(from: expireDate))  // 「2019-01-07」などが取れる
    
    // 現在日と比較して有効期限切れまでの残日数を計算する
    let calendar = NSCalendar.current
    let fromDate = calendar.startOfDay(for: Date())
    let toDate = calendar.startOfDay(for: expireDate)
    let components = calendar.dateComponents([.day], from: fromDate, to: toDate)
    print("残日数", components.day!)  // 「7」などが取れる
  }
}

このコードの大部分の元ネタは以下より。

Objective-C な以下のコードも参考になるかも。

やっていることは、

  1. アプリに同梱されているプロビジョニングプロファイル embedded.mobileprovision を取得する
  2. その中から plist (XML) 部分を抜き出す
  3. その中から ExpirationDate プロパティの値 (DateNSDate) を取得する

というのが主なモノ。

あとは表示用に整形したり、現在日との比較で有効期限切れまでの残日数を計算したりしている。

iOS シミュレータで動かした場合はプロビジョニングプロファイルが要らないので、print("ファイル取得失敗") 部分の return で抜けてしまう。

2つの日付を比較して日数を調べる方法

残日数の比較は、もう少し簡素なやり方もある。結果が小数になることに留意。

let span = expireDate.timeIntervalSinceNow
let daySpan = span / 60 / 60 / 24
print("残日数", daySpan)    // 6.99... などになる

他にも、人間が読みやすい形式に変換してくれるモノもあった。

let dateComponentsFormatter = DateComponentsFormatter()
dateComponentsFormatter.allowedUnits = [.day]
dateComponentsFormatter.maximumUnitCount = 1
print("残日数", dateComponentsFormatter.string(from: Date(), to: expireDate)!)  // "6d" などになる

有効期限の期間自体を知る方法

ちなみに、プロビジョニングプロファイルの有効期限の期間自体を知るには、ExpirationDate プロパティと同様に存在する、TimeToLive というプロパティを取得すれば良い。

let timeToLive = plist["TimeToLive"] as! Int
print("有効期間", timeToLive)  // 「7」が取れる

以上

今回のサンプルコードでは print() しているだけだが、結果を画面に置いたテキストボックスなどに表示するようにすれば、アプリ上でも確認できるようになる。

コレで開発中のアプリを入れっぱなしにしていて「あっ期限切れてた」ということがなくなるだろう。

[改訂新版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plus)

[改訂新版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plus)

[rakuten:book:18900452:detail]