2015年12月17日木曜日

Android Wear で Notification をすぐに表示するために必要なこと

スマホで表示される通知が Android Wear でどのように表示されるのかを確認したいのに、なぜか Wear で表示されないという状況に嵌ったので、その解決メモ。

環境

  • Handheld:Nexus 5(OS:6.0.1 Marshmallow)
  • Wearable:Sony SmartWatch 3(OS:5.1.1)
    • 通知表示:すべて
    • シアターモード:OFF

※Nexus 5 と SmartWatch 3 は接続確立済み


接続が確立されていたら、スマホ側で表示された通知は Wear 側でも表示されるはず。それがスマホでは表示されているのに Wear は無反応。


解決

原因は、Wear へ届く通知には優先順位があり、バイブする or 音を鳴らす 通知でない限りは、すぐに Wear へ通知が届かないからだった。

バイブや音を鳴らさない通知の場合、5分後など適当な間隔で Wear へ通知が届き、しれっとカードが表示されているという状態になる。それに気づかなかったので、通知が届かない〜!!とハマった。

すぐに Wear へ通知を出したい場合は、バイブや音を鳴らすように注意するべし!


以下、動作確認に使用したサンプルコード。

2015年8月6日木曜日

Amazon.comへ法人でTax Informationを登録する

Amazon Apps & Services Developer Portal へデベロッパー登録するためには、amazon.comのアカウントが必要になる。

amazon.co.jpでアカウントを作っていても、amazon.comとamazon.co.jpではアカウントは共通化されていないので、amazon.co.jpのアカウントはamazon.comでは使用できない。amazon.comでは新規にアカウントを作成する必要がある。

更に、amazon.comでアカウントを作成する際、広告やIn-App課金などを想定している場合は、Tax Identityへの登録も要求される。やり方は、Tax Information Interviewに答えながらフォームを埋めていく形になるのだが、これがなかなか厄介だった。


Tax Information Interview




米国市民か?に「No」を選択。「Save and continue」ボタンをクリック。




Type of beneficial owner(受益権所有者のタイプ):Corporation
Place of organization:Japan
を選択。

Organization nameには、企業名を入力。
主に個人事業主用のオプションなので入力は必要ないかなと思ったけれど、一応、代表者名をDisregarded entity nameへ入力。

「Are you an agent acting as an intermediary?(仲介業者的なことをするエージェントなの?)」には「No」を選択。




Type of beneficial ownerにCorporationを選択すると、住所などを入力するフォームが表示されるので入力する。

Mailing address(郵便を出す時の宛先住所)はPermanent addressと同じなので、「Same as permanent address」を選択。

Tax identification number(TIN)、つまり納税者番号は日本には無いので、「I do not have a U.S. TIN or a foreign (non-U.S.) income tax identification number」を選択。

「Save and continue」ボタンをクリックして次に進むと、ここまでの入力確認(レビュー)が表示される。




非米国法人の基本的なフォーマット「W-8BEN-E」の証明書類が選択されている。

ここでは、確認のみで編集は出来ないので、修正をする場合はページ下の「Previous」ボタンをクリックして、戻って修正する。




Type of beneficial ownerにCorporationがチェックされていることを確認。




次に進むには「Save and continue」ボタンをクリック。




「I consent to electronic receipt of my information reporting documentation(税務情報を電子的に送ることに同意する)」を選択。

「I consent to provide my electronic signature(電子署名を提供することに同意する)」を選択。更に、Electronic signatureについての詳細が表示されるので、全てにチェックを入れる。






「 Signature of individual authorized to sign for beneficial owner」の欄には代表者名を入力。

「E-mail address」にはamazon.comへ登録したものと同じメールアドレスを入力。

「I certify that I have the capacity to sign for the entity identified on line 1 of this form.」をチェック。このフォームの1行目とは企業名が入力されている部分。その企業を代表してサインする能力が私にあることを証明するという内容。そこまで断定的に言われると、ちょっとビビってしまいますが、チェックしましょう(^_^;)

「Submit」ボタンをクリックすると、登録完了!


登録完了後の確認

Developer ConsoleからログインしてSETTING > Tax Identity を確認してみましょう。



Validationは、1時間もせずに完了しました。

2015年7月24日金曜日

ソーシャルボタンのアイコンをSVGファイル化する

ソーシャル系のガジェットやスクリプトは、多数のリソースを読み込むなど、ユーザーの体感スピードを劣化される。デザインも統一感が、なかなか出せない。

よって、自作しよう!となった時に、ソーシャルボタンのSVGファイルが欲しくなって調査した忘備録。


1. Twitter、Facebook、Google+ のSVGファイル作成


これら3つは、font-awesomeの中にアイコンがあるので、「encharm/Font-Awesome-SVG-PNG」を使う。


環境



