Hatena::ブログ(Diary)

Over&Out その後 このページをアンテナに追加 RSSフィード Twitter

2014-01-31

Estimote Beacon をリバースエンジニアリング

f:id:shu223:20140131172037j:image


Estimote のビーコン、「2014年初頭にはSDKから加速度センサや温度センサの情報にもアクセスできるようになる」って言ってた *1 のでずっと楽しみにしてるのですが、まだその気配がありません


で、最近 Core Bluetooth のプロファイルまわりをいろいろ調べてるうちに *2 、ふと


「もしかしたらもう普通に加速度センサや温度センサの値がアドバタイジングされてるんじゃないの?」


と思いつき、どんな Service / Characteristic がアドバタイジングされてるのか、 Core Bluetooth から観測してみました。


が、こんなのもう誰かがとっくにやってそうだ、と思いググってみると、Estimote をいろんな切り口からリバースエンジニアリングした海外記事を発見しました。



貴重な情報が載っていて、解析方法もおもしろかったのでかいつまんで紹介します。


使用チップ

ガッチリ接着されているカバーが容赦なく剥がされ、高解像度で基盤写真が晒されています。


使われているチップは、

The Estimote is built around the Nordic Semiconductor nRF51822, which explains their presence on the Nordic booth at CES. It’s a nice chip, basically a 32-bit ARM Cortex M0 CPU with 256KB of flash and 16KB of RAM with a built-in 2.4GHz radio supporting both Bluetooth LE as well as 2.4GHz operation―where the 2.4GHz mode is on air compatible with the nRF24L series products from Nordic.

とのこと。


他のビーコンモジュールとスペック上で比較する際に参考になりそうです。


アドバタイジングデータの解析

下記のように推測されていました。

  • First two bytes are the Apple Company Identifier (Little Endian) 0×0042.
  • The third byte―at least most likely―specifies the data type, which is 2.
  • The fourth byte specifies the remaining data length, 21 bytes.
  • Estimote Beacons have a fixed iBeacon UUID of B9407F30-F5F8-466E-AFF9-25556B57FE6D.
  • The next two bytes after the iBeacon UUID are the iBeacon Major (Big Endian), i.e. 0xED4E, 60750.
  • The next two bytes after the iBeacon Major are the iBeacon Minor (Big Endian), i.e. 0×8931, 35121.
  • The final byte is the measured RSSI at 1 meter away, i.e. 0xB6, -74.

UUID, Major, Minor, RSSIなど、いたって一般的なiBeaconモジュールがアドバタイジングする内容です。


Method Swizzling や class-dump で SDK を解析

Estimote の iOS SDK はバイナリとして提供されているので中身がわからないのですが、この記事ではSDK内部で用いられているCore BluetoothフレームワークのメソッドをMethod Swizzlingして処理内容を出力させ解析しています。


具体的には、CBXpcConnection というCoreBluetoothフレームワーク内のクラスの

- (void)handleMsg:(int)arg1 args:(id)arg2;
- (void)sendMsg:(int)arg1 args:(id)arg2;

というメソッドを


- (void)handleMsgSwizzled:(int)arg1 args:(id)arg2;
- (void)sendMsgSwizzled:(int)arg1 args:(id)arg2;

に置き換え、


- (void)handleMsgSwizzled:(int)arg1 args:(id)arg2
{
    NSLog(@"handleMsg: %d, %@", arg1, arg2);
    
    [self handleMsgSwizzled:arg1 args:arg2];
}

- (void)sendMsgSwizzled:(int)arg1 args:(id)arg2
{
    NSLog(@"sendMsg: %d, %@", arg1, arg2);
    
    [self sendMsgSwizzled:arg1 args:arg2];
}

no title


このようにNSLogで内容を出力するようにしています。


で、さらに詳しく解析できるようにしたり、

- (void)handleMsgSwizzled:(int)arg1 args:(id)arg2
{
    int msgId = arg1;
    NSDictionary *args = arg2;
    
    NSString *deviceUUID = [[args objectForKey:@"kCBMsgArgDeviceUUID"] UUIDString];
    
    if (msgId == 4) {
        NSLog(@"state change: %@", [args objectForKey:@"kCBMsgArgState"]);
        
    } else if (msgId == 34) {
        NSDictionary *advertisementData = [args objectForKey:@"kCBMsgArgAdvertisementData"];
        
        NSLog(@"device discovered: %@, name = %@", deviceUUID, [advertisementData objectForKey:@"kCBAdvDataLocalName"]);
        
    } else if (msgId == 35) {
        NSLog(@"device connected: %@", deviceUUID);
    } else if (msgId == 51) {
        NSLog(@"device services discovered: %@", deviceUUID);
    } else if (msgId == 59) {
        NSLog(@"device service characteristics discovered: %@", deviceUUID);
    } else if (msgId == 65) {
        NSLog(@"device characteristic read: %@, handle = %@, value = %@", deviceUUID, [args objectForKey:@"kCBMsgArgCharacteristicHandle"], [args objectForKey:@"kCBMsgArgData"]);
    } else if (msgId == 66) {
        NSLog(@"device characteristic written: %@, handle = %@", deviceUUID, [args objectForKey:@"kCBMsgArgCharacteristicHandle"]);
    } else {
        NSLog(@"handleMsg: %d, %@", arg1, arg2);
    }
    
    [self handleMsgSwizzled:arg1 args:arg2];
}

no title


この結果を踏まえて ESTBeacon クラスの下記メソッドもSwizzlingしたり、

- (void)pairSensorFirstPart;
- (void)pairSensorSecondPart;

class-dumpして非公開クラスのメソッドを出力して、そこで見つけた気になるメソッドをまたswizzling したりしてSDKの処理内容を解析しています。



で、以上の解析結果をもとにまとめられた Estimote の Characteristics 仕様がこちら。


no title


バッテリーレベルなどはありますが、どうやら 加速度センサや温度センサの情報はまだ現段階のファームではアドバタイジングされてない ようです(まだ???となっている未開のCharacteristicsもありますが)。


所感

当初の目的だった「加速度センサや温度センサのアドバタイジングデータ」は結局見つかりませんでしたが、個人的には「バイナリの解析ってこうやってやるのかー」と非常に勉強になりました。


関連記事


2014-01-30

Core Bluetooth / BLEで音声データをやりとりする

以前書いた2つの記事でわかったことは、BLEは少量データ/低頻度での用途に特化することで省電力を実現した規格なので、音声データをやり取りするような用途にはそもそも向かない、ということでした。

ただ、MFiなし、WiFiもなしでデバイスとiOSアプリを無線通信させたい場合、iOSの現状の公開APIで可能な範囲ではやはりCoreBluetooth/BLE一択になってくるので、どうにかならないものかと。


そんなわけで、いろいろと調べたり聞いてみたり試行錯誤してみたことを書いておきます。


(2015.8追記)この記事は古く、書いた当時はBLEについての知識も乏しかったので内容には多分に誤りが混じっている可能性があります。


Bluetooth4.0イヤホンはどうやって音声データを流してるのか

疑問だったのは、自分がいま使ってるイヤホンは、Bluetooth4.0であることでした。



自分は Bluetooth4.0 = BLE だと思っていたので、何でBLEで音楽聴けてるんだろう?と。ビットレートをそこまで落としてる感じもしないし。


というわけで、FacebookのWF-BTLEグループで、次のような質問をしました。


BLEのプロファイルについてよくわからない点があるので、質問させてください。


BLEは『少量のデータを低頻度でやりとりする用途に、ハードウェアの低コスト化と、コイン型電池で1〜2年間の連続動作ができる超低消費電力に特化』(こちらの記事より引用)した規格であると認識しています。


なので、BLEのGATTベースのプロファイルは、Heart Rateや、Battery Serviceなど、少量データ・低頻度で済む用途のものが定義されているし、GATTの規格自体も大きいデータを流しっぱなしにするようにはなっていない(アトリビュートのvalueは512バイトまで)と。


ただよくわからないのが、世の中にはBluetooth4.0用のヘッドセットなども出ている点です。


上記ヘッドセットのページにはプロファイルにHFPを使用しているようなことが書いてあります。私の認識ではBLE機器ではGATTベースのプロファイルしか使えず、HFPなどは3.0以前の従来規格でしか使用できない、というものなのですが、そんなことないのでしょうか?もしくは、フレームレートを抑える等の工夫をしてGATTの規格内でHFP相当の通信ができるようにしている、ということなのでしょうか?


見当違いのことを言ってるかもしれませんが、識者のみなさま、ご教示いただけると幸いです。


ちなみにこの質問をする意図としては、iOSのCoreBluetoothで、デバイスと音声データのやり取りをしたい(音質は5kbpsぐらいまで落とせる)、というものになります。BLEはそもそもそういう用途の規格ではないとは思いますが、MFiなし、WiFiもなしでデバイスとiOSアプリを無線通信させたい場合、やはりCoreBluetooth/BLE一択になってくるので。。


そして、回答をいくつかいただきました。(掲載許可は得ていないので)原文を載せるのは避け、要約すると、

  • Bluetooth4.0は、3.0までの技術に、Low Energyの技術を統合したもの。なので、3までの技術も使える
    • 両方に対応したものをデュアルモードと呼ぶ
  • ただ、Core Bluetoothでは、Low Energyの部分しか制御できない
  • BLEを音声通信的なものに利用するのは、あり。CoreAudioでBluetothのヘッドセットへルート切り替えが、最近はできるようになったはず。
  • 参考リンク

という明快な回答をいただきました。


なるほど、まず大前提として、「Bluetooth 4.0 = BLE」というのが大きな勘違いでした *1


「デュアルモード」というのは知ってましたが、それは3.0にも対応している、という意味だと思っていて、4.0の仕様が3.0の仕様も含んでいる、ということだとは知りませんでした。


で、音楽を聴けるヘッドセットやイヤホンは、3.0までの技術を使っていて、それはMFiなしで使えるCoreBluetoothでは制御できないと。


また「Bluetoothを扱いたければCoreBluetoothだ!」 *2 とばかり思っていたので、オーディオのルート切り替えは盲点でした。


オーディオセッションによるBluetoothデバイスへのルート切り替え

そういえば、ルート切り替えの定義でBluetoothなんちゃらっての見たことあるな、というのはなんとなく記憶にあったので、改めて見てみると、

kAudioSessionInputRoute_BluetoothHFP
kAudioSessionOutputRoute_BluetoothHFP
kAudioSessionOutputRoute_BluetoothA2DP

