AFNetworking 2.xで画像アップロードと画像参照

iOS でサーバ通信する際、多くの iOS アプリで AFNetworking が利用されています。ここでは AFNetworking の AFHttpSessionManager を使って画像のアップロードと参照を行います。

画像アップロード

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];

NSURLSessionDataTask *dataTask = [manager POST: "リクエストURL"
parameters: @{"リクエストパラメータ"}
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:UIImageJPEGRepresentation(image, 1.0)
name:@"file"
fileName:@"fileName"
mimeType:@"image/jpeg"];}
success:^(NSURLSessionDataTask *task, id responseObject) {
// 成功したときの処理
}
failure:^(NSURLSessionDataTask *task, NSError *erorr) {
// 失敗したときの処理
}];

画像をアップロードする際は constructingBodyWithBlock で画像データをサーバに渡します。ここでは jpeg の画像データをアップロードしています。サーバ側では name に指定したパラメータでデータを受け取ります。

画像参照

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFImageResponseSerializer serializer];

NSURLSessionDataTask *dataTask = [manager GET: "リクエストURL"
parameters: @{"リクエストパラメータ"}
success:^(NSURLSessionDataTask *task, UIImage *image) {
// 成功したときの処理
}
failure:^(NSURLSessionDataTask *task, NSError *erorr) {
// 失敗したときの処理
}];

画像参照時のリクエストは基本通常のリクエスト時と変わりませんが、responseSerialiser を AFImageResponseSerializer で指定します。これによってレスポンスオブジェクトを Image で受け取ることができます。

 

HipChat で CI する

チャットツールと CI ツールを連携させることでより柔軟な運用を行えます。例えば、HipChat から Jenkins のジョブを実行し、その結果を HipChat に通知させる。日々、チーム内のコミュニケーションツールの1つとして利用しているチャットツールから CI できれば、誰もが楽に状態を把握できます。また、問題があった場合のキャッチアップも早くなります。

使ったもの

  • Mac
  • Hubot
  • HipChat
  • Jenkins

※ Hubot と HipChat についてはこちら→ Hubot と HipChat で ChatOps を参照

Jenkins のジョブ実行結果を HipChat に通知

HipChat API トークンの取得 

HipChat に通知させるには API トークンが必要です。API トークンは HipChat の「Group admin」→「API」から取得できます。Type は Admin と Notification 2種類あります。(Admin はチームに関するすべての API へアクセスが許可され、Notificaion はルームにメッセージ送信のみ許可されています。)Label は自由にです。

f:id:tunanosuke:20141117004819p:plain

Create で API トークンが作成されます。

f:id:tunanosuke:20141117014021p:plain

HipChat プラグインをインストール

Jenkins には HipChat と連携するための HipChat プラグインがあります。それをインストールし Jenkins に先程作成した API トークンを登録することで Jenkins と HipChat  が連携できます。Jenkins の「プラグインの管理」からインストールします。

インストールできたら「システムの設定」で API トークンを登録します。Global HipChat Notifier Settings に API Token とルーム名と Jenkins の URL を設定すれば OK です。

f:id:tunanosuke:20141117011241p:plain

ジョブに HipChat の設定を追加

HipChat プラグインが正しくインストールされていれば、ジョブの設定に HipChat Notifications という項目が追加されています。対象のルーム名を入力します。Start Notification にチェックを入れるとジョブ開始時にも通知されます。

    f:id:tunanosuke:20141117012549p:plain

最後に、ジョブの設定の「ビルド後の処理」でも HipChat Notifications を追加すれば、ジョブの実行結果を HipChat に通知してくれます。

    f:id:tunanosuke:20141117013050p:plain

これで、HipChat にジョブの実行結果を通知する設定が整いました。対象のジョブを実行すると、

f:id:tunanosuke:20141117013826p:plain

ジョブの実行結果 Success という通知がくるようになります。

HipChat から Jenkins のジョブを実行

ジョブの実行結果を通知できるようになりましたが、ここでは HipChat からの命令を Hubot でスクリプト解析し Jenkins のジョブを実行させます。Hubot と HipChat は連携されている前提で、ジョブを実行するスクリプトを用意します。

