furodrive

About

Archive

2014-10-17

UIViewのレイアウト周りの処理はviewDidLayoutSubViewsの内部でやった方がいい

viewDidLayoutSubviewsメソッドが呼ばれるタイミングはAutoLayoutによってUIViewのフレームが調整・変更された後に呼ばれるのでレイアウト周りの処理はこのメソッドで行うといいらしい。

以下のviewDidLayoutSubviewsというメソッドを呼ばないといけない。

override func viewDidLayoutSubviews() {
    ...
}

レイアウト周りの処理をviewDidLoadで行なっていたのでタイミング的に正確なframeが取得できなくてはまってたけど、これで無事解決した!

2014-10-14

SwiftでUITableViewを扱う(コード例あり)

SwiftでUITableViewを使ったコード例を下に載せておく。 tableViewはStoryboard上で作成したものとする。

CustomCellクラスはXCodeのメニューから

File → New File →  Cocoa Touch

を選択して、UITableViewCellをサブクラスに選択してAlso Create xib FileにチェックをしてClassの入力欄にCustomCellと入力して作成する。

次にCustomCell.xibを選択してidentifierにCell,CustomClassに CustomCellと入力する。

あとはこのxibファイルをregisterNib(...)で登録すればViewController上からアクセスすることが出来る。

viewController.swift

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {

@IBOutlet var tableView: UITableView!

    let fruitsList:[String] = ["Apple","Orange","Mango"]

    override func viewDidLoad() {
        super.viewDidLoad()


        self.tableView.delegate = self
        self.tableView.dataSource = self

        var nib:UINib = UINib(nibName: "CustomCell", bundle: nil)

        self.tableView.registerNib(nib, forCellReuseIdentifier: "Cell")
    }


    func  numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1;
    }

     func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 80
    }

    func  tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return fruitsList.count ;
    }

     func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell

        cell.textLabel?.text = fruitsList[indexPath.row]
        return cell


    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

実行結果は以下のようになる。

コードの方はこちらのGithubリンクからダウンロードできます。

2014-10-08

SendGridを使ってメール送信を行う

某ウェブサービスをHerokuで運用しているのですが、今回メール送信にSendGridを使用することにしました。 SendGridに決めた理由は主に以下の2つです。

  • 1日200通以内のメールだと無料で運用できる
  • セットアップが簡単

個人が作った中小規模のWebサービスだと無料プランで十分運用できると思う。

プラグインの追加

まず、SendGridのプラグインを追加します。

$ heroku addons:add sendgrid

sendgridをインストール

$ pip install sendgrid

実装(Python)

メール送信のプログラムは下になります。

username,passwordは適宜置き換えてください。

import sendgrid
username = 'hoge'
password = 'hoge'

def send(self):
        sg = sendgrid.SendGridClient(name,password)

        message = sendgrid.Mail()
        message.add_to('addr_to@gmail.com')
        # タイトル
        message.set_subject('タイトル')
        # メッセージ本文
        message.set_text('この記事を読んでください')

        message.set_from('from_furodrive <furodrive@sample.com>')
        status,msg = sg.send(message)
2014-10-06

Swiftで16進数のカラーコードからUIColorに変換するextensionを書いた。

UIColor、毎回RGB指定で書くのが面倒なのでCSSみたいに16進数で指定して書けたら便利かなと思って作った。

import UIKit

func hexFromRGB(hex:String) -> (CGFloat,CGFloat,CGFloat,CGFloat) {
    var red: CGFloat   = 0.0
    var green: CGFloat = 0.0
    var blue: CGFloat  = 0.0
    var alpha: CGFloat = 1.0

    let index = advance(hex.startIndex, 1)
    let hexCode = hex.substringFromIndex(index)
    let scanner = NSScanner.scannerWithString(hexCode)
    var hexValue: CUnsignedLongLong = 0
    if scanner.scanHexLongLong(&hexValue) {
        if countElements(hexCode) == 6 {
            red   = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0
            green = CGFloat((hexValue & 0x00FF00) >> 8)  / 255.0
            blue  = CGFloat(hexValue & 0x0000FF) / 255.0
        } else if countElements(hexCode) == 8 {
            red   = CGFloat((hexValue & 0xFF000000) >> 24) / 255.0
            green = CGFloat((hexValue & 0x00FF0000) >> 16) / 255.0
            blue  = CGFloat((hexValue & 0x0000FF00) >> 8)  / 255.0
            alpha = CGFloat(hexValue & 0x000000FF)         / 255.0
        } else {
            print("err")
        }
    }

    return (red,green,blue,alpha)
}

