Swiftの横スクロースができるUIコンポーネントPageMenuを使ってみた
横スクロールができるコンポーネントPageMenuを使ってみた
以下のページを参考にした。
Swift 横スクロール画面切り替えを簡単に実装する。 - Qiita
1.PageMenuのファイルを取得
githubのページからプロジェクトファイルを取得する
PageMenu
プロジェクト毎Zipファイルをダウンロードするか、以下のファイルだけでもいい。
Classes/CAPSPageMenu.swift
4.PageMenu関連のコードを追記
PageMenuの変数を宣言
class ViewController: UIViewController { var pageMenu : CAPSPageMenu? }
PageMenuに追加するViewを宣言
viewDidLoad関数の中に記述
// Viewを格納する配列 var controllerArray : [UIViewController] = [] // 追加するViewを作成 let controller1 : UIViewController = UIViewController() controller1.title = "ビューその1" controller1.view.backgroundColor = UIColor.blueColor() controllerArray.append(controller1) let controller2 : UITableViewController = UITableViewController() controller2.title = "ビューその2" controller2.view.backgroundColor = UIColor.redColor() controllerArray.append(controller2) let controller3 : UITableViewController = UITableViewController() controller3.title = "ビューその3" controller3.view.backgroundColor = UIColor.greenColor() controllerArray.append(controller3)
PageMenuの設定とビューの追加
こちらもviewDidLoad関数の中に記述
// PageMenuの設定 let parameters: [CAPSPageMenuOption] = [ .MenuItemSeparatorWidth(4.3), .UseMenuLikeSegmentedControl(true), .MenuItemSeparatorPercentageHeight(0.1) ] // PageMenuへのビューの追加と、PageMenuのビューサイズを設定 pageMenu = CAPSPageMenu(viewControllers: controllerArray, frame: CGRectMake(0.0, 20.0, self.view.frame.width, self.view.frame.height), pageMenuOptions: parameters) // PageMenuのビューを親のビューに追加 self.view.addSubview(pageMenu!.view)
画面の下部にUIToolbarを追加する
PageMenuにToolbarを追加してみる。
StoryBoardでToolbarを追加し、制約でLeft、Rightは-20、Bottomは0に設定。
このままだとToolbarが見えないので、PageMenuのビューをToolbarの後ろに移動
// PageMenuのビューを親のビューに追加 self.view.addSubview(pageMenu!.view) // PageMenuのビューをToolbarの後ろへ移動 ←追加 self.view.sendSubviewToBack(pageMenu!.view) ←追加
できあがりはこんな感じ。
ソースはこちら
ViewControlle.swiftの内容
import UIKit class ViewController: UIViewController { var pageMenu : CAPSPageMenu? override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. // Viewを格納する配列 var controllerArray : [UIViewController] = [] // 追加するViewを作成 let controller1 : UIViewController = UIViewController() controller1.title = "ビューその1" controller1.view.backgroundColor = UIColor.blueColor() controllerArray.append(controller1) let controller2 : UITableViewController = UITableViewController() controller2.title = "ビューその2" controller2.view.backgroundColor = UIColor.redColor() controllerArray.append(controller2) let controller3 : UITableViewController = UITableViewController() controller3.title = "ビューその3" controller3.view.backgroundColor = UIColor.greenColor() controllerArray.append(controller3) // PageMenuの設定 let parameters: [CAPSPageMenuOption] = [ .MenuItemSeparatorWidth(4.3), .UseMenuLikeSegmentedControl(true), .MenuItemSeparatorPercentageHeight(0.1) ] // PageMenuのビューのサイズを設定 pageMenu = CAPSPageMenu(viewControllers: controllerArray, frame: CGRectMake(0.0, 20.0, self.view.frame.width, self.view.frame.height), pageMenuOptions: parameters) // PageMenuのビューを親のビューに追加 self.view.addSubview(pageMenu!.view) // PageMenuのビューをToolbarの後ろへ移動 self.view.sendSubviewToBack(pageMenu!.view) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
node.js + express + socket.io でスライドショーのシンクロアプリを作成
概要
複数デバイス間でスライドを同期する方法はないか・・・という話があったので、
node.js + express + socket.ioを使って、スライドショーの同期アプリを作ってみた。
こんな感じで左の画面でスライドを変更すると、右の画面も同期して自動的にスライドが変わる。
タブレットを想定していたので、Webアプリにして各種ブラウザで実行できる様にした。
スライドショーのライブラリを選定
スライドショーのライブラリは以下を使用。
Supersized - Full Screen Background Slideshow jQuery Plugin
細かい設定ができて使いやすい。
各種バージョン
node.js :0.10.36
express : 4.11.2
socket.io : 1.3.4
expressでプロジェクト作成
テンプレートはejsを使うため、「-e」を追加して実行
$ express -e slide_sync create : slide_sync create : slide_sync/package.json create : slide_sync/app.js create : slide_sync/public create : slide_sync/public/images create : slide_sync/public/javascripts create : slide_sync/public/stylesheets create : slide_sync/public/stylesheets/style.css create : slide_sync/routes create : slide_sync/routes/index.js create : slide_sync/routes/users.js create : slide_sync/views create : slide_sync/views/index.ejs create : slide_sync/views/error.ejs create : slide_sync/bin create : slide_sync/bin/www install dependencies: $ cd slide_sync && npm install run the app: $ DEBUG=slide_sync:* ./bin/www
[package.json]にsocket.ioの定義を追加
{ ... "dependencies": { ... "serve-favicon": "~2.2.0", "socket.io": "~1.3.4" } }
プロジェクトフォルダに移動してインストールを実行
$ cd slide_sync/ $ npm install
app.jsの編集
app.jsに以下を追加
// サーバモジュール作成 var server = require('http').Server(app); var io = require('socket.io')(server); var port = process.env.PORT || 3000; server.listen(port); // スライド操作関連 var current_slide = 0; // 現在のスライド番号を保持 //クライアントから接続があった時 io.sockets.on('connection', function (socket) { // コネクションが確立されたら'connected'メッセージを送信する console.log("[connection] has received current_slide:[" + current_slide + "]"); socket.emit('connected', {value: current_slide}); // メッセージ送信(送信者にも送られる) socket.on("C_to_S_message", function (data) { console.log("[C_to_S_message] has received"); current_slide = data.value; io.sockets.emit("S_to_C_message", {value: current_slide}); }); // ブロードキャスト(送信者以外の全員に送信) socket.on("C_to_S_broadcast", function (data) { console.log("[C_to_S_broadcast] has received"); current_slide = data.value; socket.broadcast.emit("S_to_C_message", {value: current_slide}); }); // 切断したときに送信 socket.on("disconnect", function () { console.log("[disconnect] has received"); }); });
スライドhtmlを変更
supersizedライブラリの[slide.html]をベースに、views/index.ejsを作成。
サーバとのやりとり関連の処理を追加
<script type="text/javascript"> var s = io.connect('http://young-hollows-5254.herokuapp.com'); //heroku // var s = io.connect('http://localhost:3000'); //ローカル //サーバから受け取るイベント s.on("connect", function () {}); // 接続時 s.on("connected", function (data) { addMessage(data.value); }); // 接続時 s.on("disconnect", function (client) {}); // 切断時 s.on("S_to_C_message", function (data) { addMessage(data.value); }); //クライアントからイベント送信(イベント名は自由に設定できます) function sendMessage(slide_index) { s.emit("C_to_S_message", {value: slide_index}); //サーバへ送信 } function sendBroadcast(slide_index) { s.emit("C_to_S_broadcast", {value: slide_index}); // サーバへ送信 } //jqueryでメッセージを追加 function addMessage (value,color,size) { api.goTo(value + 1); } </script>
ページ切り替えの時にサーバとの通信を行う。
<!--Arrow Navigation--> <a id="prevslide" class="load-item" onclick="click_prevslide();"></a> <a id="nextslide" class="load-item" onclick="click_nextslide();"></a>
function click_prevslide() { var slide_num = $.supersized.vars.options.slides.length; sendMessage( ( ($.supersized.vars.current_slide - 1 + slide_num) % slide_num ) ); } function click_nextslide() { var slide_num = $.supersized.vars.options.slides.length; sendMessage( ( ($.supersized.vars.current_slide + 1 + slide_num) % slide_num ) ); }
herokuにデモサイドをアップロード
heroku用の実行コマンドファイル[Procfile]を作成
[Procfile]を作成
web: node app.js
herokuにアップロード
$ heroku create $ git add . $ git commit -m "first commit" $ git push heroku master
iPhoneからAndroidのXperia Z Ultraに変えたら意外とすんなり移行できた
iPhoneからXperiaへ
ipod Touchから始まり、iPhone4→iPhone4S→iPhone5Sとiphoneユーザでしたが、
おおきな画面にしたくてiPhone6 Plusを検討していたけど・・・
・10万?高い!
・SIMフリー売ってない!
と言うことで、いろいろ検討していたらこちらを発見!
Xperia Z Ultra | Smartphone - Sony Smartphones (Global UK English)
お値段も4万円を切るお手頃な価格。
てことで、これ買いました。
Xperia Z Ultra使ってみて
Android端末をメイン端末として使うのは初めて。
スクロールで端に来たときにiPhoneではバウンドするのが
Androidではピタッと止まるので違和感があったけど、
動きの軽快さや操作への追随など、ほとんど気にならないレベル。
Androidもここまで進化していたのか!
メリット
なんと言っても画面が大きい
6.4inch画面はiPhone6 Plusよりも一回り大きい
Webやfacebookの閲覧が快適すぎて小さい画面に戻れない
画面サイズが大きいからブログの編集もある程度可能だけど、
文字入力関連(キーボードなど)が操作しづらいので長文はつらい
防水・防塵機能完備
水中に落としても無事だった例もあるくらいの防水機能付き
雨くらいなら余裕ですな
結構薄い
ズボンの後ろポケットに入れて持ち運んでます。
今のところ曲がってはいない。
動きもサクサク
サクサク動いて反応もGood!
デメリット
プラスエリア未対応
プラスエリア未対応なので、電波が弱いところで繋がらないことあり
都内では屋外では気にならないが、地下の店で奥に座ったりすると圏外になることもしばしば
近々プラスエリア対応に挑戦する予定
キー入力など片手操作はできない
両手でキーボードのレイアウトで入力してます
swiftで現在地情報と文字列から目的地情報を取得し、現在地と目的地を結ぶ経路を取得してマップに表示
作成する機能
・現在地の位置情報を取得
・目的地の文字列から目的地の位置情報を取得
・現在地と目的地を結ぶ経路情報を取得
・地図上にこれらを表示
作成するアプリの処理内容
ユーザが検索バーに目的地の文字列を入力し、検索ボタンをタップすると現在地と目的地にピンを立て、経路を表示する
1.目的地の文字列から目的地の位置情報を取得
2.現在地の位置情報を取得
3.現在地から目的地までの経路を取得
4.現在地、目的地、経路を地図に表示
実行結果は以下(お茶の水から新宿までの経路)
前作業
まずは作業用プロジェクトを作成する
・新規プロジェクトの作成からSingleViewApplicationを選択
・ProjectNameに好きな名前を入力
・Languageは「Swift」を選択
1.目的地の文字列から目的地の位置情報を取得
位置情報の取得許可を設定するため、Supporting Files の Info.plistを右クリックして、
「Open as」-「Source Code」で開いて以下の4行を追加
Info.plist
<plist version="1.0"> <dict> ・・・ここから・・・ <key>NSLocationAlwaysUsageDescription</key> <string>I have learned more on stack overflow than anything else</string> <key>NSLocationWhenInUseUsageDescription</key> <string>The spirit of stack overflow is coders helping coders</string> ・・・ここまで・・・ </dict> </plist>
各種Delegateを設定
class定義のUIViewControllerのあとに、以下のDelegateを設定を追加
【, CLLocationManagerDelegate, MKMapViewDelegate, UISearchBarDelegate】
ViewController.swift
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate, UISearchBarDelegate { ・・・ }
・CLLocationManagerDelegate : 位置情報取得用
・MKMapViewDelegate : マップ用
・UISearchBarDelegate : 検索バー用
それぞれのDelegateにメインビューのアドレス(self)をセットしておかないと
Delegateメソッドが呼ばれないので注意。
ViewController.swift
override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. locationManager = CLLocationManager() locationManager.delegate = self mapView.delegate = self destSearchBar.delegate = self }
2.現在地の位置情報を取得
位置情報取得用のコードを追加
【locationManager.startUpdatingLocation()】を実行した後に呼び出されるDelegateメソッドを記述
現在地の測位が終わったら以下のメソッドのどちらかが呼ばれる
成功時:func locationManager(manager: CLLocationManager!,didUpdateLocations locations: [AnyObject]!)
失敗時:func locationManager(manager: CLLocationManager!,didFailWithError error: NSError!)
ViewController.swift
// 位置情報取得に成功したときに呼び出されるデリゲート. func locationManager(manager: CLLocationManager!,didUpdateLocations locations: [AnyObject]!){ userLocation = CLLocationCoordinate2DMake(manager.location.coordinate.latitude, manager.location.coordinate.longitude) // 現在地の取得に成功したら、ピンを立てておく var userLocAnnotation: MKPointAnnotation = MKPointAnnotation() userLocAnnotation.coordinate = userLocation userLocAnnotation.title = "現在地" // ピンをタップしたときに表示される文字を指定 mapView.addAnnotation(userLocAnnotation) } // 位置情報取得に失敗した時に呼び出されるデリゲート. func locationManager(manager: CLLocationManager!,didFailWithError error: NSError!){ print("locationManager error") }
検索バーの検索ボタンを押したときに現在地の取得を開始する場合は以下のように記述
ViewController.swift
// 検索ボタンを押したときにキーボードを隠して検索実行
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
locationManager.startUpdatingLocation()
}
3.現在地から目的地までの経路を取得
目的地の文字列から位置情報を取得
検索バーの文字列(destSearchBar.text)から目的地の位置情報を取得する
ViewController.swift
func searchBarSearchButtonClicked(searchBar: UISearchBar) { // キーボードを隠す destSearchBar.resignFirstResponder() // 目的地の文字列から座標検索 var geocoder = CLGeocoder() geocoder.geocodeAddressString(destSearchBar.text, {(placemarks: [AnyObject]!, error: NSError!) -> Void in if let placemark = placemarks?[0] as? CLPlacemark { // 目的地の座標を取得 self.destLocation = CLLocationCoordinate2DMake(placemark.location.coordinate.latitude, placemark.location.coordinate.longitude) // 目的地にピンを立てる self.mapView.addAnnotation(MKPlacemark(placemark: placemark)) // 現在地の取得を開始 self.locationManager.startUpdatingLocation() } }) }
現在地と目的地を結ぶ経路情報を取得
現在地(userLocation)と目的地(destLocation)を指定して経路情報を取得
ViewController.swift
func getRoute() { // 現在地と目的地のMKPlacemarkを生成 var fromPlacemark = MKPlacemark(coordinate:userLocation, addressDictionary:nil) var toPlacemark = MKPlacemark(coordinate:destLocation, addressDictionary:nil) // MKPlacemark から MKMapItem を生成 var fromItem = MKMapItem(placemark:fromPlacemark) var toItem = MKMapItem(placemark:toPlacemark) // MKMapItem をセットして MKDirectionsRequest を生成 let request = MKDirectionsRequest() request.setSource(fromItem) request.setDestination(toItem) request.requestsAlternateRoutes = false // 単独の経路を検索 request.transportType = MKDirectionsTransportType.Any let directions = MKDirections(request:request) directions.calculateDirectionsWithCompletionHandler({ (response:MKDirectionsResponse!, error:NSError!) -> Void in response.routes.count if (error != nil || response.routes.isEmpty) { return } var route: MKRoute = response.routes[0] as MKRoute // 経路を描画 self.mapView.addOverlay(route.polyline!) // 現在地と目的地を含む表示範囲を設定する self.showUserAndDestinationOnMap() }) }
4.現在地、目的地、経路を地図に表示
現在地、目的地を含む範囲を表示範囲にして地図に表示する
ViewController.swift
// 地図の表示範囲を計算 func showUserAndDestinationOnMap() { // 現在地と目的地を含む矩形を計算 var maxLat:Double = fmax(userLocation.latitude, destLocation.latitude) var maxLon:Double = fmax(userLocation.longitude, destLocation.longitude) var minLat:Double = fmin(userLocation.latitude, destLocation.latitude) var minLon:Double = fmin(userLocation.longitude, destLocation.longitude) // 地図表示するときの緯度、経度の幅を計算 var mapMargin:Double = 1.5; // 経路が入る幅(1.0)+余白(0.5) var leastCoordSpan:Double = 0.005; // 拡大表示したときの最大値 var span_x:Double = fmax(leastCoordSpan, fabs(maxLat - minLat) * mapMargin); var span_y:Double = fmax(leastCoordSpan, fabs(maxLon - minLon) * mapMargin); var span:MKCoordinateSpan = MKCoordinateSpanMake(span_x, span_y); // 現在地を目的地の中心を計算 var center:CLLocationCoordinate2D = CLLocationCoordinate2DMake((maxLat + minLat) / 2, (maxLon + minLon) / 2); var region:MKCoordinateRegion = MKCoordinateRegionMake(center, span); mapView.setRegion(mapView.regionThatFits(region), animated:true); } // 経路を描画するときの色や線の太さを指定 func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! { if overlay is MKPolyline { var polylineRenderer = MKPolylineRenderer(overlay: overlay) polylineRenderer.strokeColor = UIColor.blueColor() polylineRenderer.lineWidth = 5 return polylineRenderer } return nil }
実行イメージ
こんな感じで経路がちょうど収まる倍率で地図を表示する。
今回作ったプロジェクトはこちら
yuriken27/MapViewDirectionsTestSwift · GitHub
ViewController.swift の内容
ViewController.swift
import UIKit import MapKit import CoreLocation class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate, UISearchBarDelegate { var locationManager: CLLocationManager! var userLocation: CLLocationCoordinate2D! var destLocation: CLLocationCoordinate2D! @IBOutlet weak var mapView: MKMapView! @IBOutlet weak var destSearchBar: UISearchBar! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. locationManager = CLLocationManager() locationManager.delegate = self mapView.delegate = self destSearchBar.delegate = self // 位置情報取得の許可状況を確認 let status = CLLocationManager.authorizationStatus() // 許可が場合は確認ダイアログを表示 if(status == CLAuthorizationStatus.NotDetermined) { println("didChangeAuthorizationStatus:\(status)"); self.locationManager.requestAlwaysAuthorization() } //位置情報の精度 locationManager.desiredAccuracy = kCLLocationAccuracyBest //位置情報取得間隔(m) locationManager.distanceFilter = 300 } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // 検索ボタンを押したときにキーボードを隠して検索実行 func searchBarSearchButtonClicked(searchBar: UISearchBar) { // キーボードを隠す destSearchBar.resignFirstResponder() // セット済みのピンを削除 self.mapView.removeAnnotations(self.mapView.annotations) // 描画済みの経路を削除 self.mapView.removeOverlays(self.mapView.overlays) // 目的地の文字列から座標検索 var geocoder = CLGeocoder() geocoder.geocodeAddressString(destSearchBar.text, {(placemarks: [AnyObject]!, error: NSError!) -> Void in if let placemark = placemarks?[0] as? CLPlacemark { // 目的地の座標を取得 self.destLocation = CLLocationCoordinate2DMake(placemark.location.coordinate.latitude, placemark.location.coordinate.longitude) // 目的地にピンを立てる self.mapView.addAnnotation(MKPlacemark(placemark: placemark)) // 現在地の取得を開始 self.locationManager.startUpdatingLocation() } }) } // 位置情報取得に成功したときに呼び出されるデリゲート. func locationManager(manager: CLLocationManager!,didUpdateLocations locations: [AnyObject]!){ userLocation = CLLocationCoordinate2DMake(manager.location.coordinate.latitude, manager.location.coordinate.longitude) var userLocAnnotation: MKPointAnnotation = MKPointAnnotation() userLocAnnotation.coordinate = userLocation userLocAnnotation.title = "現在地" mapView.addAnnotation(userLocAnnotation) // 現在地から目的地家の経路を検索 getRoute() } // 位置情報取得に失敗した時に呼び出されるデリゲート. func locationManager(manager: CLLocationManager!,didFailWithError error: NSError!){ print("locationManager error") } func getRoute() { // 現在地と目的地のMKPlacemarkを生成 var fromPlacemark = MKPlacemark(coordinate:userLocation, addressDictionary:nil) var toPlacemark = MKPlacemark(coordinate:destLocation, addressDictionary:nil) // MKPlacemark から MKMapItem を生成 var fromItem = MKMapItem(placemark:fromPlacemark) var toItem = MKMapItem(placemark:toPlacemark) // MKMapItem をセットして MKDirectionsRequest を生成 let request = MKDirectionsRequest() request.setSource(fromItem) request.setDestination(toItem) request.requestsAlternateRoutes = false // 単独の経路を検索 request.transportType = MKDirectionsTransportType.Any let directions = MKDirections(request:request) directions.calculateDirectionsWithCompletionHandler({ (response:MKDirectionsResponse!, error:NSError!) -> Void in response.routes.count if (error != nil || response.routes.isEmpty) { return } var route: MKRoute = response.routes[0] as MKRoute // 経路を描画 self.mapView.addOverlay(route.polyline!) // 現在地と目的地を含む表示範囲を設定する self.showUserAndDestinationOnMap() }) } // 地図の表示範囲を計算 func showUserAndDestinationOnMap() { // 現在地と目的地を含む矩形を計算 var maxLat:Double = fmax(userLocation.latitude, destLocation.latitude) var maxLon:Double = fmax(userLocation.longitude, destLocation.longitude) var minLat:Double = fmin(userLocation.latitude, destLocation.latitude) var minLon:Double = fmin(userLocation.longitude, destLocation.longitude) // 地図表示するときの緯度、経度の幅を計算 var mapMargin:Double = 1.5; // 経路が入る幅(1.0)+余白(0.5) var leastCoordSpan:Double = 0.005; // 拡大表示したときの最大値 var span_x:Double = fmax(leastCoordSpan, fabs(maxLat - minLat) * mapMargin); var span_y:Double = fmax(leastCoordSpan, fabs(maxLon - minLon) * mapMargin); var span:MKCoordinateSpan = MKCoordinateSpanMake(span_x, span_y); // 現在地を目的地の中心を計算 var center:CLLocationCoordinate2D = CLLocationCoordinate2DMake((maxLat + minLat) / 2, (maxLon + minLon) / 2); var region:MKCoordinateRegion = MKCoordinateRegionMake(center, span); mapView.setRegion(mapView.regionThatFits(region), animated:true); } // 経路を描画するときの色や線の太さを指定 func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! { if overlay is MKPolyline { var polylineRenderer = MKPolylineRenderer(overlay: overlay) polylineRenderer.strokeColor = UIColor.blueColor() polylineRenderer.lineWidth = 5 return polylineRenderer } return nil } }
IIJmioに替えてから1ヶ月の所感
1ヶ月の使用状況
データ通信量:1.5GB
音声通話:30分(IIJmioの電話料金は高いのでG-CALLを使用)
使用料金:IIJmioの2GBプランが1600円、通話料が500円くらいで、合計は税込み2300円ほど。
使用感
電波のつかみ具合
DoCoMoの電波を使っているせいか、繋がらないと思うことはそんなにない。
データ通信速度
通信速度は東京都豊島区や新宿区でダウンロードが8Mbps〜26Mbps、
アップロードが3Mbps〜9Mbps。
ダウンロードでは大体15Mbps程度は出るから結構速い!
電話
G-CALLを使って電話をかけているせいか、相手の電話が鳴るまで少し(2秒くらい)時間がかかる
音質はDoCoMoの時と変わらないと思う。
データ通信の使用感
IIJmioでは、速度制限がない高速通信と最大200kbpsの低速通信の2種類があり、
高速通信で使えるデータ容量は契約しているプランのデータ容量になる。
高速/低速の切り替えはIIJmioが出しているアプリで随時切り替え可能で
低速通信ならデータ通信の残容量が減らないので、うまく使えば通信量を節約できる。
低速モードでもそれほどストレスが無いアプリ
・Facebookアプリ
どうやっているか分からないけど、結構ストレスなし。
・LINE
文字だけなら問題なし。画像や動画がある場合は遅くなるけど。
・メール受信
Gmailを使っているけど高速通信でも少し遅い。低速通信だともう少し遅いがそんなに気にならない。
HTMLメールで画像が多いとやっぱり遅い。
・Radiko
普通に使える。
高速通信じゃないとつらいアプリ
・Webブラウズ
文字情報メインだと問題無いが、画像がたくさんあるページが多いので、高速モードがおすすめ
・マップアプリ
高速モードでないと読み込みが遅すぎて実用的じゃない
AWSでRedmineをセットアップ時の記録
■AWSセットアップ
使ったAMI
Amazon Linux AMI 2014.03.1
インスタンスのセットアップ中にConfigure Security GroupでHTTPを追加
■MySQLセットアップ
# yum install mysql mysql-server mysql-devel
[mysqld]セクションに以下を追加
/etc/my.cnf
character-set-server=utf8
skip-character-set-client-handshake
default-storage-engine=innodb
collation-server=utf8_general_ci
innodb_file_format=Barracuda
innodb_file_per_table=1
MySQLを起動
$ sudo service mysqld start
ユーザ作成、DB作成
# mysql -uroot
mysql> CREATE USER 'user'@'localhost' IDENTIFIED BY '********';
mysql> create database dbname;
mysql> GRANT ALL PRIVILEGES ON dbname.* TO user@localhost ;
■モジュールインストール
# yum install mysql-devel
# yum install ImageMagick ImageMagick-devel -y
# yum install httpd httpd-devel -y
# gem install bundler
■Redmine セットアップ
# cd /home/
# mkdir redmine
# cd redmine/
# wget http://www.redmine.org/releases/redmine-2.5.1.tar.gz
# tar xvzf redmine-2.5.1.tar.gz
# cd redmine-2.5.1
$ bundl install
nokogiriでエラーが出たので以下を実行
$ sudo yum install gcc*
$ sudo yum install -y gcc ruby-devel libxml2 libxml2-devel libxslt libxslt-devel
※この2行は必要ないかも。。。
# bundle config build.nokogiri --use-system-libraries
$ bundle install
$ rake generate_session_store
- > Note: The rake task generate_session_store has been deprecated, please use the replacement version generate_secret_token
古いコマンドだよとのことなので、エラーメッセージに従って以下のコマンドを実行。
$ rake generate_secret_token
$ rake db:migrate RAILS_ENV=production
$ rake redmine:load_default_data RAILS_ENV=production
■Redmineの設定
# vim [redmine_root]/config/email.yml
[redmine_root]/config/email.yml
production:
delivery_method: :async_smtp
smtp_settings:
address: localhost
port: 25
domain: domainname.com
# vim [redmine_root]/config/database.yml
[redmine_root]/config/database.yml
production:
adapter: mysql2
database: redmine
host: localhost
username: user
password: "********"
encoding: utf8
■Passengerインストール
# gem install passenger --no-rdoc --no-ri
# yum install curl-devel
passenger-install-apache2-moduleを実行したら警告が出たので、事前に以下のコマンドを実行しておく。
# sudo dd if=/dev/zero of=/swap bs=1M count=1024
# sudo mkswap /swap
# sudo swapon /swap
# passenger-install-apache2-module
最後に表示される以下の情報をコピーしておく。
LoadModule passenger_module /usr/local/share/ruby/gems/2.0/gems/passenger-4.0.45/buildout/apache2/mod_passenger.so
PassengerRoot /usr/local/share/ruby/gems/2.0/gems/passenger-4.0.45
PassengerDefaultRuby /usr/bin/ruby2.0
ServerName www.yourhost.com
# !!! Be sure to point DocumentRoot to 'public'!
DocumentRoot /somewhere/public
# This relaxes Apache security settings.
AllowOverride all
# MultiViews must be turned off.
Options -MultiViews
# Uncomment this if you're on Apache >= 2.4:
#Require all granted
Passengerの設定をhttpd.confに追加
# vim /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf
LoadModule passenger_module /usr/local/share/ruby/gems/2.0/gems/passenger-4.0.45/buildout/apache2/mod_passenger.so
PassengerRoot /usr/local/share/ruby/gems/2.0/gems/passenger-4.0.45
PassengerDefaultRuby /usr/bin/ruby2.0
Passenger.confの設定
Redmineを任意のフォルダで動作させるためにはRackBaseURIの指定が必要
# vim /etc/httpd/conf.d/passenger.conf
/etc/httpd/conf.d/passenger.conf
# LoadModule passenger_module /usr/local/share/ruby/gems/2.0/gems/passenger-4.0.45/buildout/apache2/mod_passenger.so
PassengerRoot /usr/local/share/ruby/gems/2.0/gems/passenger-4.0.45
PassengerDefaultRuby /usr/bin/ruby2.0
PassengerMaxPoolSize 20
PassengerMaxInstancesPerApp 4
PassengerPoolIdleTime 3600
PassengerHighPerformance on
PassengerStatThrottleRate 10
PassengerSpawnMethod smart
RailsAppSpawnerIdleTime 86400
PassengerMaxPreloaderIdleTime 0
PassengerResolveSymlinksInDocumentRoot on
RackBaseURI /redmine
■redmineに【ドメイン名/redmine】でアクセスするため、シンボリックリンク作成
シンボリックリンク作成
# ln -s /home/redmine/redmine-2.5.1/public/ /var/www/html/redmine
apacheに権限付与
# cd /home/redmine
# chown -R apache:apache redmine-2.5.1