読者です 読者をやめる 読者になる 読者になる

LCL 開発者ブログ

夜行バス比較なびを運営する 株式会社LCLの開発者ブログ

2016年 新規iOSアプリ開発で採用した技術・プロセス

弊社では、2016年07月に「高速バス比較」というiOSアプリをリリースしました。

www.bushikaku.net

リリースして1ヶ月ほどたちましたので、本記事では、今回の開発で採用した技術・ツール・プロセスを一通りご紹介します。

言語

Swift 2.2を採用しています。

サポートiOSバージョン

iOS 8.0 以上をサポートしています。

利用ユーザ数や開発生産性を考慮し、iOS 8.0未満は対象外にすることにしました。

リリース後1ヶ月の時点では、iOS 8.X系でご利用いただいているユーザは 5%弱ですので、当面はiOS 8.X系はサポート対象に入れておいたほうが良いと考えてます。

ライブラリ

ライブラリ管理には、CocoaPods , Carthage を利用しています。

主要なライブラリとしては、次のようなものを利用しています。

  • HTTP通信
    • Alamofire
  • 画像ダウンロード
    • SDWebImage
  • データ永続化
    • realm
  • ローディング表示
    • SVProgressHUD
  • カレンダー
    • FSCalendar

FSCalendarは、カレンダー関係のロジックを実装する必要がなく楽なのですが、制約が厳しくデザイン上あまり凝ったことはできません。 弊社アプリはカレンダーが、UIとして重要なパーツのため、かなりカスタマイズをしてデザインを変更しました。 ただ、今となってはデザインが重要な場合はFSCalendarは利用せず、自作したほうがよかったと判断しています。

f:id:lcl-engineer:20160824170952p:plain

ブランチ運用

ブランチ運用は、Git Flowを利用しています。 以下の記事を参考にさせていただいています。

iOSアプリ開発のGit運用 · hikarock blog

ビルド・テスト配布

iOSアプリ開発において、良いサービスを早く作り上げていくためには、開発の初期段階でのビルド・テスト配布の自動化は必須だと思っています。ビルド・テスト配布が手動の場合は、どうしてもある程度まとまった単位でのテスト配布となってしまい、フィードバックサイクルが長くなってしまいます。

弊社では、ビルド・テスト配布の自動化は、fastlane + Crashlytics(fabric) + Bitrise を利用し、1日に何度もテストアプリを配布し、短いサイクルでフィードバックを回しています。

各種サービスの詳細や、環境によるアプリの使い分けは以下の記事で紹介しています。

techblog.lclco.com techblog.lclco.com

クラッシュ監視

どれだけ入念にテストを実施しても、クラッシュは発生してしまいますので、クラッシュ監視のサービスは導入必須だと考えています。

現在は、以下のクラッシュ監視サービスを利用しています。

  • Crashlytics
  • bugsnag

テスト配布アプリにも仕込んでおくことで、テスト中に発生したクラッシュを即把握できるので、テスト担当者からわざわざ詳細な報告を受ける必要がありません。また、発生したクラッシュを元にすぐIssueを作成でき、クラッシュ検知 → Issue作成 → 修正という流れが開発者のみで完結できます。

ログ

アプリ起動、主要なボタン操作のタイミングでログを取得しています。以下の項目をサーバ側に随時送信し、サーバ側のデータベースに格納するようにしています。

  • 端末種類 ( iphone 5s,6sなど)
  • iOSバージョン
  • アプリバージョン
  • 任意パラメータ (JSON)

PUSH通知

PUSH通知サービス

PUSH通知は、Amazon Simple Notification Service (SNS) を利用しています。

数あるサービスのなかから、以下の理由でSNSを選定しています。

  • コストが圧倒的に安い
  • 開封率などの分析・セグメント別配信などほぼ全て自前での実装になるが、将来的に発生する可能性がある要件に柔軟に対応できる

SNSのノウハウについては、Gunosyさんの資料がとても参考になりました。

900万ダウンロードアプリ『Gunosy』を支える大規模モバイルプッシュ通知基盤 // Speaker Deck

証明書

PUSH関連の証明書はややこしいので、こちらは完全にfastlaneを頼ってます。

fastlane pemで、iOSのPUSH通知用証明書を自動生成する - LCL 開発者ブログ

AppStore 申請