extension UIColor {


    convenience init(hex: String = "") {
        var red: CGFloat  = 0.0
        var green: CGFloat = 0.0
        var blue: CGFloat  = 0.0
        var alpha: CGFloat = 1.0


        (red,green,blue,alpha) = hexFromRGB(hex)

        return self.init(red:red, green:green, blue:blue, alpha:alpha)
    }

}

使い方は下のようになります。

self.view.backgroundColor = UIColor(hex: "#ee82ee")

かなり生産性上がると思う。

2014-10-02

Macのメモ帳で⌘Vでペーストした時にスタイルを保存しない方法

iOS8になってSpotlightへのアクセスがとっても簡単(下にスワイプするだけ)になってそこからすぐに メモを検索できるようになり大変便利になりました!

自分は今までメモはDay Oneを使っていたのですがiOSとOSX、どちらからでも非常にアクセスしやすくなったので標準のメモアプリに乗り換えました。

大変快適です!が!しかし、メモアプリはなぜか⌘VでウェブページをペーストするとそのCSSスタイルまでコピーされてしまい、非常に使い勝手がよくありません。

が!しかし! ショートカットキーを上書きすれば⌘VでCSSスタイルを無視してコピーすることが出来るうになりましたのでその情報をシェアします。

システム環境設定 → キーボード → ショートカットキー → アプリケーション を選択 ➕ボタンを押して、下の画像の通りにテキストを入力してください。

以上で設定は完了です。これで⌘Vでスタイルを無視してペーストが出来るようになりました!

皆さんもこれをきっかけにメモアプリの使用を検討することをおすすめします。

2014-09-22

git pushを行ったら自動でipaファイルを生成してDeployGateに配布する

最近iOSアプリの配布にはDeployGateを使用しています。簡単に配布できて便利です!

今回はgit pushを使って自動でDeployGateに登録する方法を確立したのでその手順をメモしておきます。

ターミナルからipa を生成する

まずはターミナルからipaファイルを生成してみます。普通にやると面倒なのでshenzhenというライブラリを使ってipaを生成してみます。

