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

BASE開発チームブログ

フリーミアムなネットショップ構築サービス BASE( https://thebase.in )の開発チームによるブログです。開発メンバ積極募集中! https://www.wantedly.com/companies/base/projects

独自ドメインのショップでhttpsでアクセスできるようになりました

SREチームの小林(し)です。

BASEでは独自ドメインで運用されているショップさんでHTTPSで表示できる機能を実装しました。

去年の3月にサブドメインで運用されているショップさんに関しては全てHTTPS化は実装していましたが、独自ドメインで表示されているショップさんはHTTPの表示のままでした。今回から独自ドメインを利用されているショップさんもHTTPSでアクセスが可能となり、全てのショップさんでHTTPSでのアクセスが可能となります。

今回の機能ではHTTPSアクセスに必要な証明書の取得は無料で行い、かつ管理は僕たちがやりますのでショップさんの方で証明書の取得・管理は不要です。

利用方法などはマニュアルにお任せし、今回は裏側の実装について紹介します

証明書

今回証明書を発行するにあたり、Let’s Encryptを利用させていただきました。Let’s Encryptは去年サービスが開始された無料で証明書が取得できるサービスです。

ただ同時に何枚も無制限に取得できるわけではなく、いくつかの制限が存在しています。逆に制限さえきちんと守れば同じアカウントからであれば証明書を複数枚取得することは許可されているようです。(運営に問い合わせ済み)

この Let’s Encryptから発行された証明書を使うことで、BASEの独自ドメインのショップをhttpsでアクセスすることを可能にしています。

外部サービスとの連携

取得はAmazon SQSと連携した取得専用のデーモンが自動で行なっています。 Let’s Encryptは初回はACMEアカウントと呼ばれる専用のアカウントが必要です。このアカウントが証明書を取得する際に認証として使われます。

f:id:srockstyle:20170321184658p:plain

PHPcon2016で発表した資料でもお話しましたが、BASEのサービスはロードバランサーに複数台のnginxを使っています。今回はnginxの設定を一部変更し、Let’s Encryptからのacme challengeと呼ばれる証明書取得確認のアクセスがきたら、取得専用のサーバにプロキシするようにしました。

取得専用サーバではacme challengeアクセスの受け皿としてドメインごとにディレクトリを作成しレスポンスを返しています。直下で認証が行われると証明書を取得するための一連の動作が専用のデーモンによって行われる仕組みです。

nginxへの同期と証明書の読み込み

f:id:srockstyle:20170321185659p:plain

Let’s Encryptの証明書は取得後「/etc/letsencrypt」ディレクトリに保存されます。これらをバランサーとして動作しているサーバに定期的に同期を走らせています。

nginxでの証明書読み込みはngx_mrubyをnginxにモジュールとして組み込むことで動的に行なっています。これにより同期された証明書がアクセスのたびに動的に読み込まれ、nginxを停止することなく、またnginxのメモリを圧迫することなく独自ドメインでのHTTPSアクセスができるようになりました。

まとめ

HTTPSはSEOでの効果もあるということなので、今回実装した機能はショップ運営の大きな助けになると思います。 独自ドメインを使っている方はぜひ利用してみてください!

BASEでは一緒にネットショップを開発・改善するエンジニアを募集してます。ご興味のある方はぜひ遊びにきてください。

BASE株式会社:採用情報

Try! Swift 2017 - 2日目「Swiftで堅牢なカラーシステムを構築する」

こんにちは、iOSエンジニアの遠藤(秀)です。 3/2(木)〜 3/4(土)の3日間に渡って開催された世界的なイベント「Try! Swift 2017」に参加してきました。

2日目のセッション「Swiftで堅牢なカラーシステムを構築する」について、まとめてみました。

セッション概要

これまで以上に多くの企業が、新しく増え続けるユーザーに今までよりも魅力的なアプリだとアピールするために、アプリを再設計しています。この講演ではあらゆる規模のプロジェクトにスケールできる堅牢なカラーシステムを構築するための戦略について議論します。これらのアプローチはデザイン上の決定を迅速に繰り返すのに役立ち、実行時にカラーパレットのテーマを変更するようなこともできるかもしれません。さらに、iOS 10で導入された新しいカラーフィルターのアクセシビリティ機能を使用して、色覚の問題を抱える人を支援することにも応用できることを示すデモンストレーションも行います。



キーワード 、まとめ

・プロトコル、エクステンションで堅牢なカラーシステムにする。
・ランタイムでカラーテーマを変更する。
・色覚障がいを含む、全てのユーザについて考慮すべき。



BASEアプリでのカラーマネージメント

BASEアプリでは、なるべくコード量を減らすためにclrファイルを作成して、xibファイル側に色情報を持たせるように移行している途中でした。

f:id:base_hideo:20170307150102p:plain

clrファイルの作成方法


セッション中の説明にもあったとおり、clrファルでカラーパレットを共有したとしても、カラーパレットに変更が起こったときには、全てのxibファイルを書き直す作業が必要になります。また、プログラマティックにカラーテーブルをダイナミックに変更することができません。

これらの問題を解決するので手法として、今回のセッションはとても参考になる内容でした。


エクステンションの作成

UIColorのエクステンションを作成してstructを定義します。

extension UIColor {
    struct Palette {
        static let ceruleanBlue = UIColor(red:    0.0 / 255.0, green: 158.0 / 255.0, blue: 220.0 / 255.0, alpha: 1.0)
        static let cannonPurple = UIColor(red:  147.0 / 255.0, green:  78.0 / 255.0, blue: 132.0 / 255.0, alpha: 1.0)
        static let mulberryRed = UIColor(red:  197.0 / 255.0, green:  81.0 / 255.0, blue:  82.0 / 255.0, alpha: 1.0)
        static let fireBushOrange = UIColor(red:  225.0 / 255.0, green: 148.0 / 255.0, blue:  51.0 / 255.0, alpha: 1.0)
        static let saffronYellow  = UIColor(red:  242.0 / 255.0, green: 190.0 / 255.0, blue:  46.0 / 255.0, alpha: 1.0)
        static let sushiGreen = UIColor(red:  118.0 / 255.0, green: 184.0 / 255.0, blue:  59.0 / 255.0, alpha: 1.0)
        static let black = UIColor(white: 44.0 / 255.0, alpha: 1.0)
        static let white = UIColor.white
    }
}


・クラス変数 / クラスメソッドにて色を取得します。

class var primaryText: UIColor {
    return Palette.black
}

class func contentBackground() -> UIColor {
    return Palette.white
}


・デザイナー・エンジニア間でZeplinを使用している場合、カラーテーブルをエクステンションとして出力することが出来て便利です。

f:id:base_hideo:20170307150119p:plain


カラーテーマの適用

・アプリの外観を変更(LINEの着せ替えとか。)するような場合、ノティフィケーションを使用してカラーテーマを変更します。

最初にColorUpdatableプロトコルを定義します。

/// A protocol which denotes types which can update their colors.
protocol ColorUpdatable {
    /// The theme for which to update colors.
    var theme: Theme { get set }
    
    /// A function that is called when colors should be updated.
    func updateColors(for theme: Theme)
}


ノティフィケーションの名前を定義するためのプロトコル、ColorChangeObservingを定義します。

/// A protocol for responding to `didChangeColorTheme` custom notifications.
protocol ColorThemeObserving {
    /// Registers observance of `didChangeColorTheme` custom notifications.
    func addDidChangeColorThemeObserver(notificationCenter:
                                                   NotificationCenter)
     /// Removes observance of `didChangeColorTheme` custom notifications.
    func removeDidChangeColorThemeObserver(notificationCenter:
                                                   NotificationCenter)
    /// Responds to `didChangeColorTheme` custom notifications.
    func didChangeColorTheme(notification: Notification)
 }


ヘルパー用の関数を作ります。

private extension ColorThemeObserving {
     /// Returns the theme specified by the `didChangeColorTheme` notification’s `userInfo`.
     func theme(from notification: Notification) -> Theme? {
         // . . .
         return theme
     }

     /// Updates the colors of `ColorUpdatable`-conforming objects.
     func updateColors(from notification: Notification) {
         guard let theme = theme(from: notification) else { return }
         if var colorUpdatableObject = self as? ColorUpdatable, theme != colorUpdatableObject.theme {
             colorUpdatableObject.theme = theme
             colorUpdatableObject.updateColors(for: theme)
        }
    }
}


カラーテーマが変更されたノティフィケーションを受信します。

extension UIViewController: ColorThemeObserving {
    @objc func didChangeColorTheme(_ notification: Notification) {
        updateColors(from: notification)
    }
}


テーブルビュー、コレクションビューでも同様にノティフィケーションを受信します。

extension UITableViewController {
     @objc override func didChangeColorTheme(_ notification: Notification) {
         updateColors(from: notification)
         tableView.reloadData()
     }
}

extension UICollectionViewController {
     @objc override func didChangeColorTheme(_ notification: Notification) {
         updateColors(from: notification)
         collectionView?.reloadData()
     }
}


テーマ毎に色の変更を行います。

extension UIColor {
    class func backgroundContent(for theme: Theme) -> UIColor {
        switch theme {
            case .light:
                return Palette.white
            case .dark:
                return Palette.black
            }
    }
    // . . .
}


ビューコントラー側でテーマカラーを適用します。

extension ViewController: ColorUpdatable {
    func updateColors(for theme: Theme) {
        view.backgroundColor = .contentBackground(for: theme)
        childView.updateColors(for: theme)
        // . . .
    } 
}



色覚障がいについて

・男性の8%、女性の0.5%が何らかの色覚障がいを持っているとのことでしたが、実際には地域によって割合は異なります。

色に意味を持たせて、緑色は正常、赤色は異常という文化が広がっていますが、それらを識別できないと、そのメッセージは伝わりません。

iOS10では、色覚障がい者向けのカラーフィルター設定を持っており、全ての色のコントラストに適用します。

f:id:base_hideo:20170307150130p:plain

色覚障がい者向けのフィルター設定を適用します。

import InclusiveColor

extension UIColor {
    class func primaryText(for theme: Theme,
                        blindnessType: InclusiveColor.BlindnessType = .normal) ->      UIColor {
        let color: UIColor = {
            switch theme {
            case .light:
                return Palette.black
            case .dark:
                return Palette.white
            }
        }()
        return color.inclusiveColor(for: blindnessType)
    }
}



Try! Swift 2017 - 1日目「アプリを新次元に導く3D Touch」

こんにちは、iOSエンジニアの遠藤(秀)です。 3/2(木)〜 3/4(土)の3日間に渡って開催された世界的なイベント「Try! Swift 2017」に参加してきました。

1日目のセッション「アプリを新次元に導く3D Touch」についてまとめてみました。

セッション概要

この講演では3DタッチAPIで何ができるか?そして3DタッチAPIを使うベストプラクティスを学びます。元々どのような機能があり、iOS10でどのようなカスタマイズが加えられたかを見ていきます。クールな事例を通してあなたのアプリを3Dタッチに対応させる方法を探っていきましょう。



キーワード 、まとめ

・Home Screen Quick Actions(Static / Dynamic)
・Widget (Today Extension)
・Peek & Pop(UIPreviewInteractions)
・iOS 10 Notifications(Notification Content Extension)


Home Screen Quick Actions(Static / Dynamic)

3D Touchには、静的なStatic Actionsと、動的に動作を割り当てるDynamic Actionsの2種類があります。

BASEアプリでは、Staticアクションを実装しています。Info.plistへの追加と、ApplicationDelegateにメソッドの追加だけで手軽に実装することができます。

f:id:base_hideo:20170307143326p:plain


Info.plistに、UIApplicationShortcutItemTypeキーにアクション種別を表す文字列を、 UIApplicationShortcutItemTitleキーにアクション種別を表す文字列の設定が必須となります。

f:id:base_hideo:20170307143352p:plain

その他の設定値についての詳細はこちら。 https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html#//apple_ref/doc/uid/TP40009252-SW36


メニューが選択され、アプリが起動すると application:performActionForShortcutItem:completionHandler: メソッドが呼ばれます。

func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: Bool -> Void) {
    let handled = handleShortCutItem(shortcutItem)
    completionHandler(succeeded)
}