というのがありました。


これができれば、HFPプロファイルに対応したデバイスから音声データを受け取ってそのままAudio Unitとかで波形処理できるので、なかなか良さそうです。iOS7からdeprecatedになってましたが。。


Core Bluetoothでどうにかしてみる

上述したようにオーディオセッションでルートを切り替えることで音声データのやりとりができそう、とわかったものの、デバイス側がいまのところGATTベースのプロファイルにしか対応してないので、結局Core Bluetoothでどうにかすることにしました。


※ペリフェラル側でS/N比などをみて音声データを切って送信する前提です。


[ペリフェラル側]

- (void)peripheralManager:(CBPeripheralManager *)peripheral
    didReceiveReadRequest:(CBATTRequest *)request
{
    // 音声バッファの続きを渡す
    request.value = [self soundDataFromCurrentIndex];
    
    [peripheral respondToRequest:request
                      withResult:CBATTErrorSuccess];
}

上記コード内で呼んでいる soundDataFromCurrentIndex というメソッドでは128バイトずつ *3 音声バッファのデータを渡すようにしています。


[セントラル側]

- (void)                 peripheral:(CBPeripheral *)peripheral
    didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic
                              error:(NSError *)error
{
    NSData *data = characteristic.value;
    NSUInteger bytes = data.length;

    [self.receivedData appendData:data];
        
    // 次のデータを読み込む
    if (bytes >= kMaxBytes) {

        [cbPeripheral readValueForCharacteristic:self.characteristic];
    }
    // 受信完了
    else {
        
        // receivedDataに対して処理を行う
    }
}

全部読み終わるまでreadし続ける、という(とくにTips要素もない)普通の処理です。*4


試してみた結果

上記方法で試しに 15kB の wavデータ(16bit, 16kHz)を送ってみると、20秒ちょいかかりました。先日計測した速度とだいたい同じぐらいなので妥当そうですが、送ったのは再生時間が1秒にも満たないデータなので、リアルタイムにはほど遠いレベルです。


5kbpsぐらいの通信速度である程度リアルタイムに送るには、1秒当たり600バイトぐらいに収める必要があるので、ビットレートを落とすだけじゃなく、いったんaacとかの圧縮フォーマットにエンコードして送る必要がありそうです。


関連記事

Bluetooth Low Energy (BLE) のサービス/キャラクタリスティックの構成例一覧 - Over&Out その後

ios - Reading long characteristic values using CoreBluetooth - Stack Overflow

iOS のオーディオ/サウンド処理について学べる書籍10冊+α - Over&Out その後

Bluetooth 4.0 および Bluetooth Low Energy (BLE) に関する技術情報のまとめ - Over&Out その後



*1:これ何度か気になって調べたうえで勘違いしてたので、「Bluetooth 4.0 = BLE」と間違った解説してるページがあったんじゃないかと。

*2:MultipeerConnectivityもありますがあれはiOS to iOSなので今回の目的には合わない。

*3:256以上だと挙動がおかしかった(送信データと受信データとサイズが合わなかったり)ので、何らかの制約があるのかなと。

*4:CBATTRequest に offset というプロパティがあって、もしかしたらこういうケースで使うものなのかもしれませんが、誰がどうそのoffsetを管理するのかわからなかったので結局使用しませんでした。

2014-01-29

Bluetooth Low Energy (BLE) のサービス/キャラクタリスティックの構成例一覧

既存の GATT ベースプロファイルとは違う用途でBLE通信を行いたい、つまり自分で GATT ベースの独自プロファイルを定義したい場合に、どんな感じでサービス(Service / CBService)とキャラクタリスティック(Characteristic / CBCharacteristic)を構成したらいいのかがよくわからなったので、既存プロファイルの構成例がまとまってるページがないかなーと探してみたところ、BLEのポータルにまとまってました。


たとえば Heart Rate のサービスを見てみると、

という3つのキャラクタリスティックを持っていることがわかり、それぞれのキャラクタリスティックのページからは、valueがどんなフォーマットで、最大値最小値はいくらか、というようなことが書いてあります。


というわけで独自のGATTベースプロファイルによる通信を行いたいときは、このポータルで似たようなコンセプトのサービスを探して参考にできそうです。


2014-01-28

Bluetooth 4.0 および Bluetooth Low Energy (BLE) に関する技術情報のまとめ

Bluetooth 4.0 や BLE に関して、「あれどこに書いてあったっけ」とならないように自分的お役立ち情報をここにまとめておきます。


(2014.12.22追記)引用元記事では記述や数値が修正されている部分があります。正確な情報は元記事やBluetooth SIGのドキュメントを参照してください。


Bluetoothのはなし(2)|Wireless・のおと|サイレックス・テクノロジー株式会社

この記事はちょっと突っ込んだ情報をわかりやすく簡潔に書いてくれていて、とても参考になります。


[Bluetoothのバージョンについて]

まず明らかにしておきたいのは、「Bluetooth Low Energy(LE)」と「Bluetooth 4.0」という用語の定義は同じではない、ということです。「Bluetooth LE」は Bluetooth 4.0 で新たに追加された新しい通信方式ですが、「Bluetooth 4.0」は以前の Bluetooth バージョンの仕様全て(2.1 で追加された高速モードの EDR や、3.0 で追加された超高速モード HS も)を含んでいいます。つまり「Blueotooth X.X」という表記はプロトコル仕様であってハードウェア仕様を示すものではなく、ハードウェア拡張仕様についてはバージョンの後につく「EDR」とか「HS」とか「LE」によって示されるのです。例を挙げると


「Bluetooth 1.2」...1Mbps の Bluetooth (BDR)

「Bluetooth 2.1」...1Mbps の Bluetooth, SSP ペアリングなどの拡張仕様に対応

「Bluetooth 2.1+EDR」...上に加えて 2Mbps/3Mbps の EDR 高速モード対応

「Bluetooth 3.0+EDR」...上に加えて拡張省電力モード(EPC)などに対応

「Bluetooth 3.0+HS」...上に加えて WiFi 利用の超高速モード(HS)に対応

「Bluetooth 4.0+HS」...上に加えて GATT アトリビュートに対応

「Bluetooth 4.0LE」...GATT アトリビュートに対応、LE モードに対応(但し、この表記からBDR/EDR対応状況は読み取れない)


[BLEで接続時間が改善された理由]

レガシイ Bluetooth の場合、1対のマスター・スレーブが使用する通信周波数は 1MHz 幅 79 本のチャネルを 625 μ秒単位で出鱈目に(疑似乱数に沿って)飛びまわります。Bluetooth のホッピングは徹底しており、デバイス検索時の問い合わせ手順(Inquiry)すら周波数はホッピングします。これは、PAN(Personal Area Network)の一種である Bluetooth においては多くの機器が高い密度で密集すると考えられたため、スペクトラム拡散(Spread Spectrum)を用いて周波数衝突を避けようとした設計だと思われます。


しかしこの結果、レガシイ Bluetooth ではデバイス検索においてもマスター・スレーブ間のホッピングパターン同期手順が必要となり、ペアリングの成立していないデバイス検索には長くて数秒、ペアリングが成立しているデバイスの再接続にも最短で 0.1 秒程度の時間を要することになりました。これは携帯電話のヘッドセットのような用途には許容できる時間ですが、センサー・ネットワークのように「数秒に一度、十数バイト程度のデータ」を送信する用途においては消費電力や応答時間の点で不利になります。

Bluetooth LE ではチャネルの数を 79 から 40 に半減させて周波数精度の要求を下げ、40 本あるチャネルのうち 3 本を「Advertise Channel」として予約し、デバイス検出は常にこの 3 本の周波数を使うように仕様が単純化されました。このため、デバイスの検索〜接続〜通信に要する遅延時間は 10msec 未満に短縮されたと言われています。


[Connection Intervalの時間単位]

「Connection Interval」時間単位(1.25msec の整数倍)


[同時接続可能な台数]

レガシイ Bluetooth の一大制約だった「1台のマスターに同時接続・通信可能なスレーブ数が最大7台」という 3bit のリンクアドレス長は 32bit に大幅拡張され、実用上無制限のスレーブが接続可能になっています。


Bluetoothのはなし(5)|Wireless・のおと|サイレックス・テクノロジー株式会社

上の記事と同じシリーズ。この回ではBluetoothを本気で使おうとすると必ず悩まされる「WiFiとBluetoothの干渉」問題について詳しくかつわかりやすく書かれています。


[WiFiとBluetoothの干渉]

WiFi(2.4GHz) と Bluetooth は同じ周波数帯域を使います。なので両者が同時に稼動すると干渉が発生することを避けられません。両者が同じ室内で稼動する程度であれば「ある程度」の干渉で済むのですが、携帯電話のように小型機器に WiFi と Bluetooth を実装するシステムでは深刻な影響が出ます。小型機器では実装面積が足りず WiFi と Bluetooth のアンテナが隣接することを避けがたい(場合によっては共用アンテナを使うこともある)ため、干渉の影響が桁違いに大きくなるためです。


[干渉による影響]

WiFi と Bluetooth の電波が衝突すると

  • WiFi から見た場合:チャネル内に Bluetooth の電波が入ると、一部のサブキャリアが崩れる。
  • Bluetooth から見た場合:ホッピング通信しているなかで WiFi チャネルと衝突したフレームが消える

という影響が出ます。

WiFi と Bluetooth がぶつかると、WiFi はパケット損失を検出し送信レートを落とす(シンボル冗長度を上げ、変調精度を下げる)ため性能微減、Bluetooth は損失したパケットをタイムアウトで検出し再送する(このとき FH によって以前衝突したのとは違う周波数で再送される確率が高い)ので性能大減というような影響となって現われます。


[電波の強さ]

電波の強さも両者で異なっており、一般的な WiFi システムが送信出力 15dBm(30mW) 前後なのに対し、Bluetooth Class2 は 4dBm (2.5mW) 以下です。つまり一般的には、WiFi と Bluetooth がぶつかると Bluetooth が負けることが多いのです。


Google サイト

[Connection Intervalの最小間隔]

Connection Intervalは、iOSに対応したBLE機器の場合、37.5msecが最小間隔になっており、それ以上の通信をおこなうことはありません。

そのため、Characteristicの読み書きには通常は 40msec ほどの時間が掛かると思ってプログラムを組む必要があります。各OSのBLE APIが非同期処理になっているのもこのような理由があるからと思います。


