2015/11/30

AngularJs ✕ Firebaseで爆速イメージストア環境の作成

以前、AngularJs ✕ Firebaseで爆速リアルタイムアプリケーションの作成という記事を書きましたが、
今回は画像をさくっとどこかにあげて利用したい時、firebaseを使えば、5分で環境が出来ます。
S3、Parseの利用を検討しましたが、
  • 無料
  • APIドキュメントがわかりやすい(Parseはファイルストレージが20GBだが、ドキュメントがわかりにくい)
  • リアルタイムにデータ同期しやすい
上記の点でAngularJs×Firebaseを採用。なんといってもリアルタイムデータ同期が魅力的。
※Milkcocoaは検討してませんw

Firebaseとは

いわゆるモバイルBassでWebアプリケーション、モバイル・アプリケーションの開発者向けにリアルタイムにスケーラブルなバックエンドサービスを提供しています。
一定の転送量、接続数、容量は無料で、クレジットなしで使用できます。
ストレージ1GBまで無料なので、まぁ問題ないレベル。
バックアップは無料プランでは取れません。
https://www.firebase.com/

AngularFire

そして、AngularJsからFirebaseを利用できる、
AngularFireというAPIも公開されていますので、
バックエンドのコードを書く必要も、サーバも必要なく、
必要な作業に集中できます。
AngularFireのAPIを利用することで、
Angularjsのモデルが自動的に同期され、Firebase上でリアルタイムにデータバインディングされます。
これでhtml側でのview, Angularjsでのmodel, firebaseでストアされたjsonのデータの3wayデータバインディングが可能となります。

angular-file-upload

FlashによるFileAPI代替を提供するモジュール
HTML5のFileAPIを利用,HTML5のFileAPIサポートしていないブラウザ(IE8、IE9など)にはFlashを利用して同等の機能を提供。
今回はbase64データのURL生成してアップロードしています。

サンプル:画像アップロードアプリ


わずか110行で簡単イメージストアアプリが作成できます。
var ref = new Firebase("https://.firebaseio.com/");
上記の箇所をfirebaseにサインアップして、URLを書き換えるだけですぐ使えます。
サインアップはこちらから
https://www.firebase.com/login/

※注意

無料プランでストレージは1GBまでです。

Firebaseにストアされたデータにindexをはる方法

設定で、json形式でkey,rulesの中に.indexOnを記述するだけ
詳細はこちら
https://www.firebase.com/docs/security/guide/indexing-data.html

Firebaseにストアされたデータのセキュリティに関して

jsonでのセキュリティルールの設定が可能。
認証されたユーザがどのようにデータを変更できるかを決める。
データの転送はSSL経由。
さらなる詳細はこちら
https://www.firebase.com/docs/security/

AngularFireの使用アプリ

好きなアーティストの音楽をランキング順の聴くことができるサービスです。
Recentの箇所をfirebaseでストアしています。
Lamusica
http://manchan.github.io/lamusica/
githubはこちら
https://github.com/manchan/lamusica

AngularFireのドキュメントはこちら

ng-file-uploadのドキュメントはこちら

おわりに

5分は長すぎたかもしれません。

2015/11/27

JINS MEME Swift Sample

J!NS MEME Swift Sample

Jins MemeのサンプルコードをSwiftで書き、公開しました。
https://github.com/manchan/JinsMeme-Swift-Sample
J!NS MEMEから取得できるリアルタイムデータを確認できるサンプルのアプリです。
既存のサンプル(Objective-C)をSwiftに書き換え、それぞれのデータの詳細情報を閲覧できるようにしています。
ソースコードはGithubに置いてありますので、ご自由にお使い下さい。
JINS MEMEのSDKのバージョンは1.0.5です(2015/11/25現在)

動作環境

  • iOS 9.0+
  • Bluetooth 4.0(BLE)
  • J!NS MEMEが必要です。

そのままXcodeで実行できますが一から作成するための手順を記述しておきます。