AppStoreの申請に必要な文言・スクリーンショットは、fastlane deliverを利用して登録しています。

手動でも大きな手間ではありませんが、各種情報をGit管理でき確実に反映できるのが利点です。

fastlane/deliver at master · fastlane/fastlane · GitHub

UIプロトタイプ

Prottを利用しました。

iPhone実機にProttアプリを入れると、実際のアプリに近いイメージでプロトタイプが確認できるので、早い段階でのUIブラッシュアップが可能です。

ただし、他のツールの調査が不十分ですので、継続して良い物を探していきたいと考えてます。

アクセス解析

今のところは、GTMを利用して、Google Analyticsのみを利用している状態です。この辺りも引き続き必要に応じて、他のサービスの導入を考えています。

iOSアプリ(Swift)へのGTM導入 & TIPS - LCL 開発者ブログ

まとめ

今回の新規アプリ開発で採用している技術について紹介しました。 現時点では、できるだけ広く利用している技術を選定しましたが、アプリ界隈はどんどん新しいサービスが出てくるので、うまく見極めてよいものは導入していきたいと考えてます。

RubyでiTunes ConnectからiOSアプリのダウンロード数を自動取得する

iOSアプリのダウンロード数は、Appleから提供されいてるJavaのツールを使うことでiTunes Connect (以下 iTC) から自動取得できます。 今回は、それをRubyで行う方法をご紹介します。

手順

事前準備

iTCへの接続には、以下の情報が必要です。

  • iTCへログイン可能な、id / password
  • 該当ユーザには、Report権限が必要
  • VENDOR ID

VENDOR_IDは、iTCの下記画面から確認できます。

[売上とトレンド] > [トップコンテンツ] > [レポート]

f:id:lcl-engineer:20160807201916p:plain

以下赤枠に表示されている数値が、VENDOR_IDです。

f:id:lcl-engineer:20160807201944p:plain

Rubyでの実装

gemを作成されている方がいらっしゃいましたので、こちらを利用します。

GitHub - siuying/itunes-auto-ingestion: A simple port of Apple itunes Autoingestion tool to ruby.

gemインストール

gem 'itunes_ingestion', '~> 0.3.0'

requireに追加

require "itunes_ingestion"

ログインする

  user_id = "aaaa@aaa.com"
  password = "password"
  vendor_id  = 12345678

  fetcher = ITunesIngestion::Fetcher.new(user_id, password, vendor_id)

Dailyデータを取得する

 option ={
     report_date: "20160801"
 }

report_data = fetcher.fetch(option)
reports = ITunesIngestion::SalesReportParser.parse(report_data)

Weeklyのデータを取得する。report_dateは週末(日曜日)の日付を指定必要です。

 option ={
     report_date: "20160807",
     date_type: "Weekly"
 }

report_data = fetcher.fetch(option)
reports = ITunesIngestion::SalesReportParser.parse(report_data)

取得データの見方

以下のようなデータが配列で取得できます。

{:provider=>"APPLE",
 :country=>"US",
 :sku=>"xxxxxxxxxxxxxxxx",
 :developer=>"xxxxxxxxxxxxxxxx",
 :title=>"xxxxxxxxxxxxxxxxxxxxxxxx",
 :version=>"1.1.0",
 :product_type_id=>"7",
 :units=>10,
 :developer_proceeds=>0.0,
 :begin_date=>Fri, 05 Aug 2016,
 :end_date=>Fri, 05 Aug 2016,
 :currency=>"USD",
 :country_code=>"US",
 :currency_of_proceeds=>"USD",
 :apple_id=> 123456789,
 :customer_price=>0.0,
 :promo_code=>"",
 :parent_id=>"",
 :subscription=>"",
 :period=>" "}

product_type_idを以下を意味しているので、単純に新規ダウンロード数だけカウントしたい場合は、「 product_type_id = 1」のレコードだけを抽出すればカウント可能です。

  • 1 : Free or paid app iPhone and iPod touch (iOS)
  • 3 : Redownload of iPhone-only, or iOS and tvOS app (excluding iPad-only)
  • 7 : Update iPhone and iPod touch (iOS)

他にも区分がありますので、詳細はマニュアル参照ください。

http://www.apple.com/itunesnews/docs/AppStoreReportingInstructions.pdf