[送信データサイズ]

一回の通信でやりとりできるデータのサイズは 20バイトほどが基本単位になっているので、現在のBLE機器のCharacteristicのサイズも 20バイト以下になっているものが多いです。

BLE仕様では、より大きなCharacteristicのRead/Writeを可能にするプロトコルもありますが、それらをサポートしていないOSもあるので、当面は Characteristicは 20バイト程度以下と思ってよいと思います。


[Read/Writeの頻度について]

ひとつのRead/Writeをおこなった後に、その応答が返ってくる前に次のRead/Writeをおこなうことは、BLE仕様としては認められていないので、その点も注意が必要です。

大抵のOSはRead/Writeの要求をキューによりシリアライズしているようなので、特に意識する必要はなさそうですが、あまり大量のRead/Writeをおこなうと、キュー詰まりが起きて、レスポンスが悪くなることがあります。

効率よく通信をおこないたいのであれば、アプリケーションの実装側で Read/Writeの頻度やタイミングをうまく調整した方が良いでしょう。


[通信途絶によるコネクションクローズ後の再接続について]

BLE通信の Link Layerでは、GATTの通信の有無に関わらず、Connection Interval毎に常に通信をおこなっており、もし数秒間その通信が途絶えるとリンクが切れたと判断されて、コネクションがクローズします。

CentralまたはPeripheralのどちらかが明確にコネクションをクローズしたときはすぐに切断状態になりますが、上記の通信途絶によるクローズ直後は相手側がまだ切断を認識していないことがありますので、その場合、すぐには再接続ができないことになります。



本記事は随時更新していきます。


2014-01-27

konashiをSDKなしで使う

konashiは親切にもドキュメントでサービス(Service)やキャラクタリスティック(Characteristic)の仕様を公開してくれているので、


オフィシャルに提供されている iOS SDK を使わなくても、Core Bluetoothから直接接続・通信することが可能です。


konashi
konashi
posted with amazlet at 14.02.04
スイッチサイエンス
売り上げランキング: 17,884


konashi の SDK は Core Bluetooth の薄いラッパーなので、全然SDKを使うことによる不自由は感じないのですが、この方法を試しておくことで、他のBLEデバイスも、必要な情報が公開されてさえいればSDKなしで接続できることがわかるようになるというメリットがあるかと思います。


やり方

すごくシンプルです。まず、普通に2台のiOSデバイス間で接続・通信できるようにCore Bluetoothでつくっておいて、あとは


セントラル(iOSアプリ)からペリフェラル(konashi)を探す際に、ServiceのUUIDとして "0xFF00" を使う


だけ。


ただし、genuuidコマンドから生成したUUIDのように、文字列からのCBUUIDオブジェクト生成

CBUUID *uuid = [CBUUID UUIDWithString:@"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx"];

だけですが、

konashiのように16進数のUUIDからCBUUIDオブジェクトを生成する場合は、次のようにします。

UInt16 temp = uuid16 << 8;
temp |= (uuid16 >> 8);

NSData *data = [[NSData alloc] initWithBytes:(char *)&temp length:2];
CBUUID *uuid = [CBUUID UUIDWithData:data];

あとは、 scanForPeripheralsWithServices:options: するときにこのサービスを指定するもよし、centralManager:didDiscoverPeripheral:advertisementData:RSSI: が呼ばれたときにこのサービスを提供しているかどうかを判定するもよし、です。


konashiのcharacteristic

キャラクタリスティックはkonashiとやりとりする情報の種類ごとに定義されています。


// PIO
#define KONASHI_PIO_SETTING_UUID                                0x3000
#define KONASHI_PIO_PULLUP_UUID                                 0x3001
#define KONASHI_PIO_OUTPUT_UUID                                 0x3002
#define KONASHI_PIO_INPUT_NOTIFICATION_UUID                     0x3003
#define KONASHI_PIO_INPUT_NOTIFICATION_READ_LEN                 1

// PWM
#define KONASHI_PWM_CONFIG_UUID                                 0x3004
#define KONASHI_PWM_PARAM_UUID                                  0x3005
#define KONASHI_PWM_DUTY_UUID                                   0x3006

// Analog
#define KONASHI_ANALOG_DRIVE_UUID                               0x3007
#define KONASHI_ANALOG_READ0_UUID                               0x3008
#define KONASHI_ANALOG_READ1_UUID                               0x3009
#define KONASHI_ANALOG_READ2_UUID                               0x300A
#define KONASHI_ANALOG_READ_LEN                                 2

// I2C
#define KONASHI_I2C_CONFIG_UUID                                 0x300B
#define KONASHI_I2C_START_STOP_UUID                             0x300C
#define KONASHI_I2C_WRITE_UUID                                  0x300D
#define KONASHI_I2C_READ_PARAM_UIUD                             0x300E
#define KONASHI_I2C_READ_UUID                                   0x300F

// UART
#define KONASHI_UART_CONFIG_UUID                                0x3010
#define KONASHI_UART_BAUDRATE_UUID                              0x3011
#define KONASHI_UART_TX_UUID                                    0x3012
#define KONASHI_UART_RX_NOTIFICATION_UUID                       0x3013
#define KONASHI_UART_RX_NOTIFICATION_READ_LEN                   1

// Hardware
#define KONASHI_HARDWARE_RESET_UUID                             0x3014
#define KONASHI_HARDWARE_LOW_BAT_NOTIFICATION_UUID              0x3015
#define KONASHI_HARDWARE_LOW_BAT_NOTIFICATION_READ_LEN          1

たとえばiOSアプリとkonashiを接続した状態でkonashiのスイッチを押すと、

KONASHI_PIO_INPUT_NOTIFICATION_UUID	0x3003

と定義されているキャラクタリスティックが peripheral:didUpdateValueForCharacteristic:error: で観測されます。


参考情報

konashi iOS SDKはソースがまるっと公開されているので、直接実装する場合に参考になります。

※iOSと連携するデバイスのSDKは、だいたいビルド済みの静的ライブラリしか提供されてない場合が多い


konashiって何?という方、もしくはkonashiのiOS SDKを使った連携方法を知りたい方は下記記事をご参照ください。


サービスとかキャラクタリスティックって何?という方はこちらを。


konashiは最近はAmazonでも購入できるようです。

konashi
konashi
posted with amazlet at 14.02.04
スイッチサイエンス
売り上げランキング: 17,884


その他、BLE関連記事


2014-01-26

OpenEars 1.6で音声認識を行う

フリーのiOS向け音声認識/音声合成ライブラリ『OpenEars』について半年ほど前に記事を書いたのですが、

このときのバージョンは1.3.6でしたが、2014年1月現在の最新バージョンは1.64となっています。


で、もうAPIも結構変わっていて、上記記事のコードだと動かない(ビルドエラーになる)部分も多いので、改めて実装手順を書いておきます。


ちなみに音声合成は今回は省きます。iOS7でAVSpeechSynthesizerも追加されたし、もういいかなと。。


1. フレームワーク・リソースをプロジェクトに追加

とりあえず英語の認識だけでよければ、

  • OpenEars.framework
  • AcousticModelEnglish.bundle

の2つをプロジェクトに追加します。


2. ヘッダをインポート

#import <OpenEars/LanguageModelGenerator.h>
#import <OpenEars/PocketsphinxController.h>
#import <OpenEars/AcousticModel.h>

3. 言語モデル生成

プロパティを定義しておき、

@property (strong, nonatomic) NSString *amPath;
@property (strong, nonatomic) NSString *lmPath;
@property (strong, nonatomic) NSString *dicPath;

LanguageModelGeneratorで言語モデルを生成し、プロパティに格納しておきます。

NSArray *words = @[
                   @"SUNDAY",
                   @"MONDAY",
                   @"TUESDAY",
                   @"WEDNESDAY",
                   @"THURSDAY",
                   @"FRIDAY",
                   @"SATURDAY",
                   @"QUIDNUNC",
                   @"CHANGE MODEL",
                   ];
self.amPath = [AcousticModel pathToModel:@"AcousticModelEnglish"];
LanguageModelGenerator *generator = [[LanguageModelGenerator alloc] init];
NSError *error = [generator generateLanguageModelFromArray:words
                                            withFilesNamed:@"OpenEarsDynamicGrammar"
                                    forAcousticModelAtPath:self.amPath];

if (error.code != noErr) {
    
    NSLog(@"Error: %@",[error localizedDescription]);
}
else {
    
    NSDictionary *languageGeneratorResults = [error userInfo];
    
    self.lmPath = [languageGeneratorResults objectForKey:@"LMPath"];
    self.dicPath = [languageGeneratorResults objectForKey:@"DictionaryPath"];
}

4. 各種オブジェクト初期化/プロトコル実装

ここは旧バージョンと変わってないので省略します。

上記記事の3, 4を参考にしてください。


5. 認識スタート

[self.pocketsphinxController startListeningWithLanguageModelAtPath:self.lmPath
                                                  dictionaryAtPath:self.dicPath
                                               acousticModelAtPath:self.amPath
                                               languageModelIsJSGF:NO];


こんな感じです。


変更箇所を見ると、全体的に音響モデルを取り替えやすくするようにAPIを変更したのかなーと感じました。


2014-01-24

【iOS7】MFMessageComposeViewController の宛先フィールドが真っ黒になる件の対処法

iOS7で、MFMessageComposeViewController を表示すると、次のように宛先(Recipients)フィールドが真っ黒になって表示される件の対処法のメモ。



これ、UINavigationController 管理下にある UIViewController から MFMessage〜 を presentViewController:animated:completion で表示するときに発生しました(UINavigationController使ってない場合は問題なかった)。


対処法

こちらのページの、2番目の回答にある方法がお手軽で有効でした。


MFMessageComposeViewController を表示する前に UIAppearanceで次のようにセットしておき、

[[UINavigationBar appearance] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];

表示し終わったら(すなわち messageComposeViewController:didFinishWithResult: で)元に戻す

UIImage *backgroundImage = [UIImage imageNamed:@"Navigation Bar"];
[[UINavigationBar appearance] setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];

2014-01-23

Twitter APIでコードいじってないのに403エラーが出るようになった件

SLRequest 使って直接 Twitter API をたたいてる機能が、コードいじってないのにエラーになるようになったので、調べてみると、NSJSONSerialization でエラーが出ていました。


Twitter API からのレスポンスに何か変更あったのかな、と

typedef void(^SLRequestHandler)(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error);

