VOYAGE GROUP エンジニアブログ

voyagegroup_techのブログ
VOYAGE GROUPエンジニアブログです。

iOS

【初心者でも簡単】facebookのPopでiOSアニメーションやってみた

こんにちは、VOYAGE GROUPエンジニアのガイアです
最近はiOSアプリの開発を主にやってます。
今までのiOSアプリ開発でアニメーションはほぼ触ったことがなかったのですが、今回アニメーションを行う用件が出てきたので、今回やったことを紹介します。
 

今年の5月始め、facebookがアニメーションエンジン「Pop」を発表しました。
「Pop」はfacebookがリリースしたアプリ「Paper」で使われているアニメーションライブラリをオープンソース化したものです。海外では盛り上がっています。
GithubでPopのページを見ると注目度の高さが分かります。

iOSでアニメーションは初めてですが、せっかくなのでPopを使ってみました。


- Pop

github pop
https://github.com/facebook/pop

facebook engineer blog
https://code.facebook.com/posts/234067533455773/introducing-pop-the-animation-engine-behind-paper/

このページでPopにおける目標が3つあげられています。
この目標自体がこのPopを使う利点でもあります。

  1. 一般的なアニメーションを便利に利用する
  2. ポップは拡張可能なフレームワークにする
  3. 開発者に優しいかつ強力なプログラミング·モデルを構築する


- install

CocoaPodsでインストールできます。

pod ‘pop’, ‘~> 1.0’

必要なところでインポートします。

#import <pop/POP.h>


- Code

では実際のコードを見ていきます。

SpringAnimation

Boundsを変更するばねのようなアニメーション

Spring
POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBounds];
- POPSpringAnimationのインスタンスを作成
- LayerBoundsをアニメーションさせる

DecayAnimation

XYの位置を変更するDecayアニメーション

decay
 POPDecayAnimation *animX = [POPDecayAnimation animationWithPropertyNamed:kPOPLayerPositionX];
- POPDecayAnimationのインスタンスを作成
- LayerPositionのXをアニメーションさせる

2つアニメーションを定義すると合成される。

BasicAnimation

basic
POPBasicAnimation *anim = [POPBasicAnimation animationWithPropertyNamed:kPOPViewAlpha];
- POPBasicAnimationのインスタンスを作成
- kPOPViewAlpha:Alphaの値をアニメーション

普通のアニメーションも同様に記述できるため覚えることが少なくて済みます

PropertyNamedを変更すればアニメーションする要素を変更できます。

割と簡単にアニメーションできてしまいます。
Popを使わずにアニメーションしようとすると実装方法は複数あります。
Objective-Cでアニメーションまとめ
 

PopではNSObjectにカテゴリで関数を追加しているため、CALayerやUIViewなどで同じアニメーションのコードを書けます。
これがコードが統一され、「開発者に優しいかつ強力なプログラミング·モデル」を提供できている要因の一つのようです。(ってfacebook engineer blog に書いてありました)


- 拡張可能

2番目のポップは拡張可能なフレームワークにするとはどういうことでしょう?
実はアニメーションのカスタムプロパティを作ることができるようです。
Playing with pop (iv)

試しにLabelの数値をカウントアップするプロパティを作ってみました。

customProperty

プロパティがなくても割と簡単に作ってしまえるのはいいですね。


- おまけ  複数アニメーションを直列で実行したい

Blockを使えばできますが、簡単にできるようにライブラリを提供してくれている人がいました。
このライブラリを使えばBlockが使えるだけでなく、Popの構文をさらに短縮してくれます。
POP+MCAnimate

install

pod 'POP+MCAnimate', '~> 1.0'
#define MCANIMATE_SHORTHAND
#import <POP+MCAnimate.h>

code

まずは構文の短縮です

同じ動作をするコードです

pop
pop+MCAnimate

さらにアニメーションをBlockで分けて記述することが可能です。
ばねのようなアニメーションの後X軸で回転するアニメーションです。

mcAnimate

割と直感的に書けるのでいいと思いました。
(おそらくPopそのままでも直列のアニメーションを書けるとはおもいますが…)



実際にPopを使ってみて、まだまだできないこともありますができる限りPopを使いたいです。
(コードが統一されるため)
そして、こんな僕でも簡単にアニメーションが作れました !
ありがとうPop !
 

記事のサンプルコード https://github.com/Gaia-Murata/PopDemo