iOSアプリ(Swift)へのGTM導入 & TIPS

弊社は、2016/07/25(月)に夜行バス・高速バスの最安値検索アプリ『高速バス比較』をリリースしました!

www.bushikaku.net

今後は、本アプリで得た知見を随時公開していきたいと考えてます。 今回はまず、Google Tag Manager(以下GTM)の導入と多少のTIPSを紹介いたします。

Web版のGTMとの違い

WebのGTMでは、一度タグを埋め込んでおけば、GTMの管理画面からある程度柔軟にトラッキング情報の変更ができます。 例えば、コードを仕込まなくとも、GTMの管理画面の設定によりクリックイベントを取得できます。

iOS版では残念ながら、現時点ではこのような柔軟性はありません。 クリックイベントを取得したい場合は、必ず該当の箇所にコードを埋め込む必要があります。

iOSアプリへのGTMの導入

SDKの組み込み

SDKの組み込みは少し面倒ですが、公式ドキュメント通りの手順で問題なく組み込み可能です。

Getting Started Guide for Swift  |  Google Tag Manager for iOS  |  Google Developers

公式ドキュメントが少しわかりづらい場合は、以下の記事もおすすめです。

http://www.simoahava.com/analytics/setup-google-tag-manager-ios-with-swift/

Swiftコードへ組み込む

AppDelegate.swiftに実装します。

まず、TAGContainerOpenerNotifierを継承します。