Widget (Today Extension)

iOS 10以降で、NCWidgetDisplayModeが追加され、Compact / Expandedの2つのモードがあります。

上記の説明だけで、あっさりとしたものでした。機能自体はiOS8から導入されていて、通知センターからアプリケーションへと送客できるので、流入経路を増やす意味でも有効ではないかと思います。

実装方法については、こちらで詳しく紹介されています。
https://techblog.yahoo.co.jp/ios/today-widget/

他にも流入経路を増やす方法として、2日目のセッション「 iOSにおけるDocument IndexingとApp Search」で、ECアプリの商品詳細画面に飛ばす手法が紹介されており、こちらの機能も検討したいところです。

App Search Programming Guide https://developer.apple.com/library/prerelease/content/documentation/General/Conceptual/AppSearch/index.html


Peek & Pop(UIPreviewInteractions)

内容をプレビューしたり、そのまま画面を遷移したりできます。文字通り覗き見と画面遷移をセットで考える必要があり、実装箇所が適切か検討する必要があります。

f:id:base_hideo:20170307143455p:plain


設定が無効になっている場合や、3D Touchに対応していないときは、ロングプレスを使って似た処理を実装することができます。

f:id:base_hideo:20170307143346p:plain


実装方法については、Appleのサンプルコードが提供されています。 https://developer.apple.com/library/content/samplecode/ViewControllerPreviews/Introduction/Intro.html


