【fastlane】1プロジェクトに複数アプリの入っている場合のメタデータ管理
1つのプロジェクトで複数アプリをリリースしている場合のメタデータ管理方法です。
複数アプリが全く同じメタデータならいいのですが、アイコンやスクリーンショットを別々にする場合少し工夫をする必要があります。
fastlaneの設定方法はこちらをご参照下さい。
複数アプリ対応
まずは1アプリに対応します。
プロジェクトのルートで以下コマンドを実行します。
fastlane init
アプリのメタデータが以下のような構成でダウンロードされます。
2つ目以降のアプリは以下のように別フォルダを指定してダウンロードします。
fastlane deliver download_screenshots --app_identifier com.example.other --screenshots_path fastlane/screenshots_other_app fastlane deliver download_metadata --app_identifier com.example.other --metadata_path fastlane/metadata_other_app
これで別アプリのメタデータがフォルダに保存されます。
別アプリへのメタデータのアップロードは以下のようにオプション付ける事で実現できます。
fastlane deliver --app_identifier com.example.other --screenshots_path fastlane/screenshots_other_app --metadata_path fastlane/metadata_other_app
上コマンドはFastfileに登録しておけば簡単に実行できるようになります。
fastlane update_metadata_other_app
platform :ios do lane :update_metadata_other_app do deliver( app_identifier: 'com.example', screenshots_path: 'fastlane/screenshots_other_app', metadata_path: 'fastlane/metadata_other_app', ) end end
InAppPurchase用ライブラリ、RMStoreを使ってみる
RMStoreというiPhoneのアプリ内課金を楽にしてくれるライブラリを使ってみました。
インストール
インストールはcocoapodsを使います。
pod 'RMStore'
使い方
商品情報は以下のように取得します。
引数にproductIdを渡せばSKProductの配列が返ってきます。
let productIds = ["com.example.item"] RMStore.default().requestProducts(productIds, success: { products, invalidIdentifiers in self?.products = products as? [SKProduct] }, failure: { error in })
購入処理はaddPaymentメソッドを使います。
レシートチェックなどは引数で渡されるSKPaymentTransactionクラスのインスタンスを使います。
RMStore.default().addPayment("com.example.item", success: { transaction in if transaction?.transactionState != .purchased { return } }, failure: { transaction, error in })
リストア処理は以下の通りです。
購入履歴が引数として渡されるので、それを使って購入したかの判定をします。
RMStore.default().restoreTransactions(onSuccess: { [weak self] transactions in if let transactions = (transactions as? [SKPaymentTransaction]), transactions.map({ $0.payment.productIdentifier }).contains("com.example.com") { print("商品情報がありました") } else { print("商品情報が見つかりませんでした") } }, failure: { error in })
今回は試していないのですが、コンテンツダウンロードも対応しているようです。
【iOS】iTunesConnectのSalesデータ取得プログラムを動かす【新方式に対応】
iTunesConnectの売上やダウンロード数などのデータを取得するプログラムに関する話です。
今まではiTunesConnectのSalesデータをAutoIngestion Toolというものを使って取得できました。
しかしこのツールは非推奨になり、2016年12月で停止してしました。
AppleからはReporterというツールを使うよう通知があったので今回はそれを試してみました。
ダウンロード
ダウンロードは下ページのSetup
にあるダウンロードリンクから行います。
ダウンロードすると、Reporter.jar
とReporter.properties
の2つのファイルが入っています。
Reporter.jar
が実際にデータを取得するプログラムで、Reporter.properties
はユーザー情報を書くファイルです。
Salesデータの取得方法
まずは認証情報を記入します。
Reporter.properties
を開くと以下のようになっているので、userIDとpasswordを埋めます。
userID = password = Mode=Robot.xml SalesUrl=https://reportingitc-reporter.apple.com/reportservice/sales/v1 FinanceUrl=https://reportingitc-reporter.apple.com/reportservice/finance/v1
入力が終わったらReporter.jarを使ってSalesデータを取得します。
java -jar Reporter.jar p=Reporter.properties Sales.getReport [vendor id], Sales, Summary, Daily, 20161201
vendor idは以下コマンドで取得する事ができます。
java -jar Reporter.jar p=[properties file] Sales.getVendors
コマンドは以下のようなXML返します。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Output> <Message>Successfully downloaded xxxxxxx.txt.gz</Message> </Output>
xxxxxxx.txt.gzファイルには各アプリのダウンロード数などのデータが入っています。
形式は以下のように1行1アプリ、各要素タブ区切りになります。
Provider Provider Country SKU Developer Title Version Product Type Identifier Units Developer Proceeds Begin Date End Date Customer Currency Country Code Currency of Proceeds Apple Identifier Customer Price Promo Code Parent Identifier Subscription Period Category CMB Device Supported Platforms Proceeds Reason Preserved Pricing Client APPLE US com.example developername appname 1.0 0 0 0 12/16/2016 12/16/2016 JPY JP JPY 123456789 0 Business iPhone iOS
fastlaneで複数の国のメタデータを一括更新
アプリの申請や証明書周りを自動化するfastlaneを試してみました。
インストール
インストールはgemを利用します。
gem install fastlane
fastlaneの初期化
インストールが終わったらfastlaneの初期化を行います。
プロジェクトのフォルダで以下コマンドを実行します。
fastlane init
そうするとAppleIDを聞かれるので答えます。
今回は既にあるアプリに適用したので、iTunesconnectからメタデータをダウンロードしています。
ダウンロードしたファイルはfastlaneフォルダ以下に入ります。
fastlaneでメタデータをアップロード
fastlaneを使ったメタデータの更新を試してみます。
fastlane/metadata/en-USフォルダのrelease_notes.txtを更新します。
次にプロジェクトのルートフォルダで以下コマンドを打ちます。
fastlane deliver
すると以下のようにアップロードを開始してくれます。
iTunesconnectにアクセスすると先程更新したReleaseNoteが反映されている事が分かります。
ファイルを用意するだけでメタデータの更新ができるので、複数国対応しているアプリのリリースも非常に楽になりそうです。
【Swift】Chartsを使って色々なグラフを描画してみる
Chartsというライブラリを試して色々なグラフを使ってみました。
インストール
CocoaPodsでインストールしました。
target 'MyApp' do use_frameworks! pod "Charts" end
棒グラフ
import UIKit import Charts class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() var rect = view.bounds rect.origin.y += 20 rect.size.height -= 20 let barChartView = BarChartView(frame: rect) let entry = [ BarChartDataEntry(x: 10, y: 30), BarChartDataEntry(x: 20, y: 20), BarChartDataEntry(x: 30, y: 40), BarChartDataEntry(x: 40, y: 10), BarChartDataEntry(x: 50, y: 30) ] let set = [ BarChartDataSet(values: entry, label: "Data") ] barChartView.data = BarChartData(dataSets: set) view.addSubview(barChartView) } }
バブルチャート
import UIKit import Charts class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() var rect = view.bounds rect.origin.y += 20 rect.size.height -= 20 let chartView = BubbleChartView(frame: rect) let entries = [ BubbleChartDataEntry(x: 1, y: 10, size: 30), BubbleChartDataEntry(x: 2, y: 60, size: 10), BubbleChartDataEntry(x: 3, y: 20, size: 20), BubbleChartDataEntry(x: 4, y: 40, size: 30), BubbleChartDataEntry(x: 5, y: 30, size: 40), BubbleChartDataEntry(x: 6, y: 10, size: 20) ] let set = BubbleChartDataSet(values: entries) chartView.data = BubbleChartData(dataSet: set) view.addSubview(chartView) } }
ロウソク足
import UIKit import Charts class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() var rect = view.bounds rect.origin.y += 20 rect.size.height -= 20 let chartView = CandleStickChartView(frame: rect) let entries = [ CandleChartDataEntry(x: 1, shadowH: 12, shadowL: 10, open: 11, close: 11), CandleChartDataEntry(x: 2, shadowH: 20, shadowL: 15, open: 18, close: 17), CandleChartDataEntry(x: 3, shadowH: 30, shadowL: 24, open: 26, close: 28), ] let set = CandleChartDataSet(values: entries, label: "Test") chartView.data = CandleChartData(dataSet: set) view.addSubview(chartView) } }
横棒グラフ
データは棒グラフ同様、BarChartDataを使います。
import UIKit import Charts class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() var rect = view.bounds rect.origin.y += 20 rect.size.height -= 20 let chartView = HorizontalBarChartView(frame: rect) let entry = [ BarChartDataEntry(x: 1, y: 30), BarChartDataEntry(x: 2, y: 20), BarChartDataEntry(x: 3, y: 40), BarChartDataEntry(x: 4, y: 10), BarChartDataEntry(x: 5, y: 30) ] let set = BarChartDataSet(values: entry, label: "Data") chartView.data = BarChartData(dataSet: set) view.addSubview(chartView) } }
折れ線グラフ
import UIKit import Charts class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() var rect = view.bounds rect.origin.y += 20 rect.size.height -= 20 let chartView = LineChartView(frame: rect) let entries = [ BarChartDataEntry(x: 1, y: 30), BarChartDataEntry(x: 2, y: 20), BarChartDataEntry(x: 3, y: 40), BarChartDataEntry(x: 4, y: 10), BarChartDataEntry(x: 5, y: 30) ] let set = LineChartDataSet(values: entries, label: "Data") chartView.data = LineChartData(dataSet: set) view.addSubview(chartView) } }
円グラフ
import UIKit import Charts class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() var rect = view.bounds rect.origin.y += 20 rect.size.height -= 20 let chartView = PieChartView(frame: rect) let entries = [ PieChartDataEntry(value: 10, label: "A"), PieChartDataEntry(value: 20, label: "B"), PieChartDataEntry(value: 30, label: "C"), PieChartDataEntry(value: 40, label: "D"), PieChartDataEntry(value: 50, label: "E") ] let set = PieChartDataSet(values: entries, label: "Data") chartView.data = PieChartData(dataSet: set) view.addSubview(chartView) } }
レーダーチャート
import UIKit import Charts class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() var rect = view.bounds rect.origin.y += 20 rect.size.height -= 20 let chartView = RadarChartView(frame: rect) let entries = [ RadarChartDataEntry(value: 40), RadarChartDataEntry(value: 30), RadarChartDataEntry(value: 20), RadarChartDataEntry(value: 40), ] let set = RadarChartDataSet(values: entries, label: "Data") chartView.data = RadarChartData(dataSet: set) view.addSubview(chartView) } }
点グラフ
import UIKit import Charts class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() var rect = view.bounds rect.origin.y += 20 rect.size.height -= 20 let chartView = ScatterChartView(frame: rect) let entries = [ BarChartDataEntry(x: 1, y: 10), BarChartDataEntry(x: 2, y: 15), BarChartDataEntry(x: 3, y: 9), BarChartDataEntry(x: 4, y: 13), ] let set = ScatterChartDataSet(values: entries, label: "Data") chartView.data = ScatterChartData(dataSet: set) view.addSubview(chartView) } }
まとめ
今回は簡単に一通りのグラフに触れてみました。
どれも同じようなインターフェースな為、一つ実装すれば他のものも同じように作れそうです。
【iOS】指紋認証を使ってみる
iPhone5sから登場した指紋認証ですが、まだちゃんと使った事がなかったので試してみました。
指紋認証可能化どうかはLAContextクラスのcanEvaluatePolicyメソッドを使います。 LAContextを使うためにはLocalAuthenticationをimportする必要があります。
import LocalAuthentication class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let context = LAContext() var error: NSError? if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { // 指紋認証可能 } } }
認証はevaluatePolicyメソッドを使います。
引数には認証画面での説明テキストも入れます。
import LocalAuthentication class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let context = LAContext() var error: NSError? if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "パスコードロックに使う") { success, error in } } } }
起動すると以下のようにパスコードを求められる画面になります。
.deviceOwnerAuthenticationWithBiometricsでなく.deviceOwnerAuthenticationを使った場合
シミュレータで試したところ以下のようにパスコードを求められました。
【iOS】Smile-Lockでパスコードロック機能を実現する
Smile-Lockというライブラリを試してみました。
URL見るとリクルートライフスタイルで出しているライブラリなんですね。
インストール
CocoaPodsでインストールしました。
target 'MyApp' do use_frameworks! pod 'SmileLock' end
使い方
下のようにWindowやViewに貼り付ける事で利用します。
import UIKit import SmileLock class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let kPasswordDigit = 6 let contentView = PasswordContainerView.createWithDigit(kPasswordDigit) if let window = view.window { let baseView = UIView(frame: window.bounds) baseView.addSubview(contentView) contentView.center = baseView.center window.addSubview(baseView) } } }
実行すると下のような表示になります。
パスコードを入力した時の動作はプロトコルに記述します。
passwordInputComplete:input:
は入力が完了した時に呼ばれます。
extension ViewController: PasswordInputCompleteProtocol { func passwordInputComplete(_ passwordContainerView: PasswordContainerView, input: String) { print(input) } func touchAuthenticationComplete(_ passwordContainerView: PasswordContainerView, success: Bool, error: NSError?) { } }
パスコードが違う場合のシェイクはwrongPasswordメソッドを使います。
入力のクリアだけしたい場合はclearInputメソッドを使えば良さそうです。
extension ViewController: PasswordInputCompleteProtocol { func passwordInputComplete(_ passwordContainerView: PasswordContainerView, input: String) { passwordContainerView.wrongPassword() } func touchAuthenticationComplete(_ passwordContainerView: PasswordContainerView, success: Bool, error: NSError?) { } }
それとPasswordContainerViewのプロパティーを触る事で少しだけデザインを変更できます。
ボタンの色を変えるtintColor、ハイライト時の色を変えるhighlightedColor、曇りガラス風デザインに変更できるisVibrancyEffectなどがあります。
タッチIDが使える場合は自動的にViewにタッチボタンが表示されます。
押すとタッチIDを求める表示になります。
指紋認証が完了するとdelegateのtouchAuthenticationComplete
メソッドが呼ばれます。
extension ViewController: PasswordInputCompleteProtocol { func passwordInputComplete(_ passwordContainerView: PasswordContainerView, input: String) { } func touchAuthenticationComplete(_ passwordContainerView: PasswordContainerView, success: Bool, error: NSError?) { print(success) } }
今回は触れないのですが、PasswordUIValidationというクラスを使ったアプローチもあるようです。
THPinViewControllerとの比較
THPinViewControllerより自由度が高いのが良さそうでした。
THPinViewControllerは良く使っているんですが、「パスコード正解時は自動的にdissmissされる為、確認ページへ遷移させるのが難しい」みたいな問題があってそれが解決するだけでも良さそうです。
それと指紋認証を標準で対応してくれているのもありがたいです。