この SLRequestHandler の引数の中身を見てみると、

  • errorは出てない
  • responseData が空
  • urlResponse の中身をみると、status code が 403

となってました。


調べてみると、2014年1月14日からSSL接続のみ受け付けるようになったとのこと。


対処

確かに、ちょうどそのAPIはhttpでアクセスしてたので、

http://api.twitter.com/1.1

https://api.twitter.com/1.1

に修正して解決。


あと今後のことも考えると、error の有無だけじゃなくて、status code も見るようにしたほうがよさそう。


2014-01-22

iOSアプリ申請時に『The network connection was lost』エラーが出る場合の対処法

ずばり、


Xcodeを再起動する


これでいけました。


ググって出てきた情報の中には「Apple社のサーバーの問題だからしばらく待ちましょう」みたいに書いてある記事もあったのですが、一晩待っても改善しなかったし、Twitter検索してみても同時間に同じように困ってる人がいなかったので、Xcode 5 側の問題だと思います(少なくとも僕のケースは)。


参考:ios - Xcode 5 app submission issue - Stack Overflow


2014-01-15

家電を自由に操作するiOSアプリがつくれる『IRKit』

カヤック時代の恩師 maaash*1 が、IRKitという新デバイスを個人で開発(!)して、本日よりAmazonで販売を開始しました。


IRKit
IRKit
posted with amazlet at 14.01.14
maaash.jp


このIRKitをつかうと、家電を操作するiOSアプリを好きなようにつくることができます。つまり、自分好みのリモコンアプリをつくれます。


対応している家電は・・・という制約はとくになくて、普通のリモコン(赤外線リモコン)で操作できるものなら何でもOKです。


しくみ

IRKit(デバイス)が赤外線信号を送る機能を持っていて、IRKit SDK(を組み込んだアプリ)から「どういう信号を送るか」を制御する、という感じです。ざっくり。



学習リモコンやPlutoやiRemoconとどう違うの?

学習リモコンは、もともとあるリモコンの赤外線信号のパターンを学習して、覚えさせることのできるもの。PlutoやiRemoconはそれらを公式アプリ上で好きなように組み合わせたりできるもの。


IRKitの最大の特徴は、iOS SDKが用意されているので、iOSアプリを自分で好きなようにつくれるというところにあるのではないでしょうか。


すなわち、

  • 好きなようにUIをカスタマイズできる
  • GPSや加速度センサや等のiOSデバイスが持っているセンサ類とも組み合わせて使える
  • TwitterやFacebook等の外部APIの機能とも組み合わせて使える
  • 他のiOSと連携させて使えるデバイスとも組み合わせて使える

可能性は無限大です。


さらにいえば、IRKitはArduino互換なので、公開されているファームのソースをカスタマイズして書き込むことも簡単*2ですし、空いてるピンにセンサを追加したり、何なら公開されているハード仕様に沿って自分でIRKit互換機をつくったりと、ほとんど何でもありなデバイスです。


コードを書かず、まずは試してみる

AppStoreにて公式アプリが公開されています。



こちらのアプリでIRKitデバイスのセットアップと、リモコン学習サンプルを試すことができます。


f:id:shu223:20140115072357j:image:w450


IRKit iOS SDKをプロジェクトに導入する

CocoaPodsから入れるのが簡単です。

プロジェクトのPodfile に

platform :ios, '7.0'
pod 'IRKit', :git => 'https://github.com/irkit/ios-sdk.git'

と書き足して、あとはターミナルから

pod install

するだけ。


API Key を取得する

API KeyはコマンドラインからcurlでAPIをたたいて取得できます。

$ curl -d "email={your email}" "http://api.getirkit.com/1/apps"

確認メールが届くので、リンクを踏むと、

Congratulations!

Here's your apikey: "XXXXXXXXXXXXXXXXXXXXXXX"

Paste this code in in your AppDelegate's application:didFinishLaunchingWithOptions:

[IRKit startWithAPIKey:@"XXXXXXXXXXXXXXXXXXXXXXXXX"];

と API Key がサンプルコード付きで得られます。


初期化

AppDelegateでヘッダをインポートし、

#import <IRKit/IRKit.h>

application:didFinishLaunchingWithOptions: で初期化メソッド(先ほどAPIKey取得時に表示されたコードのコピペでOK)を呼びます。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [IRKit startWithAPIKey:@"#{ fill in your apikey }"];
    return YES;
}

この時点でビルドしてアプリを動かしてみると、ログに、

[IRKit]successfully registered!

と出力されます。


IRKitを見つける

公式アプリでも使われている、IRKitを見つける(セットアップも込み)ためのビューコントローラ "IRNewPeripheralViewController" を表示します。


ヘッダインポートして、

#import <IRKit/IRKit.h>

IRNewPeripheralViewControllerDelegateへの準拠を宣言しておいて、

<IRNewPeripheralViewControllerDelegate>

IRKitが見つかったときに呼ばれるデリゲートメソッド(required)を実装しておきます。

- (void)newPeripheralViewController:(IRNewPeripheralViewController *)viewController
            didFinishWithPeripheral:(IRPeripheral *)peripheral
{
    NSLog( @"peripheral: %@", peripheral );
    
    [self dismissViewControllerAnimated:YES
                             completion:^{
                             
                                 NSLog(@"dismissed");
                             }];
}

で、起動時とか、ボタンタップ時とか何らかのタイミングで IRNewPeripheralViewController を表示するようにします。

- (IBAction)findTapped:(id)sender {

    if ([IRKit sharedInstance].countOfReadyPeripherals == 0) {
        
        IRNewPeripheralViewController *vc = [[IRNewPeripheralViewController alloc] init];
        vc.delegate = self;
        
        [self presentViewController:vc
                           animated:YES
                         completion:^{
                             
                             NSLog(@"presented");
                         }];
    }
}

これで、接続済みの IRKit が 0 の場合に、こういう画面が表示されます。


f:id:shu223:20140115072424j:image:w200


赤外線信号を学習する

IRNewSignalViewControllerDelegateへの準拠を宣言します。

<IRNewPeripheralViewControllerDelegate, IRNewSignalViewControllerDelegate>

信号学習が完了したときに呼ばれるデリゲートメソッド(required)を実装します。

- (void)newSignalViewController:(IRNewSignalViewController *)viewController
            didFinishWithSignal:(IRSignal *)signal {
    
    if (signal) {
        
        NSLog( @"learnd signal:%@", signal );
    }
    
    [self dismissViewControllerAnimated:YES
                             completion:^{
                                 
                                 NSLog(@"dismissed");
                             }];
}

IRNewSignalViewController を表示するようにします。

- (IBAction)learnTapped:(id)sender {

    IRNewSignalViewController *vc = [[IRNewSignalViewController alloc] init];
    vc.delegate = self;
    
    [self presentViewController:vc
                       animated:YES
                     completion:^{
                     
                         NSLog(@"presented");
                     }];
}

こんな画面が表示されるようになります。


f:id:shu223:20140115072445j:image:w200


学習した信号を送信する

長くなってしまったので、簡単に書きます。


信号を送る場合は IRSignal の sendWithCompletion: メソッドを呼ぶだけ。


まとめて複数の信号を送る場合は、IRSignals オブジェクトに学習した IRSignal オブジェクトを追加し、それを sendSequentiallyWithCompletion: メソッドで送信します。

_signals = [[IRSignals alloc] init];

// and add a signal to the collection
[_signals addSignalsObject:_signal];

// send multiple IRSignal-s sequentially
[_signals sendSequentiallyWithCompletion:^(NSError *error) {
    NSLog( @"sent with error: %@", error );
}];

iBeacon+IRKitで家に着いたら自動でXXXXをOn

iBeaconの実装は『iOS7 Sampler』を参考にしてください。


家電のOn/Off信号を学習させておいて、ビーコン端末を家の入り口辺りに置いておいて、

  • didEnterでOn
  • didExitでOff

するように実装しておけば、「家に着いたらエアコンやテレビや明かりを自動でon」「家を出るとき自動でoff」みたいなことができます。・・・と思ってますがまだそこまで実装できておりません


まとめ

IRKit、楽しいのでぜひ!


IRKit
IRKit
posted with amazlet at 14.01.14
maaash.jp


IRKit関連ページ

オフィシャル
ニュース系
開発情報etc...

*1このブログを始めるようアドバイスをくれた人。

*2:USBでPCとつないでArduino IDEから書き込むだけ。

2014-01-14

クラウドワークスでiOSアプリのアイコンデザインを募集してみたらすごく楽しかった件

先日、クラウドワークスで「iOS7 Sampler」ののアイコンデザインを募集してみました。



コンペ形式で、報酬金額は5,000円。プロのお力を借りるには恐縮な金額なので、1件くるか、来ないか・・・ヒットはしないだろうけど開発者界隈では評価されているアプリなので、その辺りを加味してくれるといいな・・・ぐらいに思っていたのですが、



と意外とレスポンスが早く(締め切り間際じゃないと来ないのでは、と思っていました)、その後も順調に提案が増え、最終的には7名の方から計13種類のご提案をいただきました。


最終候補と採用案

(当たり前ですが)どのデザインも自分でやるよりは遥かによく、迷いながらも最終候補として次の2つに絞りました。


f:id:shu223:20140115044502j:image:w450


f:id:shu223:20140115044501j:image


両者とも共通しているのは、iOS7の「7」をメインのモチーフにしている点。やっぱり「iOS7の新機能サンプル集」というアプリのコンセプトを伝えるには「7」がわかりやすいなと。


で、最終的に後者を選びました。


理由は、アイコン/スプラッシュの背景のグリッドが、「サンプルコード集」であることを想起させることと、ちゃんとデザインされてないアプリの中身とのバランスもいいかなと。


ちなみに準最終候補としては、KU-Nさんのと、moremoreforさんのがありました。


所感

今回が初めての利用だったのですが、サービスとしてかなり使いやすく出来ているし、なんといっても提案段階でもメッセージでデザイナーさんに意見や要望を言って修正してもらえるのがとても嬉しい誤算でした。そりゃそうだろう、という感じなのかもしれませんが、僕からすると「コンペでまだ報酬発生してないのに、こんなに要望言ってよくてしかも快く対応してくれるなんて!」という感じでした。


さらに採用案のkateruさんは、採用決定後も、納品にあたっていろいろ調整して複数パターン提示する、とおっしゃってくれています。もう決まったんだしこれでいいよね、じゃなくて。大変ありがたいです。