iOS 10 Notifications(Notification Content Extension)

iOS10から、プッシュ通知にメディア情報(Image / Audio / Video)を添付できるようになっただけでなく、UIのカスタマイズも可能になりました。

前述のPeak & Pop同様、プッシュ通知に添付されたメディアをプレビューすることができます。

f:id:base_hideo:20170307143445p:plain

できれば、アプリ側に流入して回遊してほしいところではあるので、プレビューでユーザに満足感を与えてしまうことが良いのか、判断に迷うところではあります。


その他

3D Touch対応することによって、AppStoreでフィーチャーされるかもしれません。

f:id:base_hideo:20170307145000p:plain

SendGridはゴールドプランがお得

こんにちは!CTOのえふしんです。

SendGridの料金プランの精査をしていたのですが、例えば、メールを月に500,000通送る場合、プラン別でかかるコストは以下のようになります。

f:id:f-shin:20170130202257p:plain

SendGridのプラン選定は、基本料金と超過料金をうまく組み合わせるのがコツのようで、月に50万通送る場合は、プラチナプランよりもゴールドプラン+超過料金の方がお得になります。

もし、システムが毎月送っているメールで月50万通ぐらいあるなら、プラスαの余裕を考えてプラチナプランで良いと思いますが、マーケティング目的などで、その月によって送るメールの数の差異が、結構あるようであれば、たまに90万通ぐらい行くことを想定しても、ゴールドプランの方がお得な使い方もあるように思えます。

