iOSアプリ開発の証明書周りがよくわかっていないので自分なりに整理してみた
iOSアプリの証明書周り、非常にわかりにくい。
開発時に毎回どうだったっけ?って忘れてしまうので、自分なりに整理してみました。
証明書周りの構成
証明書周りの構成は4つに分類されています。
- App ID
- 証明書
- 端末
- プロビジョニングファイル
developmentとdistribution
証明書やプロビジョニングファイルには、開発時に使用するdevelopmentと、リリース時に使用するdistributionの2つの種類があります。
- development
- 自分のxcodeで開発をして、実機にインストールする時などはdevelopment
- distribution
- アプリをarchiveして配信する場合はdistribution
App ID
App IDはアプリごとに発行するIDです。
xcodeのプロジェクト内のBundle IDと、このApp IDを合わせる必要があります。
このIDに対して、そのアプリ上で使用するサービスを選択します。(プッシュ通知や、Apple Payなど)
証明書
開発時にはdevelopment用の証明書を使用して、実機にインストールしたりします。
配信用にipaファイルを作成する場合は、production用の証明書が必要です。
この証明書を作る時に、キーチェーンを使って秘密鍵やらなにやらを用意する必要があります。
証明書作成後、Appleの管理画面からは証明書自体はDownloadできますが、秘密鍵はDownloadできませんので、必ず無くさないようにする必要があります。
※アプリ配信用の証明書の他にも、Push通知用の証明書など複数種類があります。
端末
Ad Hoc版の際にインストール可能な端末を指定するために、端末を登録する必要があります。
端末の登録には端末ごとに発行されているUDIDが必要です。
端末は最大で100件まで登録が可能。
端末を指定してDisableにすることは可能だが、削除することは基本的にできない。(100件登録してしまうと、新しい端末を登録できなくなってしまう。)
1年に1度更新のタイミングで、端末を整理することができ、そのタイミングのみ端末の削除が可能になる。
プロビジョニングファイル
プロビジョニングファイルは、下記のデータにひも付き、アプリごとに発行します。
- App ID
- 証明書
- 端末
プロビジョニングファイルがいろいろな情報を持っており、アプリをビルドする時にそのプロビジョニングファイルを指定してビルドさせます。
ただ、プロビジョニングファイルだけでビルドできてしまうと、セキュリティ的によろしくないため、プロビジョニングファイルに紐付いている証明書を持っていなければビルドができない、という仕様です。
また、プロビジョニングファイルが持っているApp IDと、ProjectのBundle IDが一致しないとビルドができません。
持っている情報が変わればプロビジョニングファイルも変わる
検証する端末が増えたりした時など、管理画面からプロビジョニングファイルの編集を行います。
この結果、新しいプロビジョニングファイルには新しいデータが書き込まれているため、古いプロビジョニングファイルと交換する必要があります。
よく、管理画面で端末を追加したのにインストールできない、というケースがありますが、これはビルド時のプロビジョニングファイルが変わっていない可能性が高いです。
Ad Hoc版
本番の証明書を使用して、限られた端末にのみインストールできるようにするものを、Ad Hoc版といいます。
Test flightやCrashlyticsで検証用のアプリを配信する際には、Ad Hoc版のプロビジョニングファイルを作成して指定する必要があります。
ものすごいざっくりですが、概念をまとめてみました。
【swift】Viewの一部を角丸にする
swiftで角丸のViewを作るには、layerのcornerRadiusを設定すれば簡単にできますが、これだと4隅すべてが角丸になってしまいます。
上だけを角丸にしたい時などには、一部だけ角丸のパスをUIBezierPathで作成し、CAShapeLayerに設定します。
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .grayColor() // 上だけ角丸にするViewを用意 let view1 = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) view1.backgroundColor = .greenColor() view.addSubview(view1) view1.center = view.center // TopLeft, TopRightを5px丸めたパスを生成 let maskPath = UIBezierPath(roundedRect: view1.frame, byRoundingCorners: [.TopLeft, .TopRight], cornerRadii: CGSize(width: 5, height: 5)) // CAShapeLayerを生成し、先ほど生成したパスをセットする let maskLayer = CAShapeLayer() maskLayer.path = maskPath.CGPath // 対象のViewのlayer.maskにCAShapeLayerをセットする view1.layer.mask = maskLayer } }

【swift】グラデーションを描画する
swiftでグラデーションを描画するには、CAGradientLayerを使います。
let startColor = UIColor(white: 0, alpha: 0).CGColor let endColor = UIColor(white: 0, alpha: 1).CGColor let layer = CAGradientLayer() layer.colors = [startColor, endColor] layer.frame = view.bounds view.layer.addSublayer(layer)

グラデーションをかけたい色を複数渡してあげるだけでした。簡単。
グラデーションの方向を変えたい場合は、startPointとendPointを設定します。
// 横方向 layer.startPoint = CGPoint(x: 1, y: 0.5) layer.endPoint = CGPoint(x: 0, y: 0.5) // 斜め layer.startPoint = CGPoint(x: 1, y: 0) layer.endPoint = CGPoint(x: 0, y: 1)