手順


Font-Awesome-SVG-PNG のインストール

$ npm install -g font-awesome-svg-png

インストール確認

$ npm ls --depth=0 -g

インストールしたディレクトリ下の、bower_components/font-awesome-svg-png/には、black/ と white/ のディレクトリがあるので、黒や白のSGVファイルが欲しい場合は、そこからゲットすればよい。

赤など、黒白以外のカラーのSVGファイルが欲しい場合は、コマンドで書き出せる。

SVGファイルを書き出し

オプションの例
  • --dest: 出力パス
  • --color: 赤
  • --sizes: 80px
  • --icons: Twitter, Facebook, Google+
  • --no-png: SVGオンリー
$ font-awesome-svg-png --dest font-awesome --color red --sizes 80 --icons twitter,facebook,google-plus --no-png
※--iconsの指定では、カンマの後ろにスペースを挟まない


2. はてブ、LINE、Pocket のSVGファイル作成


これら3つは、font-awesomeの中にアイコンが無い。既にアイコンのパスをトレースしてSVG化してくれている方がいたので、ありがたく頂戴する。


参考



補足


これ、font-awesomeにあったっけ?という時は、font-awesomeのサイトで検索するとよい。

2015年4月6日月曜日

GAE/J上のGoogle Cloud EndpointsをバックエンドにしてSupersonicのdataアクセスを試してみた


Supersonic data セットアップ



1. データプロバイダの追加


プロジェクトディレクトリ下でconnectを発動し、プロジェクトのコネクトスクリーンを開く。
$ steroids connect

コネクトスクリーンの"Data"タブで「Custom Provider」を選択。




NAMEに任意のデータプロバイダ名を入力。
BASE URLは「https://YOUR_APP.appspot.com/_ah/api/」まで設定。v1などバージョンナンバーまでのパスにしない(後述のリソース追加設定のため)。



また、Google Cloud Endpointsはhttpsアクセスしか認めていないので、http://ではなく、https://にしておく。


2. リソースの追加


「ADD NEW RESOURCE」ボタンをクリックして、リソースを設定する。

NAMEに任意のリソース名を入力。
URL PATHは「yourApi/v1/」を入力。
例えば、API名が「playlistApi」、バージョンが「v1」の場合、URL PATHは「playlistApi/v1/」になる。



前述のプロバイダのBASE URLで「〜/v1/」まで含めてしまうと、必須入力であるリソースのURL PATHに何も設定できなくなるので、プロバイダのBASE URLを「api/」までと設定した。

これにより、リソースへのパスは、BASE URL + RESORCE URL PATH = 「https://YOUR_APP.appspot.com/_ah/api/playlistApi/v1/」となる。


3. アクションのカスタマイズ


「CUSTOMIZE ACTIONS」ボタンをクリックして、get/postなどのリクエストの、URL PATHやROOT KEYSを設定する。

例えば、コレクションを取得するgetのAPIパスが「playlist」の場合、URL PATHは「playlist」になる。



これにより、完成したエンドポイントへのパスは、BASE URL + RESOURCE URL PATH + ACTION URL PATH = 「https://YOUR_APP.appspot.com/_ah/api/playlistApi/v1/playlist」となる。


更に、Google Cloud Endpointsのコレクションのルートは「items」なので、ROOT KEYSに「items」を指定する。


「RELOAD MODEL FROM API」ボタンをクリックすると、エンドポイントとの通信が行われる。無事にコレクションが取得できると、最新のエンティティモデルの内容が表示される。





デバイスから data access 確認



トップ画面には、「https://YOUR_APP.appspot.com/_ah/api/playlistApi/v1/playlist」へアクセスした結果が表示されている。




API Explorerで、dataStoreにエンティティを1つ追加してみる。




デバイスで起動しているアプリ側のリストも、数秒後に、自動的に更新される。





10秒間隔で同期が発動する



ログを見ると、ほぼ10秒間隔でエンドポイントが叩かれている。




データバインディングはいいのだが、10秒おきにプルリクエストが発動するのでは、GAEのdataStoreのRead Quotaの消費が激しくなってしまう。

2015年4月現在の無料枠では、Read Operationsのリミットは50,000回/日なので、

( 60秒 / 10秒間隔 ) x 60分 = 360回/時

1時間アプリを起動しているだけで、360回のRead Operationsが発生する。

50,000回 / 360回 = 138.889

例えば、同時に138人が1時間アプリを起動しているだけで、50,000回のRead Operationsのクオータはすぐに消費されてしまう。


データバインディングは、supersonic.data APIのwhenChanged()で実現されている。
Playlist.all().whenChanged( function (playlists) {
        $scope.$apply( function () {
          $scope.playlists = playlists;
          $scope.showSpinner = false;
        });
    });