そこで、超過料金を組み合わせたメール送信数とプラン別料金のグラフを書いてみました。

f:id:f-shin:20170130182316p:plain

メールの送信数が増えた時に、より単価の低い上位2プランの方がお得感があるのは当然のこととしても、上位2プランのうちゴールドとプラチナを比べた時に、下位に属するゴールドプランの健闘が目を引きます。

というのもゴールドのメール送信単価は0.06円、プラチナだと0.055円とメール送信単価に差があまりないのが理由で、120万通送った時のコストは、ゴールドで76,980円、プラチナプランで73,480円と、3,000円しか変わりません。

もし月に送る送信数が、相応にバラつくのであれば、ゴールドのほうが月平均のコストは低くなるかもしれませんので、サービスの成長にあわせて、ぜひ、ご検討ください。

サービスが順調に成長し、月に送るメールの桁が変わって、更に上を目指す場合には、SendGridを国内販売している構造計画研究所さんに相談すると適切なプランを教えてくれたりするようです。

なお今回は、有料プランの中でも、お試しプランに該当するブロンズプランは無視して話を書いておりますので、とりあえず試してみるのであれば、FREEプランまたは月1,180円で使えるブロンズプランから評価導入できますので是非、お試しくださいませ。

こちらにシミュレーションに使ったデータを公開しておきますね。

料金シミュレーション - Google スプレッドシート

BASEドメインをご利用の全てのショップで常時SSLが使えるようになりました