①SDKからMEMELib.frameworkを導入
②Bluetooth権限設定
Capabilities > Background ModesをONにし、 Use Bluetooth LE accessory にチェック
③Bridginging Headerファイル作成
#import を記述
Build Settings > Swift Compiler - Code Generationに、Bridging Headerを指定
④下記より認証コードを設定
⑤あとはお好きにどうぞ

実行方法

Xcode 7でビルドしてください。
こちらよりアプリを作成して https://developers.jins.com/ja/apps/create/

取得したアプリID / アプリSecretをMEMELibのsetAppClientIdの引数にセットする必要があります。AppDelegate.swift at line 20 を書き換えてください。

内容

eyeMoveUp

視線が上に動いたかどうかを示す整数値

eyeMoveDown

視線が下に動いたかどうかを示す整数値

eyeMoveLeft

視線が左に動いたかどうかを示す整数値

eyeMoveRight

視線が右に動いたかどうかを示す整数値

blinkSpeed

まばたきのスピード(Millisecond)

blinkStrength

まばたきの強さ (一般的に、50~200の間におさまります。)

walking

かかとを地面についたかどうか。それを検出するとtrueになる

roll

姿勢を表す角度のうちのロール要素を示す度

pitch

姿勢を表す角度のうちのピッチ要素を示す度

yaw

姿勢を表す角度のうちのヨー要素を示す度

accX

加速度のX軸の値。-128 ~ 127 の1byteの整数値

accY

加速度のY軸の値。-128 ~ 127 の1byteの整数値

accZ

加速度のZ軸の値。-128 ~ 127 の1byteの整数値

fitError

JINS MEMEがきちんと装着されているかどうかを示す整数値。

powerLeft

電池残量を表す整数値

詳細情報はこちらより JINS MEME(ミーム) DEVELOPERS!!

おわりに

3点式の眼電位センサーが眼の動き(視線)やまばたきを検出してくれるので、
それを利用して、何かアクションを起こすというポインティングデバイスとしての利用がおもしろいなと思います。
眼電位センサーにより疲れ度合い、眠気、集中度などもデータ解析の仕方によっては推定することが可能になるのかなと思います。実際にJinsサイドはJINS MEME DRIVEという眠気を推定するドライバー向けiOSアプリを公開していますし。
様々なハードウェアと連携させてなにかできそうです。

2015/11/20

Chromeでjsonのkeyを数字にしている場合、勝手に昇順にされる件

筆者環境:MacOSX Yosemite, Google Chromeバージョン 46.0.2490.86 (64-bit)
表題通り、ありがた迷惑な機能。
これはV8 JavaScript EngineのECMAScript準拠でバグではない模様。
5年前くらい前から変わっていない。
firefoxでは降順ソートは維持され、問題ないことを確認。

問題のIssue 37404 - chromium - Chrome reorders keys in the dictionary (object) http://bit.ly/1Qw0utr

こんな感じに成形して、keyを数字で降順ソートしたが、勝手にkeyで昇順にソートされる。
{
    1444275582: {
        url: "https://instagram.com/p/8j9S8_r_BE/",
        img: "https://scontent.cdninstagram.com/hphotos-xap1/t51.2885-15/s640x640/sh0.08/e35/12120292_917670381655742_1569021259_n.jpg"
    },
    1444545530: {
        url: "https://instagram.com/p/8sALlWAfUJ/",
        img: "https://scontent.cdninstagram.com/hphotos-xtp1/t51.2885-15/e15/12106290_1294775143882158_1454631624_n.jpg"
    }
}

対策

created_atのkeyだけで降順ソートでjson成形
{
    {
        created_at: "1447984282",
        url: "https://instagram.com/p/-SfFKzy73D/",
        img: "https://scontent.cdninstagram.com/hphotos-xfp1/t51.2885-15/       s640x640/sh0.08/e35/12256594_516826635166064_1483786264_n.jpg"
    },
    {
        created_at: "1447984163",
        url: "https://instagram.com/p/-Se2neyurm/",
        img: "https://scontent.cdninstagram.com/hphotos-xfp1/t51.2885-15/e15/12230899_1538400876451449_364138165_n.jpg"
    }
}

解決方法