Jenkins ジョブ実行用のスクリプト

module.exports = (robot) ->
robot.respond /jenkins (.*)/i, (msg) ->
config =
url: 'http://localhost:8080'
job = msg.match[1]
msg.send "ジョブ「#{job}」を実行します。"
robot.http("#{config.url}/job/#{job}/build").get() (err, res, body) ->
## 必要な処理を記述

このスクリプトは Hubot に対して {Jenkins ジョブ名} とメッセージが送られた場合に msg.match[1] でジョブ名を変数 job につめ実行させています。ジョブ実行のメッセージを送ると以下のような応答があります。実行結果も Success と通知されています。

f:id:tunanosuke:20141117015832p:plain

 

 チーム状態に関する情報をチャット上に集約できれば、今どんな動きがあってどこに問題があるのか把握しやすくなります。CI だけでなくクラッシュの情報なども確認できれば、より改善までのサイクルも早くできると思います。

 

Hubot と HipChat で ChatOps

                   f:id:tunanosuke:20141109151616j:plain          f:id:tunanosuke:20141109151647j:plain

 ここ最近、ChatOps というワードをよく耳にするようになりました。ChatOps の取り組みを行うにあたっての1つの手段として Hubot があります。Hubot については色々なサイトに記載されています。

GitHub社謹製! bot開発・実行フレームワーク「Hubot」:連載|gihyo.jp … 技術評論社

開発する上で何らかしらのチャットツールを利用しているところは多いかと思います。その チャットツールと Hubot を連携させることでテストやビルドやデプロイなどをチャット上から実行し結果をチャット上に通知することができます。それにより、チーム全体で状態を把握することができます。

今回は Hubot と HipChat を連携させ、HipChat 上から Hubot にレスポンスを投げ Hubot が応答する仕組みを作ります。

使ったもの

  • Mac
  • Hubot
  • HipChat 

 ※ Hubot のインストールについては以下を参照してください。

 Mac に Hubot をインストール - tunanosuke memo

HipChat に Hubot 用アカウントを作成

HipChat から Hubot にレスポンスを投げるには専用のアカウントを用意する必要があります。そのため始めに Hubot 用のアカウントを作成しておきます。以下のような Hubot ユーザを作りました。

 

f:id:tunanosuke:20141110115331p:plain

Adapter をインストール

Hubot と HipChat を連携させます。連携させるには Adapter が必要です。HipChat からの情報をスクリプトで解釈し、それを HipChat に伝える仲介役のような役割を担います。HipChat 用の Adapter は以下のコマンドでインストールします。

npm install hubot-hipchat --save

もしくは package.json

"hubot-hipchat": "^2.7.5"

を追記し npm install しても可能です。HipChat 意外のチャットツールと連携させたい場合はそれに合った Adapter をインストールすれば OK です。

インストール完了したら、環境変数を設定します。bin/hubot を編集します。

#!/bin/sh

set -e

npm install
export PATH="node_modules/.bin:node_modules/hubot/node_modules/.bin:$PATH"

export HUBOT_HIPCHAT_JID="Hubot 用アカウントの JID (Jabber ID)"
export HUBOT_HIPCHAT_PASSWORD="Hubot 用アカウントのパスワード"
export HUBOT_HIPCHAT_ROOMS="ルームの JID (Jabber ID)"
export HUBOT_LOG_LEVEL="debug"

exec node_modules/.bin/hubot "$@"

Jabber ID は "hoge_hoge@chat.hipchat.com" の形式の ID です。アカウント設定、ルーム設定から確認できます。

スクリプトを作成し Hubot と会話

 Hubot と HipChat の連携が可能になったので、Hubot に対して送ったメッセージをそのままリピートするスクリプトを書いてみました。

module.exports = (robot) ->
robot.respond /(.*)/i, (msg) ->
msg.send "#{msg.match[0]}"

スクリプトcoffeescript で書いています。Hubot を起動してメッセージを送り Hubot から応答があるか試してみます。

bin/hubot -a hipchat

-a オプションを付けることで使用する Adapter を指定することができます。起動したら HipChat から "good morning" と送ってみます。

