CircleCIでiOSアプリをBuild

GitHubのmasterにpushすると、CircleCI上でbuildする事を試し中 circleci.yms 内で書くbuildコマンドからXcodeCUIでbuild出来る事を知る cmd+Bとかプレイボタンだけと思ってた。

xcodebuild test -scheme <sheme名> -destination 'name=iPhone 6'

CircleCI上でiOS Buildするまではサポートも絡んで長かったので、 今度手順を書く

Swift2のUIColorではnilが渡せない

Swift1.2->Swift2

Xcode7.0.1

  • 起動と同時にConvertしますか?
  • Convertをお願いすると、Diffの画面表示

上記手順であっという間にConvert完了

一部Errorは残る

  • SpriteKit SKTextureでのnilの扱いでエラー発生

    Nil is not compatible with expected argument type 'UIColor'

  • Swift2からはinitilizerでoptionalを許容しないようなコメントあり

stackoverflow


in Swift 1.2 the initializer you are calling on super used to accept an implicitly-unwrapped optional for the color, hence you were able to pass nil

in Swift 2, that same initializer no longer accepts an optional, you must pass a UIColor if you use it (see docs)

your solution of passing UIColor.clearColor() seems reasonable to me!

という事で

let texture = SKTexture(imageNamed: "tooth_normal")
super.init(texture: texture, color: nil, size: texture.size())

↓↓

let texture = SKTexture(imageNamed: "tooth_normal")
super.init(texture: texture, color: UIColor.clearColor(), size: texture.size())

でOK

Swift2からはcolor : nil がだめってのはわかったが、color: UIColor.clearColor()がなぜ初期値として代入出来るんだろ。

ちなみにUIColor.clearColor()は透明の値

Swift1.2まではcolor:nilを渡していたけど、Swift2からはinitでoptionalを渡せないので、何らかの値が必要。という事で、透明(UIColor.clearColor)を渡しておく。という事かな。

このあたりは理解が足りなすぎる。

PHPでpush通知を打つまでの流れ

iOS/Androidのpush通知

言葉

  • APNS Apple Push Notification Service
  • Google Cloud Messaging
    • 本記事では対象外

主にPHPのライブラリを利用しています(apns-php)

https://code.google.com/p/apns-php/wiki/CertificateCreation sample_push.phpを利用

この記事を読めばイメージがつかめます

参考

必要な物

参考URLのざっくり手順

  • iOS Dev center でApp Ids でアプリを登録
  • Push Notifications を利用するにチェック
  • 登録したAppを選択してDevelopment SSL Certificate > Create xxx
  • macCSR作成してアップロード
  • Development SSL Certificate 作成した証明書をダウンロード
  • Wクリックすると、キーチェーンに取り込まれる
  • キーチェーンアシスタントで左上:ログイン 左下:証明書 Apple Development iOS Push Service を右クリック
  • .p12で書き出す 書き出す時にpassを指定、または指定なしも可
  • .p12 > pemを作成する
    • openssl pkcs12 -in dev_push.p12 -out sample.pem -nodes -clcerts -passin pass:<passを指定していたら>
    • openssl pkcs12 -in dev_push.p12 -out sample.pem -nodes -clcerts -passin pass: <=passなしの場合
    • ここでpassを入力してもcan't read file とかで怒られてはまった -passinオプションで逃げた

端末に通知が届かない場合に確認する項目(ハマった)

  • iOS Dev Centerで登録したAppIdsのIDと一致しているか?

    • product > general > bundle identifier
  • アプリのPush通知利用がON になっているか?

    • product > Capabilities > Push Notifications
  • Provisioning Profile が iOS Dev Centerで登録したアプリのプロファイルになっているか?

    • product > Capabilities > Build Settings > Code Signing

Tips

  • iOS9から、アプリインストール時に毎回DeviceTokenが新規発行される事になったようです
  • 以前はApple様のタイミングでDeviceTokenが変わっていました

便利なライブラリ

apns-php

push を受けるだけのサンプルアプリ

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.

        // device token の発行
        let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge], categories: nil)
        UIApplication.sharedApplication().registerUserNotificationSettings(settings)
        application.registerUserNotificationSettings(settings)
        application.registerForRemoteNotifications()

        return true
    }
    
    // device tokenの発行に成功したら呼ばれる
    func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData ) {
        
        // <>と" "(空白)を取る
        let characterSet: NSCharacterSet = NSCharacterSet( charactersInString: "<>" )
        
        let deviceTokenString: String = ( deviceToken.description as NSString )
            .stringByTrimmingCharactersInSet( characterSet )
            .stringByReplacingOccurrencesOfString( " ", withString: "" ) as String
        
        print( deviceTokenString )
        
        
    }

    // 起動中 通知からの起動時に呼ばれる
    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
        //print("application:didReceiveRemoteNotification: " + userInfo.description);

        switch application.applicationState {
        case .Active:
            // 起動中
            print("active")
            break
        case .Inactive:
            // バックグラウンド中で、通知タッチでフォアへ
            print("inactive")
            break
        default: break
        }

    }