皆さん。こんにちは。BASEの藤川です。

今年の4月頃に、BASEドメインの常時SSL化の取り組みについて発表させていただきました。

thebase.in

リリース時は、新規登録ショップのみの対応だったのですが、本年の9月末に、全てのBASE社においてご提供しているドメイン(thebase.inや、shopselect.netなど...)をご利用のお店においてSSLがお使いいただけるようになりました。

3月末以降に登録したお店は、最初からSSL対応になっていたのですが、それ以前からお店を開いている場合は、お店の管理画面の方でSSLをオンにしていただく必要があります。

そのやり方ですが、ショップ管理画面の「ショップ設定」にある、「SSL設定」を有効にしていただくだけです。

f:id:f-shin:20161004003434p:plain

この変更によるお客様への影響は、いくつか想定がございます。

  1. Google アクセス解析の変更や、Google Webマスターツールの再登録が必要になります。
  2. それ以外の外部サイトもURLの変更が必要になる場合がございます。
  3. この設定変更に伴うSEOの影響については考慮はしておりますが、100%影響がないという保証はございません。
  4. SEO上の混乱を防ぐために一度SSLに変更したら原則的に戻す機能は提供しておりません。(http://に戻すことは可能です)
  5. httpでアクセスしても、httpsにリダイレクトされますので、これまでの外部リンクは切れません。

(SEOへの対策としまして、httpからhttpsへの恒久的な引っ越しを示す、301リダイレクトおよび、HTML上のcanonical URLの記述により、検索エンジンのクローラに、SSLサイトへ変更されたという誘導を行っており、最大限の配慮を致しております)

検索エンジンクローラの視点では、サイトの引っ越しという扱いになりますので、ショップ様のご判断でSSLへの設定変更をお願い致します。

また、独自ドメインをお使いのショップ様については、もう少しお時間をください。年内を目処に作業を進めております。

そもそもSSL対応って何?

SSL対応というのは、お手持ちのブラウザと、サーバの間の通信を暗号化し、仮に通信経路で情報を盗聴されても、送信したクレジットカード番号や個人情報が漏洩しないようにする通信方式になります。

http://○○.thebase.in ではなく、https://○○.thebase.in などとhttpsからから始まるURLが特徴です。

クレジットカードやメールアドレスをサーバに送信する画面では、暗号化するのは最低限のWebサーバのセキュリティの常識となっております。BASEにおいても、リリース当初から、決済やメールアドレスを登録する画面はSSLページで構成されております。

今回のSSLの対応は、従来のセキュリティが求められるページの対応ではなく、通常の商品ページなどをSSLに対応する変更となります。

そもそも今回の変更が何故必要なの?

これはインターネットを取り巻くトレンドの変化が影響しております。

昨今、世界中で、スマートフォンから町中で簡単に接続できる無線LANスポットがあります。無線LANスポットの中では、暗号化されていない通信方法や、悪意のある者によるニセの無線LANのアクセスポイントを提供し、通信内容を盗聴するリスクが懸念されています。そのため、無線LANに流れる通信内容は、すべてSSLで暗号化しておきたいというセキュリティ上の見解があります。

この見解を元に、Androidを提供するGoogle社、iPhoneを提供するApple社は、現在、フルSSLへの変化を推し進めております。

その施策の一つとして、2017年から徐々に、Googleのブラウザ(Chrome)において、SSLを使っていないページにアクセスした際に、ブラウザ上で警告を表示するようになる予告をしております。

2017年初頭においては、クレジットカード情報を送る画面などが警告の対象になり、徐々に、全ての非SSL画面において警告を出す予定である旨が公開されています。

当社では、このようなインターネット業界の変化に先んじて対応し、全ての画面をSSL化しておくというのが、今回の取り組みとなっております。

BASEが保有するドメインについては、9月末にて全てのショップ様にSSL化する機能を提供いたしました。 今後、独自ドメインもSSL化できるような作業を進めてまいります。

私共は、BASEショップをお使いの方々に、安心してお店を運営に専念いただける開発を続けてまいります。 年末から来年にかけてSSL化の話題も増えていくかと思いますので、ご都合の良い時に、SSLの設定もご活用いただきますようお願い申し上げます。