大寒波です。
霜も降り息も白くなり、やっと冬らしくなってきました。
気温が大きく変化する時期は体調を崩しやすくなります。
風邪に気をつけて、外から帰ったら手洗いうがいを怠らないようにしましょう。
AngularJS のお勉強がてら Twitter クライアントでも作ろうと思いました。
やったことを自分の備忘録も兼ねて書いておきます。
やりたいこと
- Twitter クライアント作る(まずはタイムラインの表示)
- AngularJS で。
- yeoman 使いたい。
- AWS.S3 に配置してスマホで見たい。
Twitter アプリ登録
今回作成するアプリは Twitter に OAuth で認証(アクセス)します。
まずは、Twitter の Application Management にて今回作成するアプリを登録します。
※ 諸事情により、上記で登録しているアプリ名(twikurom)とクライアントアプリ名(mytwitter)が異なっていますが気にしないでください。
Callback URL は OAuth の認証URL である https://oauth.io/auth を設定してください。
設定しないとログイン後にアプリに戻ってきません。
OAuth.io アプリ登録
今回は、OAuth のプロバイダ認証を楽にしてくれる OAuth.io サービスを使用します。
Twitter で登録した API Key を設定します。
twikurom というアプリを追加していますが、デフォルトで追加されているアプリでも問題ないです。
General タブを開きます。
Public Key
は後ほど使用します。
Domains & URLs whitelist に localhost
と *.amazonaws.com
を追加してください。
アプリ作成
開発準備
まずは、ディレクトリの作成と必要なパッケージをインストールします。
yeoman の generator は公式の generator-angular を使用します。
$ mkdir mytwitter; cd mytwitter
$ npm install yo bower grunt-cli -g
$ npm install generator-angular generator-karma --save-dev
ジェネレータをローカルインストールしましたが、他でも使う場合は -g
つけてグローバルにインストールしてもいいと思います。
yeoman でプロジェクトを作成します。
$ yo angular
んで、色々聞かれます。
_-----_
| | .--------------------------.
|--(o)--| | Welcome to Yeoman, |
`---------´ | ladies and gentlemen! |
( _´U`_ ) '--------------------------'
/___A___\
| ~ |
__'.___.'__
´ ` |° ´ Y `
Out of the box I include Bootstrap and some AngularJS recommended modules.
? Would you like to use Gulp (experimental) instead of Grunt? No
? Would you like to use Sass (with Compass)? No
? Would you like to include Bootstrap? Yes
? Which modules would you like to include?
◉ angular-animate.js
◯ angular-aria.js
❯◉ angular-cookies.js
◉ angular-resource.js
◯ angular-messages.js
◉ angular-route.js
◉ angular-sanitize.js
◉ angular-touch.js
こんな感じで回答すると、プロジェクトのテンプレートがゔぁーっと作成されます。
途中で package.json を上書きするか聞かれてます(ログ流れちゃって見つけづらいんすけど)。Enter 押すと上書きしちゃうんで気をつけてくださいね。
npm WARN karma-jasmine@0.3.6 requires a peer of jasmine-core@* but none was installed.
npm WARN karma-phantomjs-launcher@0.2.3 requires a peer of karma@>=0.9 but none was installed.
npm WARN karma-phantomjs-launcher@0.2.3 requires a peer of phantomjs@>=1.9 but none was installed.
npm WARN grunt-karma@0.12.1 requires a peer of karma@^0.13.0 || >= 0.14.0-rc.0 but none was installed.
不足しているパッケージがあった場合、追加しましょう。
karma、jasmine-core、phantomjs が足らんと言われているので追加します。
$ npm install karma jasmine-core phantomjs --save-dev
ローカルサーバを起動して確認します。
$ grunt serve
おk。
ライブリロードしているので、ソースを変更して保存すると即座に反映されます。すごい。
ビルドしてローカルサーバで確認します。
$ grunt serve:dist
先ほどと同じ画面が表示されますが、distディレクトリに配置したビルド後のアプリが動いています。
dist
├── 404.html
├── favicon.ico
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.svg
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ └── glyphicons-halflings-regular.woff2
├── images
│ └── yeoman.8cb970fb.png
├── index.html
├── robots.txt
├── scripts
│ ├── scripts.aa0894ba.js
│ └── vendor.cca3e06b.js
└── styles
├── main.16c86e60.css
└── vendor.2ac5f564.css
Twitterクライアント作成
まずはじめに、OAuth の SDK を bower でインストールします。
bower でインストールしたモジュールは、ビルド時に index.html
に挿入されます。便利です。
$ bower install oauth-js --save
main.html
を編集してざっくりとしたレイアウトを決めます。
<div class="container">
<h1>My Twitter</h1>
<div class="row">
<div class="col-xs-12">
<button id="connectButton" type="button" class="btn btn-primary">サインイン</button>
<button id="getTimelineButton" type="button" class="btn btn-info">更新</button>
<button id="signOut" type="button" class="btn btn-link">サインアウト</button>
</div>
</div>
<hr/>
<div class="row">
<div class="col-xs-12" id="results">
<div class="row well">
<div class="col-xs-2">
<img src="https://pbs.twimg.com/profile_images/679162128750665729/r6ALQmhy_bigger.png" class="img-circle">
</div>
<div class="col-xs-10">
<small>名前</small>
<br> ツィート
</div>
</div>
</div>
</div>
</div>
grunt serve
で動かしてみるとこんな感じ
上記の html に angularjs のディレクティブを記述していきます。
<div class="container" ng-controller="MainCtrl">
<h1>My Twitter</h1>
<div class="row">
<div class="col-xs-12">
<button ng-click="main.connect()" id="connectButton" type="button" class="btn btn-primary">サインイン</button>
<button ng-click="main.refresh()" id="getTimelineButton" type="button" class="btn btn-info">更新</button>
<button ng-click="main.signOut()" id="signOut" type="button" class="btn btn-link">サインアウト</button>
</div>
</div>
<hr/>
<div class="row">
<div class="col-xs-12" id="results">
<div class="row well" ng-repeat="tweet in main.tweets">
<div class="col-xs-2">
<img ng-src="{{tweet.user.profile_image_url}}" class="img-circle">
</div>
<div class="col-xs-10">
<small>{{tweet.user.name}}</small>
<br> <span ng-bind-html="tweet.text"></span>
</div>
</div>
</div>
</div>
</div>
Twitter の認証やデータ取得を行うサービスを作成します。
services.js
を scripts
配下に追加します。
'use strict';
function twitterService($q) {
var authResult = false;
return {
initialize: function() {
// OAuth.io アプリの公開キー(PublicKey)を設定する。
OAuth.initialize('xxxxxxxxxxxxxxxxxxxxxxxxxxx', {
cache: true
});
authResult = OAuth.create('twitter');
},
isReady: function() {
return authResult;
},
connectTwitter: function() {
var deferred = $q.defer();
OAuth.popup('twitter').done(function(result) {
authResult = result;
deferred.resolve();
});
return deferred.promise;
},
clearCache: function() {
OAuth.clearCache('twitter');
authResult = false;
},
getLatestTweets: function() {
var deferred = $q.defer(),
url = '/1.1/statuses/home_timeline.json';
authResult.get(url)
.done(function(result) {
deferred.resolve(result);
})
.fail(function(err) {
deferred.reject(err);
});
return deferred.promise;
}
};
}
angular.module('mytwitterApp.services', [])
.factory('twitterService', twitterService);
index.html
にてサービスの script
タグを追加します。
<!-- build:js({.tmp,app}) scripts/scripts.js -->
<script src="scripts/app.js"></script>
<script src="scripts/services.js"></script>
<script src="scripts/controllers/main.js"></script>
<script src="scripts/controllers/about.js"></script>
<!-- endbuild -->
app.js
にて、モジュールを追加します。
angular
.module('mytwitterApp', [
'ngAnimate',
'ngCookies',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch',
'mytwitterApp.services'
])
最後にコントローラを実装します。
'use strict';
function MainController(twitterService) {
var vm = this;
vm.tweets = [];
twitterService.initialize();
vm.refresh = function() {
twitterService.getLatestTweets().then(function(result) {
vm.tweets = vm.tweets.concat(result);
}, function() {
// error
});
};
vm.connect = function() {
twitterService.connectTwitter().then(function() {
if (twitterService.isReady()) {
vm.refresh();
} else {
console.log('unable to connect twitter');
}
});
};
vm.signOut = function() {
twitterService.clearCache();
vm.tweets = [];
};
if (twitterService.isReady()) {
vm.refresh();
}
}
angular.module('mytwitterApp')
.controller('MainCtrl', MainController);
サインインボタンを押下すると Twitter 認証ダイアログが開きます。
S3
配置
ビルドしておきます。
$ grunt build
AWS の S3 に新しいバケットを作成しましょう。
アップロードメニューから、dist
配下に作成されたファイルをアップロードします。
バケットの設定
バケットのプロパティから、静的ウェブサイトホスティングを有効にします。
エントリポイントは index.html
を指定し保存します。
アクセス許可 → バケットポリシーの編集 にて、以下を設定します。
バケット名は変更してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::aws.bucket.name/*"
}
]
}
静的ウェブサイトホスティングのエンドポイントに設定されている URL にアクセスします。
localhost で実行したものと同様であればOKです。
せっかくだから携帯端末で確認してみましょう。
ちょっとレイアウトがごめんなさい。
参考
バージョン情報
- Chrome: 47.0.2526.106
- node: v4.2.4
- npm: 3.5.3
- yeoman: 1.6.0
- generator-angular: 0.15.1
- generator-karma: 1.0.1
- bower: 1.7.2
- grunt-cli v0.1.13
- grunt v0.4.5