push発行のサーバサイド(apns-php)

<?php
/**
 * @file
 * sample_push.php
 *
 * Push demo
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://code.google.com/p/apns-php/wiki/License
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to aldo.armiento@gmail.com so we can send you a copy immediately.
 *
 * @author (C) 2010 Aldo Armiento (aldo.armiento@gmail.com)
 * @version $Id: sample_push.php 65 2010-12-13 18:38:39Z aldo.armiento $
 */

// Adjust to your timezone
date_default_timezone_set('Asia/Tokyo');

// Report all PHP errors
error_reporting(-1);

// Using Autoload all classes are loaded on-demand
require_once 'ApnsPHP/Autoload.php';

// Instanciate a new ApnsPHP_Push object
$push = new ApnsPHP_Push(
    ApnsPHP_Abstract::ENVIRONMENT_SANDBOX,
    'p12から作成した.pem' // 1つめの証明書
);

// Set the Root Certificate Autority to verify the Apple remote peer
$push->setRootCertificationAuthority('entrust.pem'); // entrustからダウンロードした2つめの証明書
//$push->setProviderCertificatePassphrase('pemにpass phraseがあれば利用');

//$push->setProviderCertificatePassphrase(''); //pemをつくるときに指定したパスワード passなし


// Connect to the Apple Push Notification Service
$push->connect();

// Instantiate a new Message with a single recipient
$message = new ApnsPHP_Message('c8c689e14fcfe31bf1bca8754c51e6235b1eae3a0297e552d0872aee9fb9868d'); // Device Token  <>スペースを除く

// Set a custom identifier. To get back this identifier use the getCustomIdentifier() method
// over a ApnsPHP_Message object retrieved with the getErrors() message.
$message->setCustomIdentifier("Message-Badge-3");

// Set badge icon to "3"
$message->setBadge(3);

// Set a simple welcome text
$message->setText('Hello APNs-enabled device!あいうえおやっほお=ー');

// Play the default sound
$message->setSound();

// Set a custom property
$message->setCustomProperty('acme2', array('bang', 'whiz'));

// Set another custom property
$message->setCustomProperty('acme3', array('bing', 'bong'));

// Set the expiry value to 30 seconds
$message->setExpiry(30);

// Add the message to the message queue
$push->add($message);

// Send all messages in the message queue
$push->send();

// Disconnect from the Apple Push Notification Service
$push->disconnect();

// Examine the error message container
$aErrorQueue = $push->getErrors();
if (!empty($aErrorQueue)) {
    var_dump($aErrorQueue);
}

array_walkの使い方

PHPクロージャについて調べてたら、

クロージャ

use の使い方

callback

と行き着いた で、サンプルに記載のあるarray_walkに出会う

しらなかったらforeachで回して。って実装をするような部分。
array_walk( array , callable ) でarrayの内容を引数にしたcallback関数を実装する事が出来る
callable には arrayの value / key を第1,第2引数として渡す事ができる (key / value の順ではない)

php.netのsampleが秀逸 で、こういう実装をしたいな。と惚れて読んだ。
次回、こういう処理があったらクロージャを使って実装しようと思う
PHP: 無名関数 - Manual

<?php
// 基本的なショッピングカートで、追加した商品の一覧や各商品の
// 数量を表示します。カート内の商品の合計金額を計算するメソッド
// では、クロージャをコールバックとして使用します。
class Cart
{
    const PRICE_BUTTER  = 1.00;
    const PRICE_MILK    = 3.00;
    const PRICE_EGGS    = 6.95;

    protected $products = array();
    
    public function add($product, $quantity)
    {
        $this->products[$product] = $quantity;
    }
    
    public function getQuantity($product)
    {
        echo "test";
        return isset($this->products[$product]) ? $this->products[$product] :
               FALSE;
    }
    
    public function getTotal($tax)
    {
        $total = 0.00;
        
        $callback =
            function ($quantity, $product) use ($tax, &$total)
            {
                echo $quantity;
                echo $product;
                
                $pricePerItem = constant(__CLASS__ . "::PRICE_" .
                    strtoupper($product));
                $total += ($pricePerItem * $quantity) * ($tax + 1.0);
            };
        
        array_walk($this->products, $callback);
        return round($total, 2);
    }
}

$my_cart = new Cart;

// カートに商品を追加します
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);

// 合計に消費税 5% を付加した金額を表示します
print $my_cart->getTotal(0.05) . "\n";
// 結果は 54.29 です
?>

Laravel4のLog laravel-debugbarを使う

次のプロジェクトがLaravel4を使うので、sampleを試している logをtail -f ではなく、画面に表示しながら確認出来るlaravel-debugbar 画面内でdebug/info/warning/error など出し分けたログをフィルタかけられるのが良い

手順

  • composer.jsonのrequireに
"barryvdh/laravel-debugbar": "1.8.*"
  • composer update
$ composer update
  • app/config/app.php のServiceProviderに追加
'Barryvdh\Debugbar\ServiceProvider',
  • app/config/app.php のaliasに追加