バックエンド側でjsonを吐き出す実装を変える(php)



         // APIから取得したデータを成形
        foreach($result["data"] as $k => $v){
            $insta_arr[$k]["created_at"] =  $v["created_time"];
            $insta_arr[$k]["url"] =  $v["link"];
            $insta_arr[$k]["img"] =  $v["images"]["standard_resolution"]["url"];            
            //いったんソートするキーを配列で取り出して、            
            $created_at_arr[$k] = $v["created_time"];
        }

        // keyで降順
        array_multisort($created_at_arr ,SORT_DESC,$insta_arr);
        echo json_encode($insta_arr);
        exit;

js側でソート(lodash)

    _.map(_.sortByOrder(insta_arr, ['created_at'], ['desc']), _.values);

参考

Issue 37404 - chromium - Chrome reorders keys in the dictionary (object) http://bit.ly/1Qw0utr
Issue 164 - v8 - Wrong order in Object properties interation - V8 JavaScript Engine
https://code.google.com/p/v8/issues/detail?id=164
Google Chromeでjsonオブジェクトを扱う際に、勝手にキーでソートされたよ
http://log.miraoto.com/2013/02/738/

2015/11/16

SwiftでSafariのリーディングリストに追加

Safariのリーディングリストは、後で見たいウェブページをリーディングリストに登録することで、ネット環境が無いオフラインでもiPhone内のストレージにキャッシュされて記事の続きを閲覧できる機能
今回はリストに追加する実装を記載

はじめに

Build PhasesのLink Binary With Librariesに
iOS7から追加されたSafari Service Frameworkを追加

実装

import SafariServices

let title = "my profile site"
let url = NSURL(string: "http://manchan.github.io")

// リーディングリストに追加できるかどうかチェック
let isValid = SSReadingList.supportsURL(url)
let list = SSReadingList.defaultReadingList()
var msg:String?

// 追加
if isValid && list.addReadingListItemWithURL(url, title: title, previewText: nil, error: nil){
    msg = "追加に成功"
}else{
    msg = "追加に失敗"
}

// 確認       
UIAlertView(title: "追加test", message: msg, delegate: nil, cancelButtonTitle: "OK").show()

用例

AppleWatchからニュースの記事見出しだけ見て、親iPhoneのsafariに追加するなどが考えられる実装(Google News, NYTimes)
watchOS1ならopenParentApplicationで送信
watchOS2ならWatch Connectivityで

注意

追加済みのURLとかのチェックはできない、また既出のリストも取得、編集、削除できない
読みだすことができれば、いろいろとできそうなので残念。
オフライン閲覧が可能なので、ストレージにキャッシュが貯まるので膨大にある場合、キャッシュを削除する必要がある
iOS9であれば設定から
一般 > ストレージとiCloudの使用状況 > ストレージを管理 > Safari
のリーディングリストを編集を押して削除

参考

2015/11/13

RSSで取得したpubDateをNSDateFormatterで変換(Swift)

ロケールが日本語の時に上手く日付を取得できなかったので、残しておく。
Wed, 04 Nov 2015 15:02:11 +0000
上記のような書式の日付を
11月04日(水)
に変更します。

        // string = "Wed, 04 Nov 2015 15:02:11 +0000"
        let identifier = NSLocale.currentLocale().localeIdentifier

        if identifier == "ja_JP" {
            let dateFormatter = NSDateFormatter()
            // 書式が変わらない固定ロケールで一度値を取得
            dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
            dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss ZZZZ"
            let r_date = dateFormatter.dateFromString(string!)

            if let d = r_date {
                 // ロケールを日本語にして曜日を取得
                dateFormatter.locale = NSLocale(localeIdentifier: "ja_JP") 
                dateFormatter.dateFormat = "MM月dd日(E)"
                tmpEntry.addObject(dateFormatter.stringFromDate(d))
            }
        }
        // 日本語以外
        else{

        }
localeIdentifierを一度en_US_POSIXにするのがポイント。

参考

NSDateFormatterの使い方まとめ
http://qiita.com/gonsee/items/d3fb641914d2ca45e858
Swiftで現在日時を取得し、独自のフォーマットで出力する方法
http://qiita.com/cotrpepe/items/261833c465af5d70f867