【swift】Viewに自分自身の大きさを定義して、動的なViewを正しくレイアウトする
動的に要素を並べるようなViewを作成した時に、AutoLayoutの設定の仕方で悩みました。
class CustomView: UIView { init() { super.init(frame: .zero) backgroundColor = .whiteColor() // 正方形のViewを左右に並べる let view1 = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) let view2 = UIView(frame: CGRect(x: 110, y: 0, width: 100, height: 100)) view1.backgroundColor = .blueColor() view2.backgroundColor = .greenColor() addSubview(view1) addSubview(view2) } }
このようにinitializeの中で動的に要素を作成しているViewを作成します。
このViewの中ではAutoLayoutは定義せずにCGRectで位置を設定しています。
CustomViewを表示してみる
このViewをViewControllerでaddSubviewしてあげます。
addしたCustomViewはAutoLayoutで中央揃えになるように設定します。
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .grayColor() let customView = CustomView() view.addSubview(customView) customView.translatesAutoresizingMaskIntoConstraints = false // customView自体には中央揃えになるようにAutoLayoutを設定 customView.centerYAnchor.constraintEqualToAnchor(view.layoutMarginsGuide.centerYAnchor).active = true customView.centerXAnchor.constraintEqualToAnchor(view.layoutMarginsGuide.centerXAnchor).active = true } }

ビルドしてみるとこんな感じです。
うまく中央揃えになりません。
また、CustomView自体の白背景部分が描画されていないため、CustomViewに大きさが無いことがわかります。
intrinsicContentSizeの設定
UIViewにはintrinsicContentSizeというCGSizeを返すメソッドが定義されており、そのサイズを自分自身のサイズと認識します。
ですので、先ほどのCustomViewにintrinsicContentSizeをoverrideさせます。
class CustomView: UIView { init() { super.init(frame: .zero) backgroundColor = .whiteColor() let view1 = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) let view2 = UIView(frame: CGRect(x: 110, y: 0, width: 100, height: 100)) view1.backgroundColor = .blueColor() view2.backgroundColor = .greenColor() addSubview(view1) addSubview(view2) } // 追加 override func intrinsicContentSize() -> CGSize { return CGSize(width: 210, height: 100) } }
これでCustomView自体は、幅210px、高さ100pxの要素だと認識するようになりました。
この状態でビルドしてみると

正しく中央揃えになり、CustomViewの白背景も描画されています。
今回の例はサイズを全て決め打ちで書いていますが、この辺りをちゃんと計算して算出するようにすれば、動的な要素も正しくレイアウトされるようになります。
【swift】ViewControllerとViewを分離させてViewControllerの記述を減らす
最近は、storyboardもxibも使わない方針で実装しているため、Viewを構築するのも全てコードで定義しています。
特に考えなければ、initializeの時に組み立ててしまうのですが、そうするとViewControllerとは関係のないコードが増えていき、可読性が悪くなります。
class ViewController: UIViewController { init() { super.init(nibName: nil, bundle: nil) // ここで組み立ててしまうとあっという間に行数が増えていく... addSubview(UIView()) addSubview(UIView()) } }
その変わりに、View自体を独自クラスにしてあげて、それをViewControllerで読み込むようにすれば、Viewの組み立てを分離できます。
ViewControllerにはloadViewというメソッドが定義されているので、それをoverrideして、独自に定義したViewクラスを設定します。
class ViewController: UIViewController { overide func loadView() { view = SampleView() } } class SampleView: UIView { init() { super.init(frame: .zero) // Viewの組み立てはここでしてしまう addSubview(UIView()) addSubview(UIView()) } }
【swift】UITableViewCellの選択した時の表示を変更する
selectionStyleを変更するだけです。
import UIKit class CustomCell: UITableViewCell { override func awakeFromNib() { super.awakeFromNib() // Initialization code selectionStyle = .None } }
【swift】コードでAutoLayout その1 - Visual Format Language
コードでAutoLayoutを記述します。
iOSにはVisual Format LanguageというAutoLayoutを直感的に定義できるフォーマットが用意されており、使い方さえ覚えてしまえばちょっとした制約であればサクッとコードで書けてしまいます。
使ってみる
とりあえず、AutoLayoutを適用するためのViewを用意してみます。
let wrapperView = UIView() wrapperView.backgroundColor = .redColor() wrapperView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(wrapperView)
この時、大事なポイントが二つあります。
1. translatesAutoresizingMaskIntoConstraints を falseにする
詳しくは理解していないですが、AutoLayoutを使用する場合は、昔からあるレイアウトシステムのAutoresizingMaskをfalseにする必要があります。
2. AutoLayoutの制約を定義する前にaddSubviewを実行する
Visual Format Languageで制約を設定する場合、superviewに対して位置を設定したりするため、制約を定義する前にviewに追加しておく必要があります。
制約の定義
制約の定義には、addConstraintsを使います。
let views = ["wrapperView": wrapperView] // 左右の位置をsuperviewとくっつける view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat( "|-0-[wrapperView]-0-|", options: .AlignAllTop, metrics: nil, views: views)) // 上下の位置をsuperviewとくっつける view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat( "V:|-0-[wrapperView]-0-|", options: .AlignAllTop, metrics: nil, views: views))
|-0-[wrapperView]-0-|この記述が、Visual Format Languageです。
|がsuperviewを表し、対象のviewは[]で囲みます。
V:という記述で縦の結びつきを表します。
viewsで渡したディクショナリから文字列の変数展開を行い、AutoLayoutが定義されます。
これで、画面いっぱいにwrapperViewが広がるようになりました。

とりあえず今日はここまで。