iOS 7で追加されたMultipeerConnectivity.frameworkを早速使ってみた

Apple Storeに14時間並んでiPhone 5sを手に入れたら、 同期の @saya_223n が発売日にたった3時間で手に入れていて少し切なくなりました.  株式会社ジェネシックスのiOSエンジニア 坂田(@huin)です.


さて、iPhone 5s(とiPhone 5c)の発売に合わせてついにiOS 7がリリースされました. iOS 7の目玉はなんといってもUIの刷新ですが、UI以外にもフレームワークの変更や追加が数多く行われています.

というわけで、今回はiOS 7で個人的に注目している MultipeerConnectivity.frameworkについてご紹介したいと思います.

MultipeerConnectivity.framework とは

MultipeerConnectivity.framework (長いので以後MC Frameworkと表記します) はiOS 7で新規に追加されたフレームワークの一つです. Bluetooth or/and WiFiを利用して端末同士(3台以上も可能)で直接通信を行うためのフレームワークで、iOS 7で追加されたAirDropのAPI版だと考えると分かりやすいかと思います. 
 

WWDC 2013では、#708 Nearby Networking with Multipeer Connectivityというセッションで紹介されていました. 9/25現在、プログラミングガイドは存在しないのですが、MultipeerGroupChatというサンプルコードが配布されています. サンプルコード以上の例が作れなかったため非常に良いサンプルのため、今回はこのサンプルコードをベースにご紹介したいと思います.

注意 なお、このフレームワークはiPhone 5など、比較的新しい端末のみでサポートされています. AirDropが利用できないiPhone 4ではうまく動作しなかったのでご注意下さい.また、複数端末で利用する機能であるため、iOS 7が動作する端末が2台以上必要になります.

MultipeerGroupChat について

MC FrameworkのサンプルコードMultipeerGroupChatは、名前の通りグループチャット機能を実現するサンプルで、テキストメッセージの送信や写真の送受信ができます.

IMG_0002    IMG_0004


MC Frameworkの概要

MC Frameworkによる通信は、基本的にはMCSessionクラスとMCSessionDelegateプロトコルのメソッドを通じて行うだけです.サンプルでは、MCSessionの他に接続開始までのプロセスでMCAdvertiserAssistantMCBrowserViewControllerクラスを利用していますが、最低限これらのクラスだけで実現できます. 以下これらのクラスについて説明します.

デバイス同士の接続

端末同士で通信を行うためにはまず端末間の接続を確立する必要があります. MC FrameworkではAdvertiserとBrowserという2つの役割がこれを行います. Advertiserが自身を周囲に知らせ、Browserがこれを見つけて接続を確立するという流れです.

Advertiserの動作

Advertiserは周囲に対して自身の告知を行います. MC Frameworkでは MCAdvertiserAssistantクラスのオブジェクトを生成し、startメソッドを呼ぶことでこれを行います. サンプルでは SessionContainerクラスの初期化メソッドinitWithDisplayName:serviceType:の中で行っています.
 

// Session container designated initializer
- (id)initWithDisplayName:(NSString *)displayName serviceType:(NSString *)serviceType
{
    if (self = [super init]) {
        MCPeerID *peerID = [[MCPeerID alloc] initWithDisplayName:displayName];

        _session = [[MCSession alloc] initWithPeer:peerID securityIdentity:nil encryptionPreference:MCEncryptionRequired];
        _session.delegate = self;

        _advertiserAssistant = [[MCAdvertiserAssistant alloc] initWithServiceType:serviceType discoveryInfo:nil session:_session];
        [_advertiserAssistant start];
    }
    return self;
}

Browserの動作

Advertiserを探索し、接続を開始する役割はBrowserと呼ばれます. MC FrameworkではMCBrowserViewControllerクラスがAdvertiserの探索、接続およびUIの提供までを行ってくれます.

サンプルでは MainViewControllerのメソッドbrowseForPeers:でこれらの処理を行っています. といってもやっているのはMCBrowserViewControllerの初期化と、サービス提供に必要な最小/最大人数の設定、そして表示のみです.

セッションへの端末の参加/離脱イベントは、MCSessionDelegateプロトコルのsession:peer:didChangeState:メソッドで受け取れます. これらはSessionContainerクラスで実装されています.

デバイス間の通信

端末間の接続を確立したら、あとはMCSessionオブジェクトに対してデータを送るだけです.