class AppDelegate: UIResponder, UIApplicationDelegate, TAGContainerOpenerNotifier {

以下のメソッドを追加します。

func containerAvailable(container: TAGContainer!) {
     container.refresh()
}

applicationメソッドに下記を追加します。

let GTM = TAGManager.instance()

TAGContainerOpener.openContainerWithId("GTM-XXX",  
    tagManager: GTM, openType: kTAGOpenTypePreferFresh,
    timeout: nil,
    notifier: self)

GTM-XXXの箇所は、ご自身の環境のコンテナIDをセットします。 弊社では、テスト用アプリとリリース用アプリで、コンテナを別にしているため、コンテナIDはビルド環境に応じた値をセットするようにしています。

ここまでで、準備完了です。 あとは、トラッキングする箇所にコードを組み込みます。

スクリーンビューを計測する

Webのページビューは、iOSアプリのGoogle Analyticsではスクリーンビューと呼ばれています。

該当の画面が表示された時に、計測するのが一般的なので、ViewControllerのviewWillAppearに組み込みます。

override func viewWillAppear(animated: Bool) {
   super.viewWillAppear(animated)
   let dataLayer = TAGManager.instance().dataLayer
   let screenName ="HOME"
   dataLayer.push(["event" : "screenView", "screenName" : screenName])
}

iOS版のGTMの実装は、dataLayer.pushがポイントとなります。dataLayer.pushには、key:valueの形で任意値をセットすることができ、それらの値をGTMの管理画面で適切に計測するように設定します。

今回の例で言えば、event に "screenView"と設定しているので、GTMの管理画面でevent = "screenView"の時に発火するトリガーを作成します。

f:id:lcl-engineer:20160731212307p:plain

screenNameに画面名を設定しているので、管理画面で以下のタグを作成します。その際、「配信するタイミング」で上記トリガーを設定します。

f:id:lcl-engineer:20160731212557p:plain

上記設定を行うと、 dataLayer.pushによりevent = "screenView" というデータが送られてきた場合は、スクリーンビューとして計測する。その際のスクリーン名は、screenNameに設定された値となります。

イベントを計測する

クリックなどのイベントを計測する場合も、同じ流れです。 計測した箇所に、dataLayer.pushで必要な値を設定します。

@IBAction func buttonPressed(sender: AnyObject) {
   let dataLayer = TAGManager.instance().dataLayer
   dataLayer.push(["event": "ButtonPressed"
                  ,"eventCategory": "Test Category"
                  ,"eventAction": "Tetst Action"
                  ,"eventLabel": "Test Label"]
                 )
}

スクリーンビューと同様に、dataLayer.pushに設定された変数を元に、適切なトリガー・タグを生成します

f:id:lcl-engineer:20160731213729p:plain

これでイベントも計測できるようになります。

IDFA(広告主識別子)の収集を有効にする

キャンペーンの測定や、GA上でのユーザ属性を把握するためには、IDFAの収集を有効にする必要があります。

まず、Cocoapodsで、以下ライブラリを追加します。

pod 'GoogleIDFASupport'

その後、GTM管理画面のタグの設定で、「広告IDの機能を有効にする」でチェックを入れます。

f:id:lcl-engineer:20160731230935p:plain

以上でIDFAの収集が有効になります。コードの変更は不要です。

IDFAが正しく収集されているかを確認するには、後述するデバッグログを有効にします。 ログに「idfa」というパラメータが出力されていたら、正しく有効化されています。

GoogleAnalytics 3.14 -[GAIBatchingDispatcher persist:] (GAIBatchingDispatcher.m:517): Saved hit: {
    parameters =     {
        ・・・
        "&_crc" = 5;
        "&_s" = 3;
        "&idfa" = "600D3A55-B516-4787-96EB-123412341";
        "&t" = appview;
        gaiVersion = "3.14";
    };

なお、IDFAの収集を有効にすると、アプリの申請時に目的を適切に回答する必要がありますので、ご注意ください。

効率的なデバッグのためのTIPS

iOSアプリは、Webと違いGoogle Analyticsへリアルタイムにデータを送信しません。そのためリアルタイムでGA上で確認することができず、面倒です。 弊社では、確認を容易にするため、デバッグ時は以下のような方法を用いています。

詳細なログを出力する

デバッグ時には、詳細なログがコンソールに表示されるようにログレベルを変更しています。

GTM.logger.setLogLevel(kTAGLoggerLogLevelVerbose)

データ送信間隔を短くする

NSTimeIntervalを設定することで、データ送信間隔を変更できます。以下の例では、1秒に設定してるため、GA上での確認がしやすくなります。

GTM.dispatchInterval = NSTimeInterval(1.0)

Webサーバに同じデータを送る

GTMの管理画面の設定さえ正しくしておけば、あとはdataLayerに正しい値が設定されているかさえ確認しておけば問題ありません。

その確認を容易にするために、WebサーバにdataLayerにセットしてる値と同じ値を送信するようにしています。

dataLayer.push(["event" : eventName, "screenName" : screenName])

// Webサーバに同じ値を投げる
API.reuest("http://www.xxxx.xxx/\(eventName)/\(screenName)")

このようにすれば、Webサーバのログを見れば、dataLayerにセットしている値が確認できます。 ( Webサーバへのアクセスは404になっても構いません。)

最後に

iOS版のGTMは、Webと比較すると導入するメリットは少ないですが、それでも標準のGAのSDKよりは多少は柔軟にできるので、入れておいて損はないと思います。

なお、2016年5月にGoogleから「Firebase Analytics」が発表されましたので、今後はアプリのアクセス解析はこちらが主になってくるかもしれません。

アナリティクス 日本版 公式ブログ: Firebase Analytics と Firebase のご紹介

もっと気軽にリファクタリングするために、BackstopJSを導入した話

フロントエンド担当の岡田です。 ある程度の期間運用しているWebサイトの場合、CSSがカオスになりますよね。 ちょっとした修正が全体に影響してしまうのがCSSの怖いところです。

弊社でも、Sass化したり、共通のCSSを変更したりする度に主要ページを目視チェックしていました。 しかし目視チェックでは時間がかかりすぎますし、違いに気づけないこともあります。

そこで、BackstopJSを導入して、気軽にリファクタリングできる環境を作りました。

BackstopJSとは

BackstopJSは、CSSのリグレッションテストを自動化します。 具体的には、変更前・変更後の2つの画面のスクリーンショットを撮り、その差分を表示します。 f:id:lcl-engineer:20160625164434p:plain 左から順にリファレンス(変更前)、テスト(変更後)、差分の順に並んでいます。 差分のあるパーツは、ピンク色に塗られるので一目瞭然です。

BackstopJSでできること

  • ページ内の一部のパーツの比較(ページ全体の比較もできます)
  • 任意のパーツを除外したテスト(読み込みの度に表示が変わるものを除外できます)
  • スマホ・タブレットのテスト(レスポンシブサイトのみ)
  • SPAやAjaxで描画されるページのテスト

カスタムCasperJS scriptsを使うと以下のこともできるようになります

  • ユーザーエージェントを偽装したスマホ・タブレットのテスト
  • クリックしてから表示する箇所のテスト(まだ試していませんができるようです)

導入方法

以下のページでわかりやすく解説されているのでこちらでは割愛します。

ディレクター注目のBackstopJSを使用したリグレッションテストでバグ修正後の確認をしよう | 株式会社LIG
BackstopJSを使ったCSSのリファクタリング | フロントエンドBlog | ミツエーリンクス

弊社で使っている設定について

backstop.js

{
    "onReadyScript": "setUAiPhone.js",
    "viewports": [{
        "name": "sp",
        "width": 320,
        "height": 480
    }],
    "scenarios": [{
        "label": "http://localhost:3000/",
        "url": "http://localhost:3000/",
        "referenceUrl": "http://idou.me/",
        "hideSelectors": "iframe",
        "selectors": "body",
        "delay": 0,
        "misMatchThreshold": 0.1
    }, {
        "label": "http://localhost:3000/search/all/tokyo/osaka",
        "url": "http://localhost:3000/search/all/tokyo/osaka",
        "referenceUrl": "http://idou.me/search/all/tokyo/osaka",
        "hideSelectors": "iframe",
        "selectors": "body",
        "readyEvent": "backstopjs_ready",
        "delay": 0,
        "misMatchThreshold": 0.1
    }],
    "paths": {
        "bitmaps_reference": "../../backstop_data/bitmaps_reference",
        "bitmaps_test": "../../backstop_data/bitmaps_test",
        "compare_data": "../../backstop_data/bitmaps_test/compare.json",
        "casper_scripts": "../../backstop_data/casper_scripts"
    },
    "engine": "phantomjs",
    "report": ["CLI", "browser"],
    "cliExitOnFail": false,
    "casperFlags": [],
    "debug": false,
    "port": 3009
}

setUAiPhone.js

module.exports = function(casper, scenario, vp) {
  casper.echo("Setting UA");
  casper.then(function(){
    casper.userAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 9_3_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13F69 Safari/601.1');
  });
  casper.thenOpen(scenario.url);
}

※ setUAiPhone.jsは、casper_scripts/以下に保存します

解説

onReadyScript

ここでユーザーエージェントを変更するカスタムCasperJS scriptsを指定します

"onReadyScript": "setUAiPhone.js",

url

テスト対象ページ(変更後)を指定します

"url": "http://localhost:3000/",

referenceUrl

リファレンスページ(変更前)を指定します

"referenceUrl": "http://idou.me/",

hideSelectors

非表示にする要素を指定します。Twitter, Facebook, 広告などはiframeになっているので、iframeタグを指定しています

"hideSelectors": "iframe",

selectors

テストする箇所を指定します。bodyを指定するとページ全体をテストします

"selectors": "body",

readyEvent

SPAやAjax等、JavaScriptで描画される箇所があるページをテストする方法は2種類あります。1つはこのreadyEventを使う方法です。テスト対象ページの描画が完了したタイミングにconsole.log('backstopjs_ready');を追加します

"readyEvent":"backstopjs_ready",  

delay

SPAやAjaxのテスト方法のもう1つはこちらです。指定した時間だけキャプチャを取る時間を遅らせることができます。console.logを追加するのが面倒な場合は、delay設定が手軽です。ミリ秒単位で設定します。例:"delay": 1000, // 1000ミリ秒=1秒

"delay": 0,

misMatchThreshold

ミスマッチのしきい値。値が小さいほうが少しのズレでも差分として表示されます

"misMatchThreshold": 0.1

まとめ

BackstopJSは導入も簡単ですし、ローカルで動かせるので気軽にテストができます。 また、CasperJSを使うといろいろなことができそうなので、また新たな発見があれば共有します。

iOSアプリでデバッグ/テスト/リリース環境に応じてアプリを分ける

iOSアプリ開発において、接続先のサーバー等を切り替えた複数のアプリを用意するのは一般的かと思います。 弊社では、Debug版、Test版、RC版、Release版の4種類に分けています。

環境の種類

それぞれ以下の定義としています。

Debug版

  • 開発者のシミュレーターでのデバッグ用
  • アプリから、接続するサーバーは開発者ローカルマシン上のサーバ

Test版

  • 実機テスト用
  • アプリから、接続するサーバーはテストサーバ
  • Provisioning ProfileはAdhoc
  • 1日数回テスト配布する

RC版

  • AppStore申請前の最終チェック用
  • アプリから、接続するサーバーはプロダクションサーバ
  • Release版との違いは、bundle_idのみ
  • Provisioning ProfileはAdhoc

Release版

  • AppStoreへの公開用
  • アプリから、接続するサーバーはプロダクションサーバ
  • Provisioning ProfileはAppStore

切り替えの方法

スキーマとビルド設定を利用して、切り替えを行っています。 詳細は以下の記事が詳しいので、割愛します。

ビルドとテスト配布

ビルドはfastlane + bitrise を使用しています。

Bitrise,fastlane,CrashlyticsでiOSアプリのテスト配布を自動化する - LCL 開発者ブログ

fastlaneでは、ビルド環境に応じたレーンを用意し、先頭で環境に応じたパラメータをセットしています。(schemeなど)

  # テスト用ビルド
  lane :test do
    build(
      bundle_id: "com.xxx.yyy.zzz-test",
      scheme: "xyz-test",
      display_name: "TEST XYZ",
      adhoc: true,
    )
 ・・・
  end

  # RC用ビルド
  lane :release do
    build(
      bundle_id: "com.xxx.yyy.zzz-rc",
      scheme: "xyz-release",
      display_name: "RC XYZ",
      adhoc: false,
    )
 ・・・
  end

  # リリース用ビルド
  lane :release do
    build(
      bundle_id: "com.xxx.yyy.zzz",
      scheme: "xyz-release",
      display_name: "XYZ",
      adhoc: false,
    )
 ・・・
  end

  # ビルド処理 (共通) 
  private_lane :build do |options|

    sigh(
       adhoc: options[:adhoc],
       app_identifier: options[:bundle_id],
    )

   ・・・

    gym(
        clean: true,
        scheme: options[:scheme],
    ) 
  end

なお、Test版・RC版・Release版のアプリを実機で同居させるために、Info.plistの以下属性をビルド時に動的に書き換えてます。

  • bundle identifier ( app_identifier )
  • display_name

fastlaneでinfo.plistを書き換えるためのメソッドが既に用意されているので、gymでのビルドの前後で下記の記述をすれば、簡単に対応できます。

    PLIST_PATH = "./app/Info.plist"

    # 既存ファイルをバックアップ
    backup_file(path: PLIST_PATH)

    # 書き換え ( 
    update_info_plist(
      plist_path: PLIST_PATH,
      app_identifier: options[:bundle_id],
      display_name: options[:display_name]
    )

 ・・・ビルド・・・

    # バックアップからのリストア
    restore_file(path: PLIST_PATH)

Fabric とTestflightの使い分け

テスト配布は、Fabric CrashlyticsとTestflightを利用しています。

以下の理由からTest版・RC版はFabric、Release版はTestFlightというように使い分けています。

  • TestFlightは配布に少し時間がかかるので、配布頻度が高いTest版・RC版はFabricを利用
  • Release版は、AppStore申請直前の最終確認のためTestFlightを利用

以上となります。 簡単ですが、弊社での事例を紹介致しました。 ビルド定義の変更を毎回手作業で対応すると、つまらないミスも発生しますし、開発リズムも悪くなるので、開発の初期段階で完全に自動化しておくと安心です。

Photoshop不要! ブラウザにPSDを重ねてコーディングする方法

フロントエンドエンジニアの岡田です。
弊社ではデザイナーとフロントエンドエンジニアで分業をしていることもあり、HTML/CSSコーディングの際にはデザインカンプ(PSD)にスクリーンショットを重ねて確認しています。
ですが、この作業、少し面倒ですよね…
今回、LayerXBrowserSyncを導入して少しだけ快適になったので紹介します。

今までの確認方法

  1. スクリーンショットをクリップボードへコピー(Macなら⌘ + shift + 4 + control)
  2. スクリーンショットをPhotoshopへペーストして、不透明度を50%へ設定(もしくはレイヤーモードを「差の絶対値」に設定)
  3. ペーストしたレイヤーをPSD上で上下左右に動かしながら、ずれているピクセル数を計算してCSSへ反映
  4. ブラウザをリロード
  5. 1〜4の繰り返し…

f:id:lcl-engineer:20160529063102p:plain

上記の3. の作業でPSDとスクリーンショットの位置を揃えるのも面倒ですし、間違えた方向に値を増やしてしまい、さらにずれてしまった… という失敗をすることもあります。

そこでLayerX と BrowserSync を導入すると…

LayerX で ブラウザにPSDを重ねることができるようになるので、

f:id:lcl-engineer:20160530200918p:plain

BrowserSyncを起動しておけば、ファイルを変更するたびにブラウザが自動でリロードされ、常にPSDとの差分チェックができます。

導入方法

LayerXインストール

LayerXのサイトからインストール f:id:lcl-engineer:20160528231518p:plain ※「Downloand LayerX 1.1.1」ボタンでダウンロードできます

BrowserSync

gulpやgrunt等のタスクランナーを使っても良いのですが、今回は使わない方法を説明します。 node.jsが必要です。

インストール

$ npm install -g browser-sync

起動

$ browser-sync start --server --files "*.html","css/*.css","js/*.js"

※起動のコマンドは、サイトルートのディレクトリで実行してください
※ --files 以下は適切なパスに変えてください
※VagrantやVirtualBox等でローカルーサーバーが存在する場合は、「--server」ではなく「--proxy」を指定します

$ browser-sync start --proxy test-domain.co.jp --files "app/views/**/*.html.*","app/assets/sass/**/*.scss","app/assets/javascripts/**/*.js"

使い方

  1. ブラウザを開いておきます
  2. BrowserSync も起動しておきます
  3. LayerXを起動して、PSDファイルをドラッグ f:id:lcl-engineer:20160530201337p:plain
  4. ブラウザとPSDの位置を合わせて差分チェック

補足

  • LayerXで開いたPSDはロックできるので(Macの場合は⌘ + L)Chromeのデベロッパーツールなども使えます
  • BrowserSync起動時に表示されるExternalのURLを使うと、同じネットワーク内のスマホや他のPCからもアクセスできます
  • BrowserSyncの設定は、設定ファイル(bs-config.js) に保存しておくことができます。
$ browser-sync start --config bs-config.js

bs-config.js

module.exports = {
    files: ["*.html*", "css/*.css", "js/*.js"],
    server: {
        baseDir: "public",
        index: "index.html"
    },
    browser: ["firefox", "safari", "Google Chrome"]
}

まとめ

スクリーンショットを撮ってPSDで重ねる…を繰り返さなくてすむのは、けっこう快適です。 まだ使い始めたばかりなので今後課題が出てくるかもしれませんが、その際にはまた共有します。

fastlane pemで、iOSのPUSH通知用証明書を自動生成する

各所で言われてますが、iOSのPUSH通知用証明書は作成手順が複雑です。

今回は、証明書を自動作成してくれる「fastlane pem」を紹介します。

pemがあれば、複雑な手順を全く覚える必要がなくなるので、非常に楽になります。

github.com

事前準備

App IDは事前に作成していること

インストール

sudo gem install pem -n /usr/local/bin/

証明書の生成

以下のコマンドを実行するだけです。

pem -a [app_identifier] -u [ Apple ID]

fastlane導入済みのプロジェクトのディレクトリで実行する場合は、pemだけでOKです。

pem

実行したディレクトリに証明書が作成されるので、PUSH配信サーバやサービスに必要な証明書をUPすれば完了です。

pem
・・・
・・・
[15:20:44]: Creating a new push certificate for app 'xzxxxxxxxxxxxxxx
[15:20:47]: Private key: /private/tmp/production_xzxxxxxxxxxxxxxx.pkey
[15:20:47]: p12 certificate: /private/tmp/production_xzxxxxxxxxxxxxxx.p12
[15:20:47]: PEM: /private/tmp/production_xzxxxxxxxxxxxxxx.pem

一応、Dev Centerを確認すると、問題なく証明書が作成されています。

f:id:lcl-engineer:20160529235547p:plain

App IDにも紐付けられていますね。

f:id:lcl-engineer:20160529235709p:plain

この辺の手順を意識する必要がなくなるのは嬉しいですね。

その他オプション

開発用証明書を作成する場合は、developmentを付与します。

pem --development

デフォルトでは、既存の証明書の有効期間が30日以上がある場合は再生成しない。 強制的に再生成する場合は、forceを付与する。

pem --force

他にもオプションはありますが、よく利用するのはこれらぐらいだと思います。