というわけで

これからどんどん使っていこう、ということで、アプリ全体のデザイン募集を始めてみました。


人類には早すぎるiPhoneアプリ『i聖徳太子』のUIデザインです。



人類には早すぎたiPhoneアプリのUIデザインの依頼/外注|モバイルサイト・スマートフォンサイト制作の仕事 [ID:49334]

iOSアプリのUIデザイン(アイコン/スプラッシュ含む)を募集します。

▽目的・概要

「i聖徳太子」というリリース済みアプリがあります。

大ヒットはしていませんが、100ブックマークされて(少し)話題になった記事

「人類には早すぎるiPhoneアプリまとめ」

http://matome.naver.jp/odai/2132910436568989701

など、たまーにブログ等で取り上げられます。


ジョークアプリとして捉えられがちですが、忙しい現代における効率化ツールとして、あるいは音楽の新しい楽しみ方の可能な次世代プレイヤーとして、実はけっこう意義深いアプリだと思っています。


今回はこの有料版(pro)をデザインを一新してリニューアルするにあたり、そのUIデザイン案を募集します。

(無料版もほぼ同等の機能なので、デザインをご検討の際には無料版をお試しいただければと思います。有料版の詳細は後述します。)


▽要件

デザインをお願いしたいものは有料版(pro)になります。有料版の無料版との違いは、以下の通りです。

  • 広告が出ない
  • 一斉スタート機能(全音源の一斉再生)

プラス、今回のリニューアルにあたり、5/5sの場合のみ最大6音源(今までは4音源)にしたいと思っています。


上記の通りあまり違いはないので、デザインご検討の際には無料版で十分かと思います。

(今後、無料版も同様のデザインでリニューアルする可能性はあります)


【現状考えている方向性について】

  • デザインリニューアルの方向性は、「iOS7のフラットデザインに沿ったもの」という以外はノープランです。現行版の青を基調とした背景も、たまたま自分のパソコンにそういう画像があったので使用したまでで、こだわりはありません。「なるほど、その手があったか!」というデザインを楽しみにしております。
  • アイコンはフラットデザインっぽくした方がいいかなとは思っていますが、現状のよく知られている聖徳太子の肖像画をベースとしたものも気に入ってはいます。
  • スプラッシュは現行版には「223 apps」とありますが、あってもなくてもOKです。
  • 英語版タイトルは「Multi-Channel Player」です。

デザイナーのみなさま、ぜひよろしくお願いいたします!


参考記事


2014-01-13

【iOS7】プッシュ通知のバックグラウンド処理でハマったメモ

やりたかったこと:

プッシュ通知を受け取ったときにアプリを起動することなく(バックグラウンドで)APIを呼ぶ


これはおそらく「サイレントプッシュ通知(Silent Remote Notification)からの Background Fetch」の最も一般的な実装事例だと思うのですが、これがなかなかうまくいかず、試行錯誤しました。


最終的にはうまくいったのですが、そもそも何が原因だったのか、諸々の対策がどう効いて解決したのか、本質的なことはあまりわかっていません。とにかく最終的にうまくいった実装と参考にした記事をここにメモっておきます。


(どの記事にも書いてある application:didReceiveRemoteNotification:fetchCompletionHandler: を実装するとか、通知を送る側の話とか、従来通りのプッシュ通知実装と同じ手順とかはこの記事では省略しています。)


application:didFinishLaunchingWithOptions:の実装

[application unregisterForRemoteNotifications];
[application registerForRemoteNotificationTypes:
 UIRemoteNotificationTypeBadge|
 UIRemoteNotificationTypeAlert|
 UIRemoteNotificationTypeSound|
 UIRemoteNotificationTypeNewsstandContentAvailability];

[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

ポイントは3点:


ポイント1: register〜 の前に unregisterForRemoteNotifications を呼ぶ

  • これを入れるまでは、バックグラウンド処理(didReceiveRemoteNotification)が呼ばれたり呼ばれなかったり(ほとんどのケースでは呼ばれない)だった
  • これを入れてから安定してバックグランド処理できるようになった

ポイント2: UIRemoteNotificationTypeNewsstandContentAvailabilityを追加する


(上記2点とも、下記記事の「トラブルシューティング」の項を参考にしました。)


ポイント3: setMinimumBackgroundFetchInterval: を呼ぶ

  • デフォルトは UIApplicationBackgroundFetchIntervalNever になってるらしい
  • UIApplicationBackgroundFetchIntervalMinimum をセットする

下記書籍の Background Fetch の項を参考にしました。


上を目指すプログラマーのためのiPhoneアプリ開発テクニック iOS 7編
加藤 寛人 西方 夏子 藤川 宏之 鈴木 晃 高丘 知央
インプレスジャパン
売り上げランキング: 6,684


Capabilitiesの設定

Background fetchとRemote notificationsの両方ともにチェックを入れる

  • ほとんどの記事や書籍には、片方でよさそうなことを書いてある
  • 試行錯誤に疲れたので、最終的に両方のチェックが必須かどうかの検証はしていません。とにかく最後この状態でうまくいった、というだけ。

その他参考になった記事


その他のメモ

  • こちらの記事によると、なんかデバッグ時は下記のようにした方がよさそうに思ったけど、上述したunregister〜が有効で、この方法はあまり関係なかった(そもそも今回つくってたのはNewsstandアプリではない)
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"NKDontThrottleNewsstandContentNotifications"];

2014-01-12

Parse SDK使用時にFacebook iOS SDKの利用を強要される件

Parse.frameworkの最新版(1.2.18)をとあるXcodeプロジェクトに追加し、公式ページにあるガイドに沿って依存フレームワークを追加してヘッダインポートしてビルドしてみると、


Undefined symbols for architecture armv7:
  "_FBTokenInformationTokenKey", referenced from:
      -[PFFacebookTokenCachingStrategy accessToken] in Parse(PFFacebookTokenCachingStrategy.o)
      -[PFFacebookTokenCachingStrategy setAccessToken:] in Parse(PFFacebookTokenCachingStrategy.o)
  "_FBTokenInformationExpirationDateKey", referenced from:
      -[PFFacebookTokenCachingStrategy cacheTokenInformation:] in Parse(PFFacebookTokenCachingStrategy.o)
      -[PFFacebookTokenCachingStrategy expirationDate] in Parse(PFFacebookTokenCachingStrategy.o)
      -[PFFacebookTokenCachingStrategy setExpirationDate:] in Parse(PFFacebookTokenCachingStrategy.o)
  "_OBJC_METACLASS_$_FBSessionTokenCachingStrategy", referenced from:
      _OBJC_METACLASS_$_PFFacebookTokenCachingStrategy in Parse(PFFacebookTokenCachingStrategy.o)
  "_OBJC_CLASS_$_FBSessionTokenCachingStrategy", referenced from:
      _OBJC_CLASS_$_PFFacebookTokenCachingStrategy in Parse(PFFacebookTokenCachingStrategy.o)
  "_OBJC_CLASS_$_FBAppCall", referenced from:
      objc-class-ref in Parse(PFFacebookAuthenticationProvider.o)
  "_FBTokenInformationUserFBIDKey", referenced from:
      -[PFFacebookTokenCachingStrategy facebookId] in Parse(PFFacebookTokenCachingStrategy.o)
      -[PFFacebookTokenCachingStrategy setFacebookId:] in Parse(PFFacebookTokenCachingStrategy.o)
  "_OBJC_CLASS_$_FBRequest", referenced from:
      objc-class-ref in Parse(PFFacebookAuthenticationProvider.o)
  "_OBJC_CLASS_$_FBSession", referenced from:
      objc-class-ref in Parse(PFFacebookAuthenticationProvider.o)
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)

こんな感じで Facebook iOS SDK を入れろと言わんばかりに Undefiend symbols エラーがたくさんでてきました。


確かFacebook SDKはオプショナルだったはず・・・ *1 とググってみると、

If you're not using a library which requires the -ObjC linker flag, you can remove -ObjC from your project:


Build Settings > Other Linker Flags > remove -ObjC


or if you are using a library which requires that flag, you can add the Facebook SDK.

parse.com - Parse for iOS: Errors when trying to run the app - Stack Overflow


[Other Linker Flags] に "-ObjC" フラグを立てているとFacebook iOS SDKが必要になるので、嫌ならフラグを外せばいい、とのこと。



確かに外すとビルドは通るようになりました。でも、必要だから "-ObjC" 立ててたわけで・・・でも Facebook iOS SDK は必要なければ入れたくない・・・


-ObjC フラグを立てつつも Facebook iOS SDK を使わない方法

"-ObjC"フラグは必要だけど Facebook iOS SDK は入れたくないので、どうにかする方法がないか探ってみました。

上記ページではなんかとんちんかんなやりとりがされていますが、そこで示されていた下記URL

こちらにもう少しまともそうなことが書いてありました。


An easy way to do this is to use the -force_load flag instead of the -ObjC flag on the static libraries that need the -ObjC flag. You can use:


-force_load $(BUILT_PRODUCTS_DIR)/<library_name.a>


"-ObjC" が必要なライブラリに対して、"-ObjC" の代わりに "-force_load" を使用してライブラリに含まれるオブジェクトを全てロードさせる、という方法。


上記は $(BUILT_PRODUCTS_DIR) に .a ファイルが置いてある前提になってますが、.framework の場合は下記のような感じでフォルダ内の静的ライブラリのパスを指定することになります。

$(SRCROOT)/framework/xxxx.framework/Versions/A/xxxx

*1:Parse.hでもインポート文は #if __has_include(<FacebookSDK/FacebookSDK.h>) で囲まれています。

2014-01-11

カヤック「1社だけの合同説明会」に退職者として登壇してきました

1社だけの合同説明会」というカヤックの新卒採用イベント *1 に退職者として登壇してきました。


序盤だけ使ってたスライド。



ブース形式のイベントで、僕は「退職者ブース」担当でした。


事前の発表内容の指定も精査も一切なかったのですが、上のスライドをつくった時点では、採用イベントということで空気を読んで、「退職者視点でありつつもカヤックに入りたくなるような話」を意識し、あまりスパイスも効かせていませんでした。


が、退職者ブースに来る人って、やっぱり裏話的なことを期待して来るし、35分 x 12クールもあるので同じこと話してると自分も飽きてくる・・・ということで、


f:id:shu223:20140112193946j:image:w476