クオータの消費を避けたいなら、whenChanged()を使わずに、適切なタイミングで自作でデータの同期を行う必要があるなと。


参考:Supersonic Guides - Supersonic Framework

2015年4月3日金曜日

AppGyverのSupersonicを使ってdataアクセスするアプリを作っていて"Module 'common' is not available!"のエラーが出たら

AppGyverが提供しているハイブリッドアプリ開発のフレームワークSupersonic。

Supersonicを使ってアプリを作っていて、バックエンドのデータへアクセスする部分を組み込んだ途端、

Error: [$injector:nomod] Module 'common' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.

というエラーが出て、ハマってしまったので、その備忘録。



アクセスしようとしたデータもnot found状態になる。





ここで要求されている「common」モジュールは、プロジェクトのディレクトリ下のapp/common/。

Supersonic Guides - Supersonic Framework Utilising the common module
The common module also already contains a layout file (located at app/common/views/layout.html), which has all the basic dependecies of your project declared, such as supersonic.js, steroids.js and cordova.js. Because common is declared as a dependency to all modules by default, the layout file in there can be used to throughout the app just by removing any layout files from the module itself.

Supersonicを使ったアプリのレイアウトなど基本的な部分で使われているモジュール。

自分のプロジェクトには、確かにそのディレクトリが無い。


レイアウトという時点で、もしやと思ったのは、シンプルページアプリケーションとして、プロジェクトを作ったことがボトルネックになっているのではないか、マルチページアプリケーションとして、そもそもプロジェクトを作っていないと、このcommonモジュールはapp下にデプロイされないんじゃないか?ということ。


試しに、プロジェクトをマルチページで、一から作りなおしてみる。

$ steroids create プロジェクト名

続くアプリタイプの選択で、デフォルトのマルチページタイプを選択。



改めて、新しく作ったプロジェクトで、データのリポジトリを作り、テストデータを入れてみたら、今度はエラーが出ない!

テストデータも表示されている。




commonモジュールが無いエラーで嵌ったら、プロジェクトをマルチページタイプで作りなおせばOKです。


シングルページタイプのアプリでSueprsonicのdata APIが使えないということでは無いと思います。

あくまでも、Supersonicのチュートリアルを試していて、データのハンドリングをやりたいと思っただけなのに、commonモジュールにはまってしまった場合の対処方法です。

2015年3月14日土曜日

Android端末でとったスクリーンショットが「フォト」で同期されないと思ったら

Android端末でとったスクリーンショットが、PCのブラウザから「フォト」へアクセスしても見当たらないなと思ったら、自動バックアップがオンになっていても、スクリーンショットのディレクトリはデフォルトでは同期の対象外になっていました。

スクリーンショットのディレクトリを同期対象に含めるには以下の方法で。

Android端末で「フォト」を起動。「メニュー」から「端末内」を選択。


Screenshotsのクラウドアイコンがオフになっているので、タップしてオンに変更。


同期対象になりました。


以降は、スクリーンショットを撮る度に、PCのブラウザからGoogle+ の「フォト」へアクセスすると、すぐに画像が表示されます。

2015年2月27日金曜日

npm installしたパッケージの名前だけを取得する

ローカルにインストールしたパッケージの名前だけを取得したいときのコマンド。

$ npm ls --depth=0

実行すると、以下のように、トップレベルの名前だけ取得できる。
$ npm ls --depth=0
├── browser-sync@2.2.1
├── gulp@3.8.11
├── gulp-autoprefixer@2.1.0
├── gulp-concat@2.5.2
├── gulp-imagemin@2.2.1
├── gulp-less@3.0.1
├── gulp-minify-css@0.4.6
├── gulp-minify-html@1.0.0
├── gulp-newer@0.5.0
├── gulp-plumber@0.6.6
├── gulp-sass@1.3.3
├── gulp-uglify@1.1.0
├── rimraf@2.2.8
└── run-sequence@1.0.2

トップレベルだけでなく、もう一階層深く知りたいときは
$ npm ls --depth=1

つまりdepthを増やしていけばいい。


グローバルにインストールされたパッケージを取得したいときは-gを付けるだけ。
$ npm ls --depth=0 -g
/usr/local/lib
└── npm@2.5.1

MacでNode.jsとnpmをアンインストールするには

Node.jsをMacからアンインストールするには、以下のシェルスクリプトを実行する。
lsbom -f -l -s -pf /var/db/receipts/org.nodejs.pkg.bom \
| while read i; do
  sudo rm /usr/local/${i}
done
# uninstall node
sudo rm -rf /usr/local/lib/node \
     /usr/local/lib/node_modules \
     /var/db/receipts/org.nodejs.*;

# uninstall npm
sudo rm -rf ~/.npm;

# uninstall check
node -v;
npm -v;