`$gem install shenzhen

を入力してインストールしたあと、

$cd /path/to/xcode_project
$ipa build

を入力するとipaファイルが作成されるかと重います。

DeployGateにターミナルからpushしてみる

次に deploygateのコマンドを$curl https://deploygate.com/install.sh | /bin/shでインストールします。

インストールが終了したら

$dgate push your_app_name your_app.ipa

を入力してください。これだけでアプリがDeployGateに配布されます。

Bitbucketにレポジトリを登録

BitbucketにiOSプロジェクトのレポジトリを登録します。

Bitbucketにプッシュしたかどうかをローカルホストでも受け取れるようにする

このようなフックは標準だとローカルホストでは受け取れないので、UltraHookというサービスを使用してローカルホストでも受け取れるようにします。

$ gem install ultrahook
$ ultrahook github 8001

と入力すると

Forwarding activated...
http://github.furodrive.ultrahook.com -> http://localhost:8001

のような結果が表示されたらOKです!

これでhttp://github.furodrive.ultrahook.comで受け取ったWebHooksはlocalhost:8001に転送されます。

Bitbucketにwebhooksを登録

次にBitbucketのページにて APP → Settings → Hooks → Add hook を選択した後、hookのタイプをPOSTにして以下の様なURLを入力します。

 http://github.furodrive.ultrahook.com/push?group=your_group_name&path=/path/to/ios_project&app=your_ipa_name

以下はパラメータの説明です。

  • group: 配布先のグループ名
  • path: iosのプロジェクトのパス
  • app: ipaの名前(例: hoge.ipa)

これでBitbucketにPUSHしたら上のURLにPOSTリクエストが送信されます。

FlaskでAPIサーバーを書く

次にこのPOSTリクエストを受け取るサーバーをFlaskで作成します。

次にFlaskを使ってサーバーを作成します。

flask_app/app.py

from flask import Flask,request
import os

app = Flask(__name__)

@app.route("/")
def index():
    return "index"

@app.route("/push",methods=['POST'])
def push():
    if request.method == 'POST':
        data = request.data
        group = request.args.get("group")
        app = request.args.get("app")
        path = request.args.get("path")
        os.system("""cd {};
                        ipa build;
                        dgate push {} {};
                  """.format(path,group,app))
        return 'success'

if __name__ == '__main__':
    app.run(port=8001)

ここまでですべての手順は完了です。お疲れ様でした。

UltraHooksとflaskのサーバーを起動させたままiOSプロジェクトに対して git pushを実行してみると無事にipaファイルが作成されDeployGateにUploadされます!

おまけ: LaunchAgentsを使ってサーバーの起動を自動化する

(注意) おまけ編はMac OSの方のみとなります。

このままだと、毎回UltrahooksとFlaskのサーバーを立ち上げないと行けないのでMacにログインしたらこれらのサーバーが自動で起動するようにしておきます。

Ultrahooksを起動

/Library/LaunchAgents/com.furodrive.ultrahooks.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>EnableGlobbing</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>com.furodrive.watch</string>
    <key>ProgramArguments</key>
    <array>
        <string>ultrahook</string>
        <string>github</string>
        <string>8001</string>
    </array>
    <key>StandardErrorPath</key>
    <string>/tmp/com.furodrive.watch.err</string>
    <key>StandardOutPath</key>
    <string>/tmp/com.furodrive.watch.out</string>
</dict>
</plist>

Flaskを起動

/Library/LaunchAgents/com.furodrive.server.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EnableGlobbing</key>
<true/>
<key>Label</key>
<string>run_watch_server.job</string>
<key>ProgramArguments</key>
<array>
<string>python</string>
<string>/Users/haradashinya/project/watchman/manage.py</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/tmp/run_watch_server.job.err</string>
<key>StandardOutPath</key>
<string>/tmp/run_watch_server.job.out</string>
</dict>
</plist>

後はこれらのplistファイルを launchctl load ...で読みこめばMacにログインするだけで 自動的にサーバーが起動するようになります。

2014-09-17

ディレクトリ内にあるファイル名をターミナルにて一括で変更する

ディレクトリ内のファイルを一括で変更するいくつかの方法をメモ。 ここではhoge@2x.png,fuga@2x.pngをhoge.png,fuga.pngにリネームする場合について考える。

renameコマンドを使う場合

まずはrenameコマンドをインストール

brew install rename

あとはリネームしたいディレクトリに移動してrenameコマンドを以下のように発行すれば良い。

cd /path/to/will_rename_dir
rename 's/@2x.png/px.png/' *.png

shellスクリプトを使う場合

以下のrename.shをリネームしたいディレクトリに配置して実行すれば良い。

rename.sh

for file in *.png
do
    mv "$file" "${file/@2x.png/.png}"
done

あとはこれを

source rename.sh

で実行するだけ。

2014-09-15

Django経由でAmazon SNSを使ってPush通知を送る(Part4:Django編)

この記事はDjangoでAmazon SNSを使用してiPhoneにPush通知を配信するまでの流れのPart4です。

流れとしては以下のようになります。太字の箇所が今回説明する箇所となります。


Part1(準備編)

1.iOSに通知するメッセージを送るサーバー構築(今回はAmazon SNSサービスを使用)

2.通知サービスが有効になったApp IDを作成

3.Apple Push Notification Service(APNs)とサーバー間でメッセージをやりとりするための証明書を作成

4.Provisioning Profileを作成

Part2(iOS編)

5.iOSアプリに実装して端末識別用のDevice Tokenを取得してサーバーに送信

Part3(Amazon SNS編)

6.Amazon SNSのセットアップ

Part4(Django編)

7.Django側からAmazon SNSを経由して送信


ではDjango側の実装を行なっていきます。 なお今回はPython2.7.5,Django1.6で実装を行なっていきます。 またAmazon WebServiceのライブラリ、botoをインストールしておいてください。

まずはDjangoアプリを作成します。

# プロジェクトの作成
django-admin.py startproject pushserver

# deviceアプリを作成
cd pushserver
django-admin.py startapp devices

次にdeviceモデルを作成します。

pushserver/devices/models.py


import uuid
from django.db import models
from boto.sns import sns_connection

class Device(models.Model, Base):
    device_token = models.CharField(max_length=200, blank=False, unique=True, null=False)


    def register(self):
        '''
        Amazon SNSにデバイストークンを登録します。
        '''

        sns_connection = boto.sns.connect_to_region('ap-northeast-1',
                aws_access_key_id=AWS_ACCESS_KEY,
                aws_secret_access_key=AWS_SECRET_KEY)

        #ARNはAmazon SNS Mobile Pointに記載されています。
        sns_connection.create_platform_endpoint(
                platform_application_arn=ARN,
                token=self.device_token,
                custom_user_data='test')

 

次にpushserver/settings.pyのINSTALLED_APPSの中に'devices'を追記して以下のコマンドでDBを作成します。

python manage.py syncdb

pushserver/urls.py

/devicesで始まるurlに関する処理はdevices/urls.pyに処理をするようにさせます。


from django.conf.urls import patterns, include, url

urlpatterns = patterns('',
                       url(r'^devices/',include('devices.urls')),
                       )

pushserver/devices/urls.py

/devices/tokenのリクエストが来たら、/devices/views.pyのtoken_view()メソッドが呼ばれるようにします。


from django.conf.urls import patterns, include, url
from django.contrib import admin

urlpatterns = patterns('',
        url(r'^token$',views.token_view,name='token'),
        )

pushserver/devices/views.py

/devices/tokenにPOSTリクエストが来たら、DeviceTokenを持ったDeviceをDBに保存します。



def token_view(request):
    if request.method == "POST":
        device_token = request.body[1:-1]
        device = Device.get_or_create(device_token =device_token)
        device.register()
        return HttpResponse("success!")
 

ここまでの作業を行ってpython manage.py runserverを行なってサーバーを起動させたままにして Part2で作成したiOSアプリを開くとDeviceTokenがDBに保存されます!

次にAmazon Web ServiceをPython側から簡単に扱えるBotoというライブラリを使ってpython manage.py devices publishというコマンドを入力するとすべてのDeviceにPush通知を行う実装を行います。

devices/management/commands/publish.py



#coding: utf-8
import boto
from django.core.management.base import BaseCommand,CommandError
from devices.models import Device
import re
import os
import boto.sns
from django.conf import settings

class Command(BaseCommand):
    help = 'setup'


    def handle(self,*args,**options):
        AWS_ACCESS_KEY = settings.LOCAL_AWS_ACCESS_KEY
        AWS_SECRET_KEY = settings.LOCAL_AWS_SECRET_KEY

        # Amazon SNS Mobile Pointに記載されているarnを入力
        arn = 'arn:aws:sns:ap-northeast-1.../APP_NAME/APP_SANDBOX'






        sns_connection = boto.sns.connect_to_region('ap-northeast-1',
                                                    aws_access_key_id=AWS_ACCESS_KEY,
                                                    aws_secret_access_key=AWS_SECRET_KEY)

        for device in Device.objects.all():
            res = sns_connection.create_platform_endpoint(
                platform_application_arn= arn,
                token = device.device_token,
                custom_user_data = 'test'
        )

            endpoint = res.get('CreatePlatformEndpointResponse').get('CreatePlatformEndpointResult').get('EndpointArn')



            sns_connection.publish(target_arn=endpoint, message=u"Hello from Django")

 

Done!

ここまでがきちんと出来ていると

python manage.py devices publish

というコマンドを入力すると登録したすべてのデバイスにPush通知が行われます! お疲れ様でした:)

2014-09-12

Django経由でAmazon SNSを使ってPush通知を送る(Part3:Amazon SNS編)

この記事はDjangoでAmazon SNSを使用してiPhoneにPush通知を配信するまでの流れのPart3です。 太字の箇所が今回説明する箇所となります。


Part1(準備編)

1.iOSに通知するメッセージを送るサーバー構築(今回はAmazon SNSサービスを使用)

2.通知サービスが有効になったApp IDを作成

3.Apple Push Notification Service(APNs)とサーバー間でメッセージをやりとりするための証明書を作成

4.Provisioning Profileを作成

Part2(iOS編)

5.iOSアプリに実装して端末識別用のDevice Tokenを取得してサーバーに送信

Part3(Amazon SNS編)

6.Amazon SNSのセットアップ

Part4(Django編)

7.Django側からAmazon SNSを経由して送信


では具体的に手順を見ていきます。

6. Amazon SNSのセットアップ

Amazon SNSのページ → Navigation → Add a new App をクリックすると以下の画面が現れます。

以下の項目を入力します。

  • Application Name: アプリの名前
  • Push Platform: Apple Push Notification Service Sandbox (APNS_SANDBOX)
  • Choose P12 File: Part1で作成したp12ファイルを選択
  • Enter Password: P12 Fileのパスワードを入力

次にLoad Credentials from FileをクリックするとCertificate,Private Keyが挿入されるのでAdd New AppをクリックするとAppが作成されます。

Amazon SNSの管理画面からPush通知を行う

ここで管理画面からPush通知を行なってみます。 Apps → 作ったアプリの名前を選択 → Add Endpoints を選択するとプロンプトにdeviceTokenとuserDataの入力を促されます。deviceTokenにPart2で取得できるDevice Tokenを入力、UserDataにtestを入力してAdd Endpointsをクリックします。

次にEndpoint Action → Publish を選択すると以下のプロンプトが表示されます。

このMessageの項目に好きな文字を入力してみてPublish Messageを入力するとPush通知が送信されます。

Done!

これでAmazon SNSのセットアップ編は終了です。 次回はサーバーサイド(Django)の実装を行なっていきます。

2014-09-12

Django経由でAmazon SNSを使ってPush通知を送る(Part2:iOS編)

この記事はDjangoでAmazon SNSを使用してiPhoneにPush通知を配信するまでの流れのPart2です。

流れとしては以下のようになります。太字の箇所が今回説明する箇所となります。


Part1(準備編)

1.iOSに通知するメッセージを送るサーバー構築(今回はAmazon SNSサービスを使用)

2.通知サービスが有効になったApp IDを作成

3.Apple Push Notification Service(APNs)とサーバー間でメッセージをやりとりするための証明書を作成

4.Provisioning Profileを作成

Part2(iOS編)

5.iOSアプリに実装して端末識別用のDevice Tokenを取得してサーバーに送信

Part3(Amazon SNS編)

6.Amazon SNSのセットアップ

Part4(Django編)

7.Django側からAmazon SNSを経由して送信


では具体的に手順を見ていきます。

UIAppDelegate.h

ヘッダーにUIApplicationDelegate,NSURLConnectionDelegateを追加します。

@interface AppDelegate : UIResponder <UIApplicationDelegate,NSURLConnectionDelegate>

UIAppDelegate.m

PUSH通知が正しく設定されているとdidRegisterForRemoteNotificationWithDeviceToken:(NSData *)deviceTokenというメソッドが呼ばれて、deviceTokenが取得できます。 このdeviceTokenをサーバーにhttp://localhost:5000/devices/tokenに対してPOST送信します。

- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSString *deviceTokenValue = [deviceToken description];

    //Send deviceTokenValue to Server.
    NSString *urlForPost = @"http://localhost:5000/devices/token";
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlForPost]];
    request.HTTPMethod = @"POST";
    request.HTTPBody = [deviceTokenValue dataUsingEncoding:NSUTF8StringEncoding];

    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    [connection start];
}

//deviceTokenが正しくPOST送信されたら呼ばれる。
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSLog(@"Device Token is sent successfully!")
}

Done!

これでiOS側の実装は完了です。 次回はAmazon SNSのセットアップを行います。