MC Frameworkでは、データ、リソース、ストリームの3種類のデータ送信がサポートされており、それぞれ

  • -(BOOL)sendData:toPeers:withMode:error
  • -(void)sendResourceAtURL:toPeer:withTimeout:completionHandler:
  • -(NSOutputStream *)startStreamWithName:toPeer:error:

を呼ぶことで各種データの送信が可能です.

また、受信側は、MCSessionDelegateプロトコルの各メソッド、

  • - (void)session:didReceiveData:fromPeer:
  • - (void)session:didReceiveResourceAtURL:fromPeer:
  • - (void)session:didReceiveStream:withName:fromPeer:

そ実装することで、受信できます.

サンプルでは、SessionContainersendMessage:およびsendImage:メソッドでそれぞれテキスト(をNSDataにしたもの)と画像(のURL)を送信しています.


// 文字列の送信
- (Transcript *)sendMessage:(NSString *)message
{
    NSData *messageData = [message dataUsingEncoding:NSUTF8StringEncoding];

    NSError *error;
    [self.session sendData:messageData toPeers:self.session.connectedPeers withMode:MCSessionSendDataReliable error:&error];

    if (error) {
        return nil;
    } else {
        return [[Transcript alloc] initWithPeerID:_session.myPeerID message:message direction:TRANSCRIPT_DIRECTION_SEND];
    }
}

// 画像URLの送信
- (Transcript *)sendImage:(NSURL *)imageUrl
{
    NSProgress *progress;
    for (MCPeerID *peerID in _session.connectedPeers) {    
        progress = [self.session sendResourceAtURL:imageUrl withName:[imageUrl lastPathComponent] toPeer:peerID withCompletionHandler:^(NSError *error) {
            if (error) {
                NSLog(@"Send resource to peer [%@] completed with Error [%@]", peerID.displayName, error);
            } else {
                Transcript *transcript = [[Transcript alloc] initWithPeerID:_session.myPeerID imageUrl:imageUrl direction:TRANSCRIPT_DIRECTION_SEND];
                [self.delegate updateTranscript:transcript];
            }
        }];
    }

    Transcript *transcript = [[Transcript alloc] initWithPeerID:_session.myPeerID imageName:[imageUrl lastPathComponent] progress:progress direction:TRANSCRIPT_DIRECTION_SEND];
    return transcript;
}

まとめ

今回はMultipeerConnectivity.frameworkによる端末間通信について紹介しました. 接続の確立までが少し手間ですが、登場するクラスは少なく簡単に端末間通信を行うことが可能です.

端末間で直接通信を行うアプリはこれまでもありましたが、サーバーを介したものなど大掛かりなものが多かったように思います. MC Frameworkの登場で、身近にいる人同士で直接楽しめるアプリが増えるのではないかと思います. ジェネシックスでもこれらの新しいフレームワークを積極的に利用していくつもりです.
 

なお、VOYAGE GROUPでは現在、新規サービス立ち上げに向けてiOSエンジニアを募集しております. ご興味のある方は下記URLからお問い合わせ下さい.

採用情報 :  http://voyagegroup.com/crew/recruit/career/ios/

応募までは行かないけど…という方は@huinにご連絡頂けると社内バーのAJITOで飲みながらのお話などご招待させて頂きます. ご連絡お待ちしております!

iOSの究極テストツール:Calabash-iOSを使いこなすぞ!(1)

こんにちは、genesixで働いているiOSのエンジニアTonnyです。

Calabash-iOSって何?

まず、このツールを聞いたことが無い方に簡単に紹介します。Googleでcalabash-iosを検索すると一番のリンクをクリックすると、Calabash-iOSのHPに飛んでいきます。

原文を使って、簡単に説明すると

Calabash is an automated testing technology for Android and iOS native and hybrid applications

重要なポイントは全部太字にしました。よく見たら、すごいと思わないですね。このようなツールは世の中にすでにいっぱいありますよ。