最後にnodeやnpmコマンドを実行して失敗することを確認している。


上記のコードを、「uninstall-node.sh」などのファイル名で保存して、実行権限を付与。
$ chmod +x ./uninstall-node.sh

実行すると、Node.js、npmのアンインストールが完了する。
$ ./uninstall-node.sh


再インストールするには

公式のダウンロードサイトからpkgをダウンロードしてNode.jsを再インストールする。homebrewやnodebrewなどからインストールする方法もあるが、公式のダウンロードサイトからpkgをダウンロードしてインストールする方法の方が確実だと感じた。

再インストールが完了したら、念の為バージョン確認。
$ node -v
v0.12.0
$ npm -v
2.5.1


アンインストールに至った経緯

そもそも、Node.jsを再インストールして白紙からやり直そうと思ったのは、npm install 実行中に色々とエラーが発生したから。

例えば、gulp-sass@1.3.3をインストールでは、以下のエラーが発生。
Error: `libsass` bindings not found. Try reinstalling `node-sass`?
    at getBinding (/path/to/my/project/node_modules/gulp-sass/node_modules/node-sass/lib/index.js:21:11)
    at Object.<anonymous> (/path/to/my/project/node_modules/gulp-sass/node_modules/node-sass/lib/index.js:181:23)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (/path/to/my/project/node_modules/gulp-sass/index.js:3:17)
    at Module._compile (module.js:456:26)

更に、browser-sync@2.2.1のタスク実行では、以下のエラーが発生。
dyld: Symbol not found: _node_module_register
  Referenced from: /path/to/my/project/node_modules/browser-sync/node_modules/socket.io/node_modules/engine.io/node_modules/ws/build/Release/bufferutil.node
  Expected in: dynamic lookup


stackoverflowを見ると、Node.jsのバージョンが関係しているようだったので、クリーンな状態に一旦戻してからnpm installを試してみようと。

クリーンな状態から、再度、npm installを実行すると、gulp-sassもbrowser-syncも、問題なくローカルにインストールできた。

2015年2月26日木曜日

Git - gulpのパッケージをgitで共有したくなかったら

gulp、そしてgulpで利用するパッケージだけで、かなりディレクトリ容量が膨らむ。
これをgitで共有するのは嫌だなあと思って試行錯誤。

とりあえず、グローバルとローカルの両方にgulpをインストールするのではなく、グローバルだけにできないかと思ったが、逆(ローカルのみインストールする)はあっても、グローバルのみで動かす設定は発見できず。

gulp.jsのフローを見る限り、ローカルへのインストールは必須のようだし。
if (!env.modulePath) {
    gutil.log(
      chalk.red('Local gulp not found in'),
      chalk.magenta(tildify(env.cwd))
    );
    gutil.log(chalk.red('Try running: npm install gulp'));
    process.exit(1);
  }

このフローの通り、ローカルにgulpがインストールされていないと、gulpの実行はできない。
[13:20:52] Local gulp not found in ~/git/プロジェクト名
[13:20:52] Try running: npm install gulp


gulpが、グローバルとローカルとの、両方でインストールが必須なのには構造的な理由がある。

グローバルにインストールされたgulpは、ローカルにインストールされたgulpを実行するためのもの。このグローバルとローカルの2つのモジュールの中身は完全に同じもので、まったく同じモジュールをグローバルとローカルにインストールすることになる。

gulpコマンドが実行されると、gulp.jsのrequireで、ローカルのgulpがインポートされる。

そして、実際の処理(gulpfile.jsに書かれたタスク)はrequireされたローカルのgulpモジュールが全て行う。つまり、gulpは、自分自身が自分自身と同じモジュールをrequireして使うという仕組みで動いている。


では、ローカルへのインストールは仕方がないとしても、gitで共有したくない問題はどうにかできないかと思ったら、

gitなどでプロジェクト共有している場合、この node_modules を共有していると結構重かったりしますし、 package.json が共有されていたらあとで $ npm install をしたら必要なものが入ってくるため、 node_modules のディレクトリの共有は不要です。
Node.js 製の タスクランナー gulp.js を使ってみる - HAM MEDIA MEMO


ハッ!その手があったか!思わずポンと手を打ってしまった。


.gitignoreでnode_modulesをignoreすればいいじゃないですか。


gitからクローンした際は、npm installすればパッケージはインストールされるんだし。


ですよねぇ。これって常識だったのかしら。


追記

.gitignoreのサンプルは以下。一行だけだけれど。

/node_modules/

上記内容をプロジェクト直下にファイル名「.gitignore」で保存。
「node_modules」の前の/で、プロジェクトと同階層であることを明示。
「node_modules」の後の/で、ディレクトリであることを明示。

つまり、「/node_modules/」で、プロジェクト直下のnode_modulesディレクトリを無視する、という設定になる。