という1ページだけをモニタに表示して、何の段取りもテーマもないまま、退職者3人がお客さんからいただいた質問・お題について好き勝手しゃべる、という形式に変えました。


f:id:shu223:20140112202638j:image


3人で話すと「ぶっちゃけ」がかなりエスカレートしていきましたが、基本カヤック愛のある3人なので、カヤックの良さが伝わるべき人には伝わったのではないでしょうか。。



楽しいイベントに読んでいただきありがとうございました!!


関連記事

全体の様子はこちらのブログに詳しくレポートされています。


面白法人カヤックの、1社だけの合同説明会はやはり面白かった。 | ciotan blog(しおたんブログ)


*1:中途も対象。というか志望してなくても、社会人でも誰でも参加OK

2014-01-10

iOSのCore Bluetooth / BLEの通信速度

Bluetooth Low Energy(Bluetooth4.0, 以下BLE)の通信速度について調査、実測してみたメモ。


(2015.3追記)この記事は古く、書いた当時はBLEについての知識も乏しかったので内容には多分に誤りが混じっている可能性があります。


調査

まず "BLE 通信速度" でググってみました。


BLEでは「無接続状態」から→「接続」→「データやり取り」までの速度を圧倒的に早くすることで

普段は頻繁に「つないで」「死んで」「つないで」「死んで」を繰り返している。

ホントに必要なときしか動かないことで消費電力を最適化しているわけだ。


そうすると気になるのは送信側でのデータ入力から受信側での受け取りまでのディレイだが、

接続自体のディレイは6ms程度、なのできっとデータ送受信トータル20-30msくらいなのかなぁ。


まぁ普通の人間が感じることができる(違和感を感じることができる)ディレイなんてせいぜい30ms以上の場合だけだから既出のキーボードなどの用途ではまったくもって申し分ないレベルだ、といえるだろう。

500 Internal Server Error


スペック上は最大通信速度が1Mbpsと謳われているが、「実質10kbps程度と圧倒的に遅い」(森山氏)そうだ。

no title


BLEは、例えば1秒に20バイト程度のデータを送受信するような、データのやり取り頻度は低いけれども、無線接続自体は長期間維持できる応用分野を想定した規格です。データ通信速度も物理層で1Mbpsです。クラシックBTは、ヘッドセットやパーソナル・エリア・ネットワーク(PAN)のような、特定の端末と接続すること(ペアリング)、常時データ通信があること、また高いデータ・レート(~3Mbps)が必要とされる、場面を想定した規格です。

BLEの通信速度は、物理層で1Mbps、実際の通信速度は~50kbps程度です。一方でクラシックBTは物理層で3Mbps(WiFiの物理層を使わないものであれば)で、~500kbps程度です。そもそも、そのような連続かつ高速のデータ送受信をし続ける応用例には、BLEを選択すること自体が、BLEの規格の狙い目からはずれていますから、クラシックBTのみで設計すればよいでしょう。

no title


諸説ありますが、実質10〜50kbpsのようです。


iOSのCore Bluetoothで実測

Core Bluetoothで実際に実装して計ってみました。


計測用アプリは、下記書籍のサンプルをもとに、

  • NSTimerでセントラルからのRead処理 *1 をループさせる(ループ間隔はUIで変更できる)
  • ペリフェラルからはランダムなNSDataを送り返す(データ長はUIで変更できる)
  • セントラルで受信したデータサイズから通信速度(最大、最小、平均)を計算する

というような計測用アプリをつくりました。


上を目指すプログラマーのためのiPhoneアプリ開発テクニック iOS 7編
加藤 寛人 西方 夏子 藤川 宏之 鈴木 晃 高丘 知央
インプレスジャパン
売り上げランキング: 6,194


セントラル側に iPhone5s、ペリフェラル側に iPhone5 を使用し、ループ間隔や、一度に送るNSDataオブジェクトのサイズをいろいろ変更しつつ計測したところ、安定して出た通信速度は 5kbps 程度でした。


ただ、GATTまわりがまだよくわかってなくてサンプルそのままなので、改善の余地はあるかもしれません。


関連記事


*1:ペリフェラルからのNotifyも同様にループさせて試してみたところ、Readよりも遅かったので、本記事ではReadについてのみ言及しています。

2014-01-09

Bluetooth のプロファイルについて調べたことのまとめ

Bluetoothのプロファイルって何?というところから、iOSのCore Bluetoothで対応しているプロファイルについてのアレコレまで、ググって調べたことのまとめ。


注意:この記事は全くの無知な状態から調べながら書いたので、(とくに序盤に)多分に誤解・語弊のある言い回しが含まれております。


プロファイルとは?

Bluetoothはその特性上、様々なデバイスでの通信に使用される為、機器の種類ごとに策定されたプロトコルがあり、これをプロファイル (Profile) と呼び標準化している。 通信しようとする機器同士が同じプロファイルを持っている場合に限り、そのプロファイルの機能を利用した通信をおこなえる。

プロファイルは、各機器がBluetoothを使って何ができるかを示したもので、機器同士の接続性が一目でわかるようになるものと期待された。しかし現実には、Bluetooth応用分野の拡大に伴って急激にプロファイルが増加したこともあり、以下のような問題が目立つ。

  • 同じような機能のプロファイルが乱立気味であり、利用可能な、あるいは目的に適したプロファイルがわかりにくい。
  • 対応プロファイルの少ない古い製品の陳腐化を助長し、しかもアップグレードが提供されないことが多いので買い替えを余儀なくされる。
  • 「同じBluetoothなのにプロファイルの有無が原因でつながらない」という印象を与えやすい。

Bluetooth - Wikipedia


汎用の短距離無線通信技術であるBluetoothは、さまざまな情報機器が対応し、データを交換することができる。その際、パソコンなどを介さずに機器同士が直接データを転送して互いの機能を利用するという使用法も想定されている。


このため、Bluetoothでは従来の通信技術のように単に回線を確立してデータが転送できるだけでは不十分で、どのような順番・タイミングで、どんな種類の情報を転送すべきか、という機器の「使い方」にあたる手順を共通化しておく必要がある。


こうした機器固有の通信手順(プロトコル)を製品の特性ごとに標準化したものがBluetoothプロファイルである。業界団体のBluetooth SIGによって機器の種類ごとに標準のプロファイルが策定されているほか、メーカーが自社固有の機能を実装した独自のプロファイルを提供することもできる。


たとえば、デジタルカメラが自分の保存している画像を近くのプリンタで印刷したい場合は、プリンタプロファイル(Printing Profile)を使って通信し、プリンタに印刷を依頼するのである。パソコンがデジタルカメラの保存している画像を一覧したい場合にはデジタルカメラプロファイル(実際には、「Still Image Profile」というプロファイルを使う)を使ってデータの転送を依頼すればよい。

Bluetoothプロファイル(Bluetooth Profile)とは - IT用語辞典


代表的なプロファイルの一覧

  • GAP (Generic Access Profile)

機器の接続/認証/暗号化を行うためのプロファイル。

  • SDAP (Service Discovery Application Profile)

他のBluetooth機器が提供する機能を調べるためのプロファイル。

  • SPP (Serial Port Profile)

Bluetooth機器を仮想シリアルポート化するためのプロファイル。

  • DUN (Dial-up Networking Profile)

携帯電話・PHSを介してインターネットにダイヤルアップ接続するためのプロファイル。

  • FTP (File Transfer Profile)

パソコン同士でデータ転送を行うためのプロファイル。ファイル転送プロトコルのFTPとは無関係。

  • HID (Human Interface Device Profile)

マウスやキーボードなどの入力装置を無線化するためのプロファイル。

  • HCRP (Hardcopy Cable Replacement Profile)

プリンタへの出力を無線化するためのプロファイル。

  • BPP (Basic Print Profile)

プリンタへ転送・印刷するためのプロファイル。

  • OPP (Object Push Profile)

名刺データの交換などを行うためのプロファイル。

  • SYNC (Synchronization Profile)

携帯電話・PHSやPDAと、PCとの間で、スケジュール帳や電話帳のデータ転送を行い、自動的にアップデートするためのプロファイル。

  • LAP (LAN Access Profile)

Bluetoothを利用して無線LANを構築するためのプロファイル。

  • FAX (FAX Profile)

PCからFAXを送信するためのプロファイル。

  • HSP (Headset Profile)

Bluetooth搭載ヘッドセットと通信するためのプロファイル。モノラル音声の受信だけではなく、マイクで双方向通信する。

  • HFP (Hands-Free Profile)

車内やヘッドセットでハンズフリー通話を実現するためのプロファイル。HSPの機能に加え、通信の発信・着信機能を持つ。

  • BIP (Basic Imaging Profile)

静止画像を転送するためのプロファイル。

  • PAN (Personal Area Network Profile)

小規模ネットワークを実現するためのプロファイル。

  • A2DP (Advanced Audio Distribution Profile)

音声をレシーバー付きヘッドフォン(またはイヤホン)に伝送するためのプロファイル。HSP/HFPと異なり、ステレオ音声・高音質となる。

  • AVRCP (Audio/Video Remote Control Profile)

AV機器のリモコン機能を実現するためのプロファイル。

  • PBAP (Phone Book Access Profile)

電話帳のデータを転送するためのプロファイル

  • OBEX (Object Exchange)

オブジェクト交換 (OPP、BIP、FTP、SYNC) で用いる認証方式の一つ。データ転送プロファイルの一つで、実装しているとデータ送受信時にOBEX認証パスキーの入力を接続相手に要求する。

  • ICP (Intercom Profile)

同一ネットワーク内にあるBluetooth搭載携帯電話同士を公衆電話網を介さずに直接、接続させるためのプロファイル。

  • HDP (Health Device Profile)

健康管理機器同士を接続するためのプロファイル。

これらプロファイルのうち、DUN/FTP/HID/OPP/HSP/HFP/A2DP/AVRCPなどの使用頻度が高い。GAPやSDAPのような下位層のものは実装されていても意識されないことが多い。

Bluetooth - Wikipedia


別のプロファイル一覧ページ:Bluetoothプロファイルの一覧 - Wikipedia


Core Bluetoothが対応しているプロファイル

プロファイルとは何か、どんなのがあるのかわかったところで、Core Bluetooth フレームワークではどんなプロファイルが使えるのか調べてみたところ、

Core Bluetooth is meant for low energy,You can only implement GATT Profiles(like Heart Rate,Alert Notification) with BLE and BLE is for small data rates.

iphone - What profile can I use with CoreBluetooth? - Stack Overflow