既存のテストライブラリ・ツール

  1. KIF ( Keep It Functional ) by Square
    • UI Test用
    • accessibility labelを利用している
  2. Kiwi by Allending
    • BDD test用
    • Cedarと似てる
  3. Cedar by Pivotal
    • BDD test用
    • よくできている、OCUnitの代替品になる
    • Deviceのサポートがない
  4. GHUnit by Gabriel
    • OCUnitの代替品
  5. GTM Unit test by Google
    • OCUnitの代替品
  6. OCUnit by Sen:te, supported by Apple
    • Unit Testの一番良いツール
  7. UIAutomation by Apple
    • 大変使い辛い
    • 勿体無いなぁ!
  8. Zucchini by Playup
  9. FoneMonkey -> MonkeyTalk by Gorilla Logic
  10. Frank by Moredip
    • Deviceでの実行はサポートしているとはいえ、なかなか使いづらい
  11. Calabash-iOS by lessPainful
    • 今日の本題 一番良い
    • BDD用
    • SimulatorとDevice両方使える
    • Record/Playbackをサポート

先に結論からいうと:Calabash-iOSが一番良いツール

なぜかというと、

  1. Cucumber式のテストコード書き方。頑張れば、 全部日本語で テストコードを書ける。
  2. Record/Playback機能は非エンジニアのテスターを開放。これは素晴らしい。
  3. SimulatorとDeviceでのテストを同時にサポート。これは実になかなか難しいことだ。他のUIテストのフレームワークはSimulatorとDeviceを同時にサポートできていない。
    • UIAutomationは本当にダメな奴だ。

他の原因もあります。この記事では説明しませんが、興味があれば、Googleしてね。

その他の原因

  • CIシステムと統合しやすい
  • テストケースの中に画面キャプチャーを取れる

Cucumber式のテストコード

CucumberはBDDの世界で非常に有名なツールです。Gherkinを使っていますが、実はあまり気にしなくてもいいです。基本的に、そのテストコードが 自然言語(英語)と似ていて、読みやすい のが特徴です。

Calabashがデフォルトに入れてくれたテストケース

$ calabash-ios gen     # generate the basic test cases

これを実行すると、次のようなコードが生成される

$ cat features/my_first.feature 
Feature: Running a test
  As an iOS developer
  I want to have a sample feature file
  So I can begin testing quickly

Scenario: Example steps
  Given I am on the Welcome Screen
  Then I swipe left
  And I wait until I don't see "Please swipe left"
  And take picture