'Debugbar'           => 'Barryvdh\Debugbar\Facade',
  • debug trueにすると画面に表示
'debug' => true,

Vagrant上のMySQL(guest)にlocal(host)から接続する方法

どんな時に必要?

  • Vagrant上のDBにlocal(DBViewer or 0xDBEなど)から接続したい時

前提

  • Vagrantfileでportfoward済
    • host:xxxx => guest:3306

    Vagrantfile config.vm.network :forwarded_port, guest: 3306, host: xxxx

MySQLの設定

  • 待受アドレスの設定

    • /etc/mysql/my.conf or /etc/my.conf
    • サーバの持つ全てのIPアドレスを受けますという意味になる

    /etc/my.conf bind-address = 0.0.0.0

  • 権限付与 (ALL)

GRANT ALL PRIVILEGES ON *.* TO root@'%' IDENTIFIED BY 'password' WITH GRANT OPTION
  • MySQL再起動 (flushでも良いかもしれないです)
# service mysqld restart

Fitbit Charge HRを使ってみて

Fitbit Charge HR (small)を使い始めました!!

買う前にデメリットとして感じていた点

  • Runkeeperと連動出来ない
  • リアルタイムで心拍数が見れない
  • 腕につける事に抵抗が有る

利用者(私)の現在状況

  • 1日中キーボードを使う仕事なので、仕事中に腕時計をつける事に抵抗がある
  • オフの時でも腕時計はつけない
  • Fitbit Oneを1年半使っている
  • 月間平均50Km ( 6分/Km ) 目標は毎月100Kmという感じ
  • 走る時は腰のポーチにiPhone(Runkeeper) とFitbit Oneをつけている

使ってみて良かった点

  • 時計の代わりになり、移動中にスマホを取り出して時間確認する回数が減った
    • 腕を内側にひねりながら、時計を見るようなジェスチャーをすると、時間が表示される
  • 画面付近をダブルタップする事で、現在の心拍数は走っている時でも見れる
    • ダブルタップした時の表示項目は設定画面で選択出来る (心拍数にした)
    • リアルタイムに心拍数を表示し続ける事が出来ないだけ
    • ボタンをポチポチしても見れる
  • Fitbit Oneでは面倒だった睡眠計測が簡単
    • 常につけているので、夜の睡眠、昼寝でも睡眠として計測されている
  • 電池が予想より持つ
    • 週に1-2回の充電で持ちそうな感じ
    • 買った当初はしょっちゅうiPhoneと同期したり、ポチポチ心拍数を見たりしてたので、電池の減りが激しかった
    • 慣れてくると、同期することも少なくなるし、3日以上は持ちそうな感じ

そもそも (買おうと決心した理由)

  • 現在のペースを見てどうこういう程、走る事が習慣化出来ていない
    • 毎月コンスタントに100Km走ってから考える
    • 心拍を常に見れる腕時計型の機器は3万円近くするし電池の持ちはFitbit HR程長くない
  • 走っている時の心拍がどれくらいで推移しているのかが知りたかった
    • 日によって、同じ距離でも最大心拍数が違っているのかどうか程度
    • 最終的に迷っていたのは、胸に巻くタイプの心拍計測機器 (Runkeeperと連携が出来るから)
  • Fitbit Oneを1年以上使っていて、アプリのUIが最高に見やすい事を知っているので、心拍数もきっと見やすく表示してくれるだろうという安心感。
  • 普段の生活も含めて心拍数の推移が見える方が良い

雑感

Pebble Timeと迷っていたが、Fitbit HRにして良かった。Pebble TimeはRunkeeperとの連携が出来て、 リアルタイムのペースが見れるのは良かったが、自身の走行距離では、走りながらiPhoneで見たりするのと そんなに変わらないし1分1秒を争うほどの走力、習慣はない。 あと、Fitbit Oneをズボンからズボンに付け替え忘れていて、記録漏れが有る日があった。 心拍数の為に胸の下に巻く機器はつけるのが面倒そう。もうこれ以上機器を増やしたくないと思っていた部分もある。

購入する方への参考になれば

  • 実機が見れれば一番良いが、バンドサイズに種類があるので、要確認 https://www.fitbit.com/content/assets/chargehr/charge_hr_sizing_guide.pdf

  • 心拍数を図る際のつける場所 ( 時計ではないので計測し易い場所がある )

    • 購入する前まではこういう事知らなかったのでメモ
    • 通常時
      • 手首の骨から指1本分、体側につける
    • アクティビティ時
      • 手首の骨から指2-3本分、体側につける
      • 血流が多く、計測し易いみたいな事がFitbitのWebサイトに記載あり

各設定画面の画像

  • タップジェスチャー (画面付近をダブルタップした時に何を呼び出すか設定が出来る) f:id:tbrhdys:20150912193750p:plain f:id:tbrhdys:20150912193746p:plain f:id:tbrhdys:20150912193742p:plain f:id:tbrhdys:20150912193738p:plain f:id:tbrhdys:20150912193727p:plain f:id:tbrhdys:20150912193733p:plain f:id:tbrhdys:20150911200348p:plain