とあり、使えるのはGATT(Generic Attribute Profile)と呼ばれるプロファイル、もしくはGATTをベースとして定義されたプロファイルだけらしい。


Core BluetoothはiOSアプリに Bluetooth LE (BLE) デバイスの発見、接続と読み書きの操作を提供するフレームワークであり、BLEデバイスの振る舞いはGATTプロファイルとして定義されている、ということのようです。


(参考:no title


# というわけで上に載せたプロファイル一覧はBluetooth3.0以前用で、MFIを取得してExternal Accessoryフレームワークを使用しないと使えない類いのもののようです。


GATTプロファイルとは?

Bluetooth LEでは、基本的に「GATT(Generic Attribute Profile)」と呼ばれるプロファイルをベースとして定義されたプロファイルで通信が行われます。

no title


GATTをベースにしたプロファイルとしては、"Object moved" によると、次のようなものがあるようです。

  • Alert Notification
  • Blood Pressure
  • Cycling Power
  • Cycling Speed and Cadence
  • Find Me
  • Glucose
  • Health Thermometer
  • Heart Rate
  • HID OVER GATT
  • Location and Navigation
  • Phone Alert Status
  • Proximity
  • Running Speed and Cadence
  • Scan Parameters
  • Time

GATTの詳細

このデータ通信はGATT(Generic Attribute Profile)をベースとして,service(サービス)を用いて行います.serviceは,属性値のcharacteristic(キャラクタリスティック),任意属性値のdescriptor(ディスクリプタ)から構成されます.


例として,バッテリー情報を提供するBattery Serviceでは,Battery Lavelという電池残量値を持ったcharacteristicと,そのフォーマットを指定するdescriptorで構成されます.

[iOS] Bluetooth Low Energyでアプリ開発: Seesaa京都アプリエンジニアブログ


実際のデータのやりとりは、キャラクタリスティックに対して読み書きすることで行われます。オブジェクト指向プログラミングをしている方々には、サービスがクラス、キャラクタリスティックがプロパティととらえるとわかりやすいかもしれません。


各キャラクタリスティックの値は無暗号化状態で読み書きすることもできますが、ペアリングの操作を行うと暗号化されます。また、キャラクタリスティックの値が変化したときに通知を受け取れるものもあります(notify)。


これらのサービスやキャラクタリスティックは Bluetooth SIG が標準として定義しているもののほかに、デバイスの開発者が独自に定義することも可能です。


いくつかの必要なサービスを組み合わせたものを「プロファイル」と呼んでいます。(特にこれまでのBluetoothのプロファイルと区別する必要のある場合はGATTベースプロファイルと呼ばれます) プロファイルも標準的なものは Bluetooth SIG が定義しており、たとえば、マウス・キーボードにあたる「HID over GATT」というプロファイルには、「Human Interface Device」「Device Information」「Battery Service」「Scan Parameters(オプション)」のサービスが含まれると定義されています。


サービス・キャラクタリスティックは、UUID で識別されます。UUID は 32 桁ですが、Bluetooth SIG の標準で定義されているものについては 4 桁で表現されます。4 桁の UUID は実際には Bluetooth Base UUID というものをつけ、0000●●●●-0000-1000-8000-00805f9b34fb となります(●のところに4桁 UUID が入ります)。規格外で独自に定義する場合は Mac では uuidgen コマンドを使うなどして生成します。

no title


GATTは、サーバが持つデータを、キャラクタリスティクスという単位で読み書きする仕組みを提供します。また、サーバには多くのキャラクタリスティクスがありますが、そのキャラクタリスティクスをグループ化する、サービスという仕組みも提供します。


サービスは、その機器のハードウェアとしての機能を表します。例えば、体温計があるとします。体温計のハードウェアとしての機能は、温度の計測と、計測が完了した時のアラート音の出力の2つだとします。この場合、温度計測をするサービスが1つ、そして警告音を出すサービスが1つ、あるでしょう。それぞれのサービスには、温度を読み出すキャラクタリスティクス、警告音のOn/Offの指示を書き込むキャラクタリスティクスがあるでしょう。体温計という振る舞いにではなく、ハードウェアとしての機能に、サービスが割り当てられます。


Bluetooth LEのアプリケーションは、GATTの上に作られます。Bluetooth LEの規格認証の範囲はGATTまでです。サーバがどのようなサービスやキャラクタリスティクスを提供するかは、機器のアプリケーションとして実装されます。ですから、機器の開発者は、Bluetooth LEの規格認証のもとで、任意のサービスおよびキャラクタリスティクスを定義して、それを実装できます。


これはiOSアプリケーションでも同じです。iOSアプリケーションは、Core Bluetoothフレームワークを通して、GATTのサービスとキャラクタリスティクスにアクセスできます。iOSアプリケーションは、接続した機器の複数のサービスを組み合わせて、機器の振る舞いを制御します。Bluetooth LEを使うiOSアプリケーションは、パソコンで言うデバイス・ドライバに相当する部分を、アプリケーション内部に持つことになります


クラシックBluetoothで任意のアプリケーションを作る場合は、勝手なプロファイルを定義できないため、SPPの汎用通信を使うほかありません。しかし、Bluetooth LEは、その規格のもとで任意のプロファイルを勝手に定義することができます。例えば、先ほどの体温計のサービスを利用して、iOSアプリケーションの振る舞いの制御を変えれば、室温を計測して熱中症をアラート音で警告する振る舞いをさせることも、できます。


Bluetooth SIGは、よく使われるサービスやプロファイルを定義しています。例えば、バッテリー残量やアラートの出力のようなサービスが定義されています。必要なプロファイルに使えるサービスがすでに定義されていれば、それを利用することができます。わざわざ定義や開発をする必要はありません。


また、プロファイルは、開発者が任意に定義できますが、これでは特定のメーカや機種を超えた汎用性が得られません。Bluetooth SIGは、それぞれの業界団体から提出された汎用化したプロファイルを公式のプロファイルとして審査承認して、Bluetooth LEの公式のプロファイルの定義とすることで、これを解決します。

no title


GATTプロファイルは、「サービス」「キャラクタリスティック」「ディスクリプタ」と呼ばれる3つの要素で構成されています。プロファイルは1つ以上のサービスから構成されます。


サービスはプロファイルの一機能を表します。サービスは、複数の入れ子になっているサービスと複数のキャラクタリスティックから構成されます。


キャラクタリスティックは単一の値を持った属性を表します。キャラクタリスティックは、キャラクタリスティック自体の値、値へのアクセス方法を定義するプロパティ、複数のディスクリプタで構成されます。


ディスクリプタはキャラクタリスティックに付加情報が必要な際に用いられる属性値を表しており、キャラクタリスティックによってはディスクリプタは定義されていません。

クライアントは発見した任意のサーバと接続した後、GATTプロファイルをベースとしたプロファイルで情報の取得や書き込みを行います。実際には、上述のキャラクタリスティックまたはディスクリプタの値で情報をやりとりします。

なお、Bluetooth Smartデバイス側は、鳴動によるユーザーへの通知機能を提供する「Immediate Alert」サービスと、バッテリー残量情報を提供する「Battery Service」サービスに対応している必要があります。Immediate Alertサービスを含むプロファイルとしては「Find Me」プロファイルなどが、Battery Serviceサービスを含むプロファイルは「HID OVER GATT」プロファイルなどがあります。

no title


参考書籍

上を目指すプログラマーのためのiPhoneアプリ開発テクニック iOS 7編
加藤 寛人 西方 夏子 藤川 宏之 鈴木 晃 高丘 知央
インプレスジャパン
売り上げランキング: 6,194


「7-2 Core Bluetooth」に約20ページにわたる詳細な解説があります。プロファイルの話も出てきます。


(参考記事:『上を目指すプログラマーのためのiPhoneアプリ開発テクニック iOS 7編』書評 - Over&Out その後


2014-01-08

シェルスクリプトでmp4からアニメーションgifを生成する

mp4からアニメーションgifを生成したい、というケースが最近ちょくちょくありまして。


たとえば「GitHub の README に動く様子を載せたい」場合、YouTubeやVimeoの埋め込みタグをREADME.mdに載せてもプレイヤーを表示してくれないので、アニメーションgifをつくって載せています。

元の動画はQuickTimeでシミュレータのキャプチャ動画を撮ったものだったり、iPhoneのカメラで撮ったものだったりするのですが、アニメーションgifへの変換はどういう方法があるのか知らなかったので、

  • QuickTimeで動画を短くトリムする
  • Photoshopで動画を読み込んで適当にフレーム飛ばしてAnimation Gifに書き出す

という非常に面倒なことをやっていました。


で、ふと下記記事を見ていると、

「90sのmp4から12fpsで320*180のアニメgifを作る」スクリプトが例に挙げられています。


高速化云々以前に、そんな便利なことができたのか!と。


というわけで試してみました。


準備

まず、自分の環境にはffmpegが入ってなかったのでインストール。

$ brew install ffmpeg

あとアニメーションgifを生成する gifsicle もインストールする必要があるのですが、brew installしようとすると

gifsicle: Unsatisfied dependency: XQuartz

Homebrew does not package XQuartz. Installers may be found at:

https://xquartz.macosforge.org

と怒られたので、エラー文の言う通りに https://xquartz.macosforge.org に行って、インストーラから XQuart をインストール。


で、あらためて gifsicle をインストール。

$ brew install gifsicle

シェルスクリプト作成

$ touch gen_animegif.sh
$ vi gen_animegif.sh

で以下のように編集(shellわからないので、元記事のコードをほぼそのままお借りしています)。

#!/bin/sh

# Task 1
SRC="$1"
[[ ! -f "$SRC" ]] && echo 'no exists' && exit 1
INI=$SECONDS
mkdir ./temp

# Task 2-3
ffmpeg -loglevel panic -ss 0 -i "$SRC" -r 12 -an -f image2 -s 320x180 "./temp/%03d.gif"
gifsicle -O3 --batch ./temp/*.gif

# Task 4
gifsicle ./temp/*.gif > output.gif
rm -rf ./temp
echo "done with `expr $SECONDS - $INI`s" && exit 0

実行してみる

$ sh ./gen_animegif.sh xxxx.mp4

23.9MB の mp4 動画ファイルが、コマンド一発で1.7MBのgifアニメに!


movファイルも試してみました。

$ sh ./gen_animegif.sh xxxx.mov

24MB → 5.1MBに!


問題点

上記shellだと、mp4(iPhoneで撮影)は出力ファイルにおける動画の向きが90度回転してしまい、mov(QuickTimeでスクリーンキャプチャ)は元々縦長だった動画が横長になって上下方向につぶれた感じになってしまいました。きちんと向きを処理する必要がありそうです。


まとめ

シェルスクリプト、他にも知らずに損してることがたくさんありそうです。勉強します。


2014-01-07

【iOS7】MapKitで移動手段(徒歩 or 車)を指定して経路探索する

iOS7から使えるようになった MKDirections, MKDirectionsResponse, MKPolylineRenderer 等を用いて経路探索と地図上への描画を行う方法は、iOS7 Samplerに入っているサンプルのとおりなのでここでは割愛しますが、

経路探索において移動手段を指定するには、MKDirectionsRequest の transportType に、MKDirectionsTransportType 型の値をセットします。

request.transportType = MKDirectionsTransportTypeWalking;

MKDirectionsTransportTypeはMKDirectionTypes.hに下記のように定義されていて、

typedef NS_OPTIONS(NSUInteger, MKDirectionsTransportType) {
    MKDirectionsTransportTypeAutomobile     = 1 << 0,
    MKDirectionsTransportTypeWalking        = 1 << 1,
    MKDirectionsTransportTypeAny            = 0x0FFFFFFF
} NS_ENUM_AVAILABLE(10_9, 7_0);

名前の通り徒歩か車かを選択できます。


transportTypeのデフォルト値は MKDirectionsTransportTypeAny です。


2014-01-06

2014年の目標

昨年は海外で働くという自分にも他人にもわかりやすい目標がありましたが、今年はややぼんやりしています。断片的にはいろいろあるけど、「海外で働く!」みたいに明快で大きいものがない


なのでこの記事を書いてみようとしつつまとまりそうにないからやめとこう、と見送りそうになりましたが、ぼんやりしてるときこそちゃんと書き出した方がいいと思い直し、とりあえず今頭の中にある断片を書いていくことにします。順不同。


1. 連載を書籍化する

gihyo.jpでの連載執筆を加速させて、書籍化まで持っていきたい。

ある程度の分量は必要ですが、書きたいデバイスの数だけで言うと既にそれぐらいはあります。


でもなかなか書けなくて、連載開始2ヶ月経ってまだ2回分のみ。早く書かないと、既に書いた部分が古くなってしまうので、できれば

  • 週1ペースで書いて2月末までにプラス6記事
  • そこから書籍化に向けた加筆作業に入る

ぐらいの感じで進めたい。ただ生活の柱にはならないので、他のメイン業務に容易に割り込まれてしまうのが悩みどころ。スキマ時間にちょっとずつ書き進められるような仕組み化を考える。


2. 勉強→ブログの流れをもう一歩前進させる

  • 興味のある技術を勉強する
  • → ブログに書く
  • その技術を使ったミニマルなアプリをつくってリリースする

という流れをつくりたい。


理由の一つとしては、自分でアプリを考えて、リリースするということをもっと継続的にやっておきたいなと。アイデアを考える脳みそは使い続けてないとすぐに腐ってくるし、アプリをリリースしたときに感じられる空気感とかはすぐに古くなるので。


もうひとつの理由は、「興味のある技術を勉強する」をちょっとでも収益化すること。ブログに書いてもあまりお金にならないし、すぐに仕事に使えるものばかりでもないので。


あとアプリ考えたりつくったり出したりするのはやっぱり楽しい、というのもあります。


「結局やらない」対策

アプリを出すときに不可避かつ面倒なのが、

  • アイコンデザイン
  • スプラッシュ画面のデザイン
  • AppStore文言

といったものを用意する作業。


このあたりのことを思い浮かべると、面倒だなーと思ってGitHubで公開して終わり、になってしまうので、

  • 配色やらフォント選びだけでワンパターンでできるようにする
  • クラウドワークスみたいなサービスに出す

みたいに、とにかく実行するにあたって心理的障壁を感じないようにする仕組みづくりが必要。


そんな考えもあって iOS7 Sampler のアイコンデザインを募集してみたりしてます。


3. 個人でKindle書籍出版

仕事で使う予定もないし、個人アプリで使う予定もない。でも興味はある、という技術ネタを、単にブログに書いて終わり、ではなくちょっとでもマネタイズしたいというのはずっと思っていて、出版社からちゃんとした本として出すのはプレッシャーやハードルが高いので、そういうものをまとめた寄せ集めTips本をKindleで個人出版してみたいなと。


自分が興味を持ったネタは自分以外にも興味がある人はいるはず。儲かりはしないだろうけど、自分の勉強になるからやって損はない。


連載と同様、進め方が課題なのであとで考える。


4. 「旅するプログラマ」構想

カヤックに入る前にカヤックの制度で惹かれたもののひとつが、「旅する支社」というもの。

鎌倉に本社を置く、面白法人カヤックですが、

ネット環境を整えれば、沖縄でもアメリカでも、

どこででも仕事ができることを証明します。


単純な話、いろいろなところに行く/住むのって楽しいわけでして。。


で、アメリカで2年ぐらいは働くぞと思って鎌倉のアパートも解約して家具も処分したのですが、わずか数ヶ月で帰国することになったので、幸か不幸か住所がよくわからないことになってます。


こういう状況(ちゃんとした家と家具がない)ってなかなか意図してつくれるものじゃないので、「いろんなところを転々としつつ仕事をする」といういつかやりたいと思っていたことを実行に移す絶好のチャンスなんじゃないかと。


寒い冬を暖かいところで過ごす

というわけで沖縄のマンスリーマンションを予約してみました。ちょっといま仕事で調整中のものがあり、それ次第ではとりやめるかもしれませんが、問題なければ今月末から1ヶ月間、あっちに住んでリモートで仕事をしようと思います。


沖縄にしたのは、海外は今は仕事の関係で不便が多くなってしまうのと、調べてみたら国内では圧倒的に暖かそうだったからです。


5. Androidアプリをつくる

専門はあくまでiOSに置きつつ、趣味のアプリ/実験アプリをつくれる程度に *1 なっておきたい。


理由としては、審査なしでアプリをさくっと出せるという点が、ブログの一歩先のアウトプット先として向いているなぁというのと、Google Glassみたいに楽しそうなデバイスが出たときに、iOS SDKは最初はないとかAndroidのほうが簡単にいろいろ制御できるというケースがこれからちょくちょく出てきそうなので。


6. 一緒に仕事したい人と仕事をする

一緒に仕事したい人に自分から会いに行って売り込む、ということを昨年末あたりから始めていて、これをもっと形にしていきたい。


会ってもらうことはできて、いいですね、ぜひ一緒にやりましょう!からなかなか具体的にできていないのが現状。


もっと頭を絞り、自分にしか出せない価値や自分だから背負えるリスクといった武器を持って、相手が僕と「今」組む理由を明確に打ち出して動く必要がある。


まとめ

ここまで書いてみて、今年のテーマは「興味や好奇心をお金に変える」ための試行錯誤なんだなぁと。ひらたくいうと、「やりたいことだけやって食えるようになる」のが目標。


ただ、6以外はほぼ個人での小さい動きになってしまう(得られる実績のインパクトが小さい)ので、なんとしても6をうまく軌道に載せないと、未来はない、というか来年がない *2。がんばります。


*1:仕事でちゃんとしたものをつくろうとすると、やっぱりどんなものでも深く踏み込む必要があるものなので。

*2:食いっぱぐれるまではいかないけど、上昇スパイラルが下降スパイラルになっていくイメージ。

2014-01-05

クラウドワークスでiOS7 Samplerのアイコンデザインを募集してみました

iOS7の新機能のサンプルコードを集めたアプリ『iOS7 Sampler』を、アプリ制作に関わるディレクターやデザイナーもすぐに試せるよう、AppStoreでも配布したいと思いつつ早数ヶ月。


すでにアプリの体裁を成して動作しているものをAppStoreに出すにあたって一番の障壁になっているのは、アイコンのデザインでした。


何度か自分でやろうとしたのですが、

  • iOS7の例の虹色のグラデーションの "7" を使おう
    • → そのままはNG。でもセンスのない自分が下手にアレンジするとダサくなりそう
  • テキストで "iOS7 Sampler"って書けばいいや
    • → せめてフォントやサイズやレイアウトをいい感じにしようとしてみるけど、時間がかかるし「すごく」良くなるイメージもない。

みたいな感じで少し手を出しては放置、ということを繰り返しているうちに2013年が終わってしまいました。中途半端に時間を使って中途半端なものをつくるよりは、お金を払ってでもちゃんと「その道のプロ」にお願いしたいなと。


というわけでクラウドワークスでコンペ形式でデザインを募集することにしました。


世界中から注目されるアプリのアイコンデザインの依頼/外注|アイコン作成の仕事 [ID:46506]

iOSアプリのアイコン/スプラッシュ画面のデザインを募集します。


▽目的・概要

iOS7 Samplerという、iOS7の新機能のサンプルコードを集めたアプリをGitHubで公開しています。

https://github.com/shu223/iOS7-Sampler

現在1800以上のstarを獲得しており、世界中のiOSアプリプログラマから評価されています。


これをアプリ制作に関わるディレクターやデザイナーもすぐに試せるよう、AppStoreでも配布するにあたり、アプリのアイコンとスプラッシュ画面のデザインを募集します。


▽要件

希望は

  • iOS7のフラットデザインに沿ったもの
  • シンプルなもの
  • 日本語や英語などの言語に依存しないもの("7" や "iOS" はOKです)
  • アプリの内容を伝えるもの

参考ページ:http://d.hatena.ne.jp/shu223/20130924/1379990718


アイコンとスプラッシュ画面は同じデザインを基調としてサイズだけ変えたものでも問題ありません。


▽その他のメリット

希望があれば、GitHubリポジトリにアイコンデザインのクレジットを載せることも可能です。

また私のブログで紹介する可能性もあります。iOSアプリ制作に携わる人たちから多くのアクセスがあるので、PR効果があるかもしれません。

http://d.hatena.ne.jp/shu223


5,000円というのはプロのみなさまの力を借りるには非常に低い金額だと思いますが、iOSアプリ制作界隈では注目されるかもしれないアプリなので、そのあたりも鑑みてご提案いただけると嬉しいです。よろしくお願いいたします。


2009 | 08 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2015 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2016 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 11 | 12 |
2017 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2018 | 02 |