ちなみに、GFM(github flavored Markdown)で`cucumberを書くと上記のようなSyntax Highlightができる。これは読みやすいぞ!

Cucumberの詳細はまた同じぐらい長さのBlog Postが必要なので、ここでは割愛します。

Calabashがすでにいろいろな Steps を定義してくれたので、基本的な操作とテストは全部カーバー出来ました。その詳細はCalabash-iOSのWikiページを見れば、すぐに書けます。ここで敢えて一部の抜粋を説明します。

Calabash-iOSの Predefined Steps の抜粋

  1. Screenshots
  2. Playback of touch events
  3. Assertions

Record/Playback機能は大変助かる

チームのエンジニアが忙しくて、テストをサボっている。非エンジニアの方はチームにいって、どうしても助けてあげたい!ただ、テストコードを書けず、人力テストしかできない。2週間やったら、非エンジニアの方が疲れて、テストがうまく進めていけない〜〜。

このようなシーンは多々あると思いますね。このタイミングに、ちょっと力になるのはCalabash-iOSの自動テストですね。

一言の仕組み

Calabashは実際に**Private API**を使って、Eventをレコーディングして、後にそのレコーディングしたEventを完璧に再生できる。

Sample

まず、既存のアプリの.xcodeprojが所在のフォルダで、次のコマンドを叩く:

$ calabash-ios setup
$ xcodebuild -list

終わったら、自動的にテスト専用の**target**が生成される。例えば CoreDataBooksと言うサンプルコードを使うと、CoreDataBooks-calというターゲットが追加されます。

そのTargetを選択して、SimulatorもしくはDeviceに入れて、アプリを起動すると、Xcodeのコンソールに

2013-03-22 17:48:37.022 CoreDataBooks[11445:c07] Creating the server: <LPHTTPServer: 0x7574510>
2013-03-22 17:48:37.025 CoreDataBooks[11445:c07] simroot: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk
2013-03-22 17:48:37.027 CoreDataBooks[11445:c07] Started LPHTTP server on port 37265
2013-03-22 17:48:37.735 CoreDataBooks[11445:2103] Bonjour Service Published: domain(local.) type(_http._tcp.) name(Calabash Server)

このようなログが出力されます。

次は一番重要だ

ただ、長さの制限があるので(なぜかわからないよね! Livedoorさん!)次の記事を御覧ください。
 

androidとiOSで共通で使える暗号方式

こんにちは、VOYAGE GROUPのしんばし(@shinbashi)です。

昨今何につけてもスマートフォンですよね。
かくいう僕もPDAからのW-ZERO3という王道を通って来ました。

さて、最近は特にスマートフォン対応とか、アプリ化する機会が増えてきたと思います。
android版を作ればiOS版も出すよ!みたいな話になりますよね。
「android版だけでいい」
なんて言葉を信じて設計すると、後で痛い目を見るのは火を見るより明らかです。

前フリが長くなりました。
android版だけだと信じて僕が痛い目を見たのは暗号化・復号処理の部分です。
Javaはともかく、Objective-Cをよく知らなかったのでライブラリに頼るわけですが、
Objective-Cの暗号化・復号処理をしてくれるライブラリでは扱えないアルゴリズムとかあるんですね。

ざっくり調べた感じだと以下な感じです

表1 アルゴリズム比較表
AES ARCFOUR Blowfish DES DESede ECIES RC2 RC4 RC5 RSA CAST
javax.crypt(android)
CCCrypt(iOS)

表2 パディング比較表
no padding PKCS7 PKCS5 PKCS1 PAEP
javax.crypt(android)
CCCrypt(iOS) ※1

※1 PKCS7 ≒ PKCS5 (ブロック長の違いなのでPKCS7でPKCS5形式のものをunpad出来る)

実際、パディング処理は暗号化前、復号後に自前でやってしまえばいいのでなんとでもなりますね。
こうしてみると、暗号化アルゴリズムはAESで実装するのが妥当そうです。
Objective-Cで自前でPKCS5でunpadする場合は以下な感じになると思います。
+ (NSData *) pkcs5_unpad:(NSData *)data
{
    int pad = [[[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(data.length - 1, 1)] encoding:NSASCIIStringEncoding] characterAtIndex:0];
    if (pad > data.length) return nil;
    return [data subdataWithRange:NSMakeRange(0, data.length - pad)];
}
ざっくりまとめると
  • アルゴリズム:AES(鍵長は128でも256でもいいと思います)
  •  ブロック形式:CBC(EBCも使えます)
  • パディング:PKCS5(独自で実装できるのでお好きにどうぞ)
な感じで暗号化しておけば、android(java)でもiOS(Objective-C)でも取り扱いできます。
javax.cryptやCCCryptの使い方は色々な方が解説していらっしゃるのでそちらを参考にしていただければと思います。決してJavaのコード長すぎて写すのを面倒臭がっているわけではありません。

また、僕の場合だけかもしれませんが、CCCryptを使った時に、末尾に改行コードが含まれていて、NSDataからNSStringに変換しようとした時にエラーが発生したので、トリムする必要があるかもしれません。
また、WindowsPhoneに関してですが
「C#だし」
ってことで割愛させて頂きました。


おまけ

mixi Engineers' Blog » OpenSSLの暗号文をJava/Perl/Rubyで開く
http://alpha.mixi.co.jp/blog/?p=91

こちらでJavaでOpenSSLのパスフレーズから鍵を導出する処理が書かれていたので、せっかくなのでObjective-Cで実装するとどうなるのか書いてみました。

+(NSDictionary*) pass2keyInfo:(NSData *)pass salt:(NSData *)salt
{
    int keySize = 256;
    int ivSize  = 128;
    int keyAndIvSize = (keySize/8) + (ivSize/8);
    NSMutableData* result = [[NSMutableData alloc] init];
    NSMutableData* keyAndIv = [[NSMutableData alloc] init];
    while (keyAndIv.length < keyAndIvSize) {
        [result appendData:pass];
        [result appendData:salt];
        [result setData:[result MD5Digest]];
        [keyAndIv appendData: result];
    }
    NSData* key = [keyAndIv subdataWithRange:NSMakeRange(0, keySize/8)];
    NSData* iv  = [keyAndIv subdataWithRange:NSMakeRange(keySize/8, ivSize/8)];
    return [NSDictionary dictionaryWithObjectsAndKeys:key, @"key", iv, @"iv", nil];
}
参考
Java ™ 暗号化アーキテクチャー標準アルゴリズム名のドキュメント
http://java.sun.com/javase/ja/6/docs/ja/technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator

CommonCryptor.c
http://opensource.apple.com/source/CommonCrypto/CommonCrypto-36064/Source/CommonCryptor.c
記事検索
QRコード
QRコード