f:id:tunanosuke:20141110125306p:plain

こんな感じでメッセージをリピートしてくれます。

チャットツールを使うことで状態を把握でき、色々自動化できそうなので運用がかなり効率化できそうです。

 

HipChat で CI する - tunanosuke blog

 

requests と beautifulsoup でバス時刻表を取得する

Python ライブラリの requests と beautifulsoup を使って自宅の最寄りにあるバス停の時刻表を取得してみました。これまでバスはめったに乗らなかったのですが、場所によってはバスの方が便利なことが多いなと気付き始めました。そんなこともあって、バス会社の HP からバス時刻表をクローリングしてみました。特に時刻表を取得して何かするわけではありません。ただの興味本位です。何かアイデアが降ってきたら色々やってみます。

 使ったライブラリ

  • requests … HTTP 操作のためのライブラリ
  • beautifulsoup  HTML を解析し WEB クローリングを簡単に行えるライブラリ

クローリングする  

クローリングをするにあたって始めにバス会社の HP の HTML がどのような構造になっているか確認する必要があります。だいたいどの HP も時刻表は table タグで構成されていることが多いです。早速見てみます。

f:id:tunanosuke:20141030134235p:plain

予想通り table で構成されていました。table タグの class 属性値である "timeTableWkd" で時刻表を構成する要素を取得できそうです。beautifulsoup では find や findAll を用いて取得できます。

busstop_soup = BeautifulSoup(busstop_request.text.encode(busstop_request.encoding))
time_table = busstop_soup.find("table", attrs = {"class": "timeTableWkd"})

 find の第一引数はタグ名、第二引数に属性値を指定します。取得ができたら table  の子要素である tr や th、td タグの情報を取得していきます。全体としてこんな感じになりました。

# -*- coding: utf-8 -*-

"""
scrape bus stop diagram
"""

import requests
from BeautifulSoup import BeautifulSoup

"""---------------------------------------------
main.
"""
def main():
headers = {
"User-Agent": "<ユーザエージェント>"
}

busstop_request = requests.get("<バス会社の URL>", headers = headers)
busstop_soup = BeautifulSoup(busstop_request.text.encode(busstop_request.encoding))
time_table = busstop_soup.find("table", attrs = {"class": "timeTableWkd"})

for tr in time_table.findAll("tr"):
hour = tr.find("th", attrs = {"class": "left"})
minutes = tr.findAll("td", attrs = {"class": "pl-6"})
print hour.text,
for minute in minutes:
if minute.text != "&nbsp;":
print minute.text,
print ""

if __name__ == "__main__":
main()

for 文の中では 時(hour)と 分(minutes)を取得しそれを単純にコンソールに吐き出しています。見づらくて申し訳ないですが、コンソール上には以下のように時刻表が吐かれます。

f:id:tunanosuke:20141030135552p:plain

注意すること

  1. 過度なアクセスは控えましょう。攻撃されていると勘違いされないためです。
  2. user-Agent でクローラーであることを知らせましょう。
  3. robots.txt を確認しておきましょう。

まとめ 

動的ページだと厄介ですが、基本的にはさくっと短時間で必要な情報がいつでも取得できるので便利です。時刻表以外にも、例えば物件情報なり店舗情報なりクローリングしてデータの収集にも利用できそうですね。

今回は beautifulsoup を使ってクローリングしましたが、個人的には casperjs が使いやすいです。テストフレームワークのため人間的操作をそのままコードに書けば良いので分かりやすく、動的ページにも対応しやすいのでおすすめです。 

 

iOS アプリ 開発環境まとめ

iOS アプリの開発環境周りは複雑ですよね。色々手順があり、なかなかつながりが見えにくかったりします。特に僕は iOS Dev Center とのやり取りを理解するまでは時間がかかりました。

キーチェーン ?

証明書 ?

プロビジョニング ?

.p12 ?

そこで、まだ理解が曖昧であれば参考にしていただければと。

 


iOSアプリ 開発環境まとめ // Speaker Deck

 

 情報が変わった場合は都度更新していきたいと思います。