Quantcast
Channel: アシアルブログ
Viewing all 298 articles
Browse latest View live

Onsen UIをカスタマイズするOnsen Theme Rollerの紹介

$
0
0

Onsen UIを使えばハイブリッドアプリやスマートフォン向けWebサイトにおいてリッチで高速な描画ができるUIを手に入れることができます。しかし多機能かつ多彩な表現を可能にすればするほど、ちょっとしたカスタマイズもしづらくなってしまいます。



それを防ぐのに使えるのがテーマ機能です。色をがらっと変えることで印象が大きく変わります。Onsen UIではOnsen Theme Rollerを用意しており、それを使うことで各UIコンポーネントのカスタマイズを簡単に行えるようになっています。今回はOnsen Theme Rollerの使い方を紹介します。



Onsen Theme Rollerの使い方



まずOnsen Theme Rollerを開きます。




Onsen Theme Rollerのトップページ

Onsen Theme Rollerのトップページ



見て分かる通り、各UIコンポーネントが並んでいます。スイッチやレンジ、ナビゲーションバーといったUIコンポーネントに加えて、リストに入ったスイッチ、各種リスト、ポップオーバー、アラートなど60種類以上のコンポーネントが登録されています。



これらで例えばスイッチのデザインを変えようと思った場合、横にあるチェックボックスをつけます。




チェックボックスをチェックする

チェックボックスをチェックする



そうすると左側にあるカラーリストでスイッチに関係する部分(Border ColorとSwitch Highlight Color)だけが明るくなり、他はグレーアウトします。




チェックボックスをオンにした状態

チェックボックスをオンにした状態



これでどの設定が、どのUIコンポーネントに関わってくるのかが分かりやすくなります。思いもしないところが変更されてしまったり、逆にどこを変更すれば反映されるのか分からないといった事態にならなくなるでしょう。



カラースキーマを選ぶ



自分で一からカラー設定を変更していく他、予め作成されているカラースキーマからまとめてカラーリングを変更することもできます。




カラースキーマ

カラースキーマ



例えばこの中から好きなものを選び、クリックします。そうすると一気に全体のカラーリングが変更されたのが分かるはずです。




紫のカラースキーマ適用

紫のカラースキーマ適用



全体の色合いをここから選択し、その後細かな調整を行っていくことも可能です。



パターンでチェック



そして個々の細かなUIコンポーネントだけでなく、実際にアプリ風に使ってみた時の見え方を確認できるのがパターンです。




パターンを選択

パターンを選択



パターンのタブに切り替えると、ショップ詳細やプロフィール、タイムライン、スケジュールなど様々なアプリで良くある画面をOnsen UI(かつ設定しているテーマ)で表現したらどう見えるのかをチェックできます。こうやってアプリ風に見せることでこれから開発するアプリのイメージがわきやすくなりますし、Onsen UIの表現力の高さもお分かりいただけるかと思います。



コンポーネントを探す



そしてさらに右上にあるFind Componentをクリックすると、表示部分におけるUIコンポーネント名を知ることができます。




Find Componentをクリック

Find Componentをクリック




コンポーネント名を知る

コンポーネント名を知る



さらにそのコンポーネントをクリックすると、該当コンポーネントがHTML/CSSにどのように記述すれば良いのかも確認ができるようになっています。




コンポーネントのHTML/CSSを確認

コンポーネントのHTML/CSSを確認



作成が終わったらダウンロード



テーマの作成が終わったら Download Theme ボタンをクリックしてZipファイルをダウンロードします。解凍すると次のようなファイル構成になっています。




ダウンロードされたファイル一覧

ダウンロードされたファイル一覧



ファイルはOnsen UIのスタイルシート(ミニファイ版含む)とStylus用のファイル一式になっています。ここからさらに細かくカスタマイズしても良いですし、そのままプロジェクトに取り込んでも良いでしょう。ファイルのライセンスはApache Licenseとなっています。






いかがでしょうか。背景色をグレーベースにしたり、薄いピンクなどにするだけで印象は大きく変わってきます。フラットUIは情報構造設計を優先するのでデザイン上の差がなかなか出しづらいかも知れません。しかしカラーリングを変えるだけで随分違って見えるものでしょう。



Onsen Theme Rollerはビジュアル的に確認しながら作業が進められます。様々なアプリUIのパターンを見ながら最適なテーマカラーを作成してください。



Onsen CSS Components


社内勉強会での「チームで作る!イケてるデザイン」の資料を公開しました

$
0
0

アシアルの社内勉強会で発表した資料を公開します。今回の社内勉強会では、「イケてるデザイン」をテーマに勉強会を開催しました。自分はその中でも「どうやってチームでイケてるデザインを作るのだろうか?」ということをテーマにして話をしました。

Onsen UIとjQueryを組み合わせてスマートフォンWebサイト/ハイブリッドアプリを作ろう

$
0
0

Onsen UIはHTML5モバイルアプリを高速化し、かつネイティブアプリのようなUIを提供するフレームワークになっています。技術的にはカスタムエレメントとAngularJSを使って作られていますが、その利用に際してAngularJSの習得が必須という訳ではありません。現在のOnsen UIはAngularJS以外の様々なJavaScriptフレームワークと組み合わせて使えるようになっています。



今回はWeb開発で最も使われているであろうjQueryを使ってOnsen UIの操作を説明したいと思います。



ベースになるHTML



まずはベースのHTMLファイルの内容です。



  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4.   <meta charset="utf-8">
  5.   <meta name="apple-mobile-web-app-capable" content="yes">
  6.   <meta name="mobile-web-app-capable" content="yes">
  7.   <title>My App</title>  
  8.   <link rel="stylesheet" href="lib/onsen/css/onsenui.css">  
  9.   <link rel="stylesheet" href="styles/app.css"/>
  10.   <link rel="stylesheet" href="styles/onsen-css-components-blue-basic-theme.css">  
  11.   <script src="lib/onsen/js/angular/angular.js"></script>    
  12.   <script src="lib/onsen/js/onsenui.js"></script>    
  13.   <script src="lib/jquery/jquery-2.1.3.min.js"></script>    
  14.   <script src="js/app.js"></script>  
  15. </head>
  16.  
  17. <body>
  18.   <ons-navigator title="Navigator" var="myNavigator">
  19.     <ons-page>
  20.       <ons-toolbar>
  21.   <div class="center">Onsen + jQuery デモ</div>
  22.       </ons-toolbar>
  23.       <p>
  24.   <div style="text-align: center">
  25.     <p><ons-button id="next_page">次のページ</ons-button></p>
  26.     <p><div id="my-content">書き換えられるコンテンツ</div></p>
  27.   </div>
  28.       </p>
  29.     </ons-page>
  30.   </ons-navigator>
  31. </body>  
  32. </html>

HTMLのレベルではOnsen UIのカスタムエレメントをそのまま書きます。また、カスタムエレメントを通常のHTMLに変換するためにAngularJSとOnsen UIのJavaScriptは必須です。



通常のHTMLに展開する



カスタムエレメントを描画するのはまだ殆どのブラウザが対応していません。そこでOnsen UIのコンパイル機能を使います。



  1. ons.bootstrap();

この bootstrap メソッドによって、以下のように描画されます。




初期表示

初期表示



見ての通り、



  1. <ons-button id="next_page">次のページ</ons-button>

はボタンの表示になっていますが、



  1. <div id="my-content">書き換えられるコンテンツ</div>

は変わっていません。動的にUIを書き換える場合は次のようにします。



  1. ons.ready(function() {
  2.   var content = $("#my-content");
  3.   content.html("<ons-button>追加されたボタン</ons-button>");
  4.   ons.compile(content[0]);
  5. });

jQueryを使って #my-content の内容を Onsen UIのカスタムエレメントに書き換えています。それを ons.compileに渡すことによってHTMLエレメントに変換しています。jQueryオブジェクトからDOMに変換する際には [0] を使います。$(function() {}) ではなく、 ons.ready を使うのが注意点です。




コンテンツを動的に書き換えた例

コンテンツを動的に書き換えた例



ボタンを押した時のイベント



ボタンを押した時のイベントは通常のjQueryとして記述ができます。



  1. $("ons-button#next_page").on('click', function(e) {
  2.   // ここに処理を書きます
  3. });

ナビゲーション操作



ページを移動するスタック管理やナビゲーション機能を提供するコンポーネントに ons-navigator があります。こちらを使う場合には予め次のように var要素を書いておきます。



  1. <ons-navigator title="Navigator" var="myNavigator">
  2.   :
  3. </ons-navigator>

こうすることで window.myNavigator にこのナビゲーションコンポーネントが定義されますので myNavigator としてアクセスが可能になります。



ボタンを押した時に画面遷移する



前述のクリックイベントとナビゲーションコンポーネントを組み合わせるとページ移動ができるようになります。



  1. $("ons-button#next_page").on('click', function(e) {
  2.   myNavigator.pushPage('page2.html');
  3. });

pushPageはページ移動になります。page2.htmlは元々のHTMLファイルと同じ階層にあるpage2.htmlを読み込みます。例えば次のような記述です。



  1. <ons-page>
  2.   <ons-toolbar>
  3.     <div class="center">Onsen + jQuery デモ</div>
  4.     <div class="left">
  5.       <ons-back-button onclick="myNavigator.popPage();">Back</ons-back-button>
  6.     </div>
  7.   </ons-toolbar>
  8.   <div id="my-content">
  9.   </div>
  10. </ons-page>

こちらのようにonでイベントハンドリングするだけでなく、onclickで定義も可能です。popPageはページスタックから最前面のページが削除され、1つ前のページに戻る処理です。page2.htmlで記述している内容はコンパイル済みで、HTMLエレメントがそのまま表示されます。



表示する際の動的書き換え



画面を移動する際にコンテンツを動的に書き換えたいというニーズは多いと思います。この場合はナビゲーターのイベントハンドリングで行います。



  1. myNavigator.on('postpush', function(e) {
  2.   $(e.enterPage.element).find("#my-content").html('<p><div class="center" style="text-align:center">コンテンツ書き換え</div></p>');
  3. });

postpushはpushが完了した時に呼ばれるイベントになります。 $(e.enterPage.element) にページの内容が入っていますので、そこから書き換えたい要素を検索して変更できるようになっています。



全体の動きは次のようになります。




動作デモ

動作デモ






このようにOnsen UIはAngularJSからだけでなく、jQuery(その他のJavaScriptフレームワークも)から利用が可能です。基本的な使い方さえ覚えてしまえば、スマートフォンアプリはもちろん、スマートフォンWebサイトに求められるアニメーションやUI/UXを簡単に手に入れることができます。これまでのナレッジを使って開発ができるようになるでしょう。



ぜひOnsen UIを使ってスマートフォンWebサイト/アプリを開発してください。



HTML5モバイルアプリをもっと速く、もっと美しく | Onsen UI

Cordova勉強会 #4 に参加してきました

$
0
0

Cordova/PhoneGap、Monacaなどを使っている方向けのユーザ会、Cordovaユーザ会 #4が2月13日(金)、日本マイクロソフト セミナールームにて開催されました。レポートを書くまでが勉強会、ということで個人的な感想を含めてレポートを書きたいと思います。




Andre氏

Andre氏



まず最初はAdobe社のAndre Charland氏の発表でした。彼は元々PhoneGapを開発していたNitobi社の創設者で、Adobe社に買収された後は米PhoneGapチームマネージャーを勤めています。つまりPhoneGapのすべてを知っている人と言えます。



CordovaとPhoneGapの違いは度々話題にあがるのですが、こちらの資料が一番分かりやすいと思います。




Cordova/PhoneGap/PhoneGap Enterpriseの違い

Cordova/PhoneGap/PhoneGap Enterpriseの違い



CordovaはApache財団に寄贈されたオープンソース・ソフトウェアです。MicrosoftやIBM、Google、Salesforceなど多くの企業が開発に参加しています。そのCordovaに対してAdobe社が便利なツールを追加したのがPhoneGapになります。ここまでは無料で使える範囲になります。



そしてAdobe社のビジネスモデルとしてPhoneGapに解析機能であったり、コンテンツ管理機能を追加したのがPhoneGap Enterpriseであり、こちらは有償のサービスになっています。



無料のPhoneGapツールについては主な機能は以下の通りになります。



  • Build
  • CLI
  • Desktop App
  • Develper App


PhoneGap Buildはクラウド上でPhoneGapアプリをビルドできるサービスとして知られています。



Cordovaで最も気にされるのがパフォーマンスだと思うのですが、最新のOS(iOS8、Android 5.0)では十分にパフォーマンスが上がってきているとのこと。この辺りは実際に開発されている方にしても納得できるかと思います。



そしてそもそもなぜPhoneGapを選択するのかという話なのですが、一番大きいのはシングルコードでマルチプラットフォームに提供できるのが大きいとのことです。iOS/Android/Windows Phoneなど多くのプラットフォームに対して単一のコードでアプリを提供できます。さらにHTML5/JavaScript/CSSで構築されていますのでWebサイトにも使えます。



パフォーマンスについては前述の通り、OSやハードウェアが高性能化しているのに加えてUIフレームワーク(Onsen UIやIonicなど)を使うことで高パフォーマンスなUIを実現できるようになっています。



Webアプリとの違いで言えばデバイスのAPIにアクセスできる点が大きいでしょう。HTML5でも幾つかのAPIが使えますが、プッシュ通知やBluetooth、バックグラウンド処理などはネイティブアプリならではです。



また、あまり知られていませんがコンテンツをアプリストア(App StoreやGoogle Playなど)を通さずに差し替えることもできます。これはA/Bテストなどで活躍する機能になるでしょう。その他、ネイティブアプリの中にCordova/PhoneGapを内包するという仕組みも可能です。これによりハイパフォーマンスが求められる部分はネイティブで、頻繁な変更が求められるところはWebViewで実装と分けることもできます。すべてCordova/PhoneGapまたはゼロという選択肢だけでないのは良さそうです。



Cordova/PhoneGapとネイティブを組み合わせたアプリは数多くあります。Instagram/Evernote/Amazon/Yelpなどでも使われているそうです。また、Basecamp(Ruby on Rails開発元)もかなりの部分がHTML5で実装されているとのことです。



気になる数字が色々と発表されました。




PhoneGapから見る数値

PhoneGapから見る数値



  • PhoneGap CLIのダウンロード回数 15万回
  • PhoneGap Buildのユーザ数 65万ユーザ
  • PhoneGap Buildを使ったアプリ 45万アプリ
  • PhoneGap Developer Appのダウンロード回数 8万回
  • PhoneGap Desktop Appのダウンロード回数 2.3万回
  • CordovaはNPMのダウンロードトップ


最後にPhoneGap Enterpriseについて。こちらは主にマーケティング担当者向けのサービスになるようです。ダッシュボードでステータスを確認したり、その使われ方を可視化しています。さらにアプリのアップデートもPhoneGap Enterpriseを通して簡単にできるようになっています。




PhoneGap Enterpriseの画面

PhoneGap Enterpriseの画面



最後に以下のような質問があがっていました。



Q. Adobeに移ったということで、AppleやAndroidのWebViewに対する発言力は増したのかどうか



A. Cordovaはオープンソースでアリ、GoogleやMicrosoftなどが加わったことで影響は増している。また、AppleやAndroidに対する発言力も増しているといえる。



Q. 他のプラットフォーム(Xboxなど)への対応はあるのか

A. PhoneGap自体はモバイル対応がメインで他は今のところない。将来的には分からないが対応を考えたい。






続いてMicosoft社の物江さんによりVisual Studioを使用したCordova開発という発表です。




Visual Studioを使用したCordova開発

Visual Studioを使用したCordova開発



Visual StudioではHTML5/JavaScriptでアプリを開発できますが、ストアアプリ、Windows Phone、XBOXはHTML5/JavaScriptからネイティブコードに変換される仕組みになっています。そしてCordova開発はVisual Studio Tools for Apache Cordovaというアプリをインストールすると可能になります。こちらはVisual Studio 2015から今後デフォルトで入ってくるそうです。




Visual Studio 2013とHTML5アプリ

Visual Studio 2013とHTML5アプリ



現状はエミュレータはApache Rippleなのですが、2015からはHyperVベースになるのでより本物に近い形でデバッグできるようになります。Visual Studio Tools for Apache CordovaはVisual Studio 2013 × Windows 8.1(Update 3からはWindows 7も)で動かすようです。




Visual Studio Tools for Apache Cordova

Visual Studio Tools for Apache Cordova



開発できるターゲットはAndroid 2.33または4以上、iOSは6以上が開発対象になります。ただしiOSやAndroid 4.4未満ではデバッガーが動きません。Mac OSXを経由してiOS対応もできるようですが、ブレークポイントが使えなかったりするのでAndroid向けと考えるのが良さそうです。



Visual Studio Tools for Apache Cordovaを使う大きな利点として、開発環境を整えるのが簡単であるとのことです。Javaランタイムを含め、Android SDKをインストールしたり、Cordoavaの環境を整えたりするのがVisual Studioのアドインインストールだけで完結します。これは確かに便利そうです。また、HTML5関連の開発支援機能が使えるようになります。




Visual Studio Tools for Apache Cordovaを使うメリット

Visual Studio Tools for Apache Cordovaを使うメリット



後は実際にVisual Studioを使って、どうやって開発を行っていくのかをデモされました。強力な入力補完機能であったり、省略した入力からHTMLタグを展開したりと記述量を抑えた開発ができるようになります。CordoavaプラグインのインストールもVisual Studioから選択して行えるようになっています。




プラグインのインストール

プラグインのインストール



最後に以下のような質問があがっていました。



Q. Cordovaのプラグイン開発はできますか?



A. Androidはできます。iOS向けはできません。



Q. ExpressでCordova開発はできますか?



A. プラグインのインストールができないのでCommunity Editionを使ってください。



Q. Visual Studio以外の環境に移せますか?



A. ファイル構成は同じなのでフォルダを移動するだけでいけます。



Q. TypeScriptで使えますか?またはTypeScriptの方が効率的ということはありますか?



A. 使えます。実際のところ好みではないでしょうか。



Q. Cordovaのバージョンアップした場合の対応



A. 現状は入れ直しになります。将来的にはアップデートに対応予定。






最後に当社代表取締役の田中によるCordovaをWindowsで使うというセッションです。




CordovaをWindowsで使う

CordovaをWindowsで使う



先ほどのVisual Studioで使う場合でも分かりますが、WindowsではiOS向けの開発においてかなり難があると言えます。それをどうにかして解決しようというセッションです。



アプリ開発には以下のようなプロセスがあると言えます。



  • 開発/デバッグ
  • ビルド
  • 実機転送
  • リリース


これらのプロセスに対してWindowsでのAndroid開発は問題なく行えます。対してiOSでは困難です。この各プロセスに対する打開策は次のようになります。



開発/デバッグ



まだ若干難はあるものの、GapDebugを使うとiOSアプリのデバッグを行えるようになります。




GapDebug

GapDebug



ビルド



ビルドはMac OSX + Xcodeが必須とのことで残念です。




ビルドについて

ビルドについて



代替手段としてはPhoneGap BuildやMonacaを使うといった手段があります。




ビルドの代替手段

ビルドの代替手段



リリース



リリースもまたMac OSX + Xcodeが必須とのことで残念です。



代替手段として代行サービスがあるのですが、iTunes Connectのメールアドレス/パスワードを教える必要があります。セキュリティ上のリスクが大きいと言わざるを得ない状態です。




リリースの代替手段

リリースの代替手段



まとめとしてはiOSアプリの開発はWindowsだと色々と大変なことがつきまとうようです。ただしApp Storeへの申請を除けば、基本的にMacと同じことはできるようになっています。



最後に以下のような質問があがっていました。



Q. Windows + Androidで動けばiOSでも大丈夫?



A. 動くはずですが、社内的には色々愚痴を聞きます。






当日の様子は以下の動画で確認できます。





第4回Apache Cordova勉強会 - YouTube



WindowsでiOS向けのCordovaアプリ開発は茨の道に見えますが、例えばMonacaシミュレータを使えば開発、デバッグ、ビルドまでWindows上だけで完結できます。GapDebugのような手段もありますので、今後Visual Studioの高機能化に期待といったところでしょうか。



Cordova勉強会は今後も行われますので参加しましたらまたレポート記事を書きたいと思います。

Monaca公式ガイドブック『クラウドでできるHTML5ハイブリッドアプリ開発』が出版されました

$
0
0
こんにちは、塚田です。

昨日、Monaca公式ガイド『クラウドでできるHTML5アプリ開発』が翔泳社より出版されました。

これまでも皆さんからMonaca関連の公式本のご要望を多数頂いていたのですが、著者の永井勝則氏のご協力のもと、ようやくお届けできることになりました。



本書ではMonacaを使って、iOS/Android両プラットフォームで動作するハイブリッドアプリを作る方法を解説しております。

いくつかのサンプルアプリを作りながら、HTML5ハイブリッドアプリ開発の基本テクニックや、Cordovaプラグインの使い方、またOnsen UI / AngularJSを用いたアプリのUI構築方法などについて学ぶ事が出来ます。

iOS/Android両対応のアプリを開発したい、あるいはHTML5ハイブリッド開発に興味があるものの敷居が高そうと感じていた方など、Web技術でハイブリッドアプリ開発をしたいと考えている方すべてにおすすめの一冊なので、是非お読みいただければと思います。

目次

 第1章 HTML5ハイブリッドアプリ開発とMonaca
 第2章 Monacaの使い方
 第3章 はじめてのMonacaアプリ
 第4章 CSSアニメーションと描画機能
 第5章 Onsen UIの基本
 第6章 イベントとインタラクション
 第7章 画面のパターンと構成
 第8章 Cordovaとデバイス機能
 第9章 AngularJS入門
 第10章 本格的なアプリ開発

また、本書の出版を記念しまして、全国7都市でアプリ開発セミナーを開催いたします。皆様のご参加をお待ちしております。

Laravel5でシンプルなCRUDアプリを開発する

$
0
0
こんにちは〜たきゃはしです〜最近もホントにとにかくビール最高!って感じです!
今回はついにリリースされたLaravel5(以降はL5と略記する)を早速使ってみました!

◯ この記事の概要



L5の基本機能を扱いつつシンプルなブログアプリを作ってみようと思います。

こんな感じになります

この記事の目的はブログアプリの開発を通してL5でCRUDを作れるようになることです。構成をなるべくシンプルにしたかったこともあり沢山の機能は取り扱ったわけではありませんが「PHPやMySQLは分かるけどFWはよくわからないな〜」とか「Laravel5 気になってるんだよな〜」という人には特におすすめですよ!

さっそくインストールからはじめたいと思います。

◯ インストール



  1. $ composer create-project laravel/laravel l5blog --prefer-dist

l5blog というディレクトリを作成しインストールします
以降に登場するファイルパスはこの l5blog を基準とします。

◯ 初期設定



・ storageのパーミッションの変更



  1. $ chmod -R 777 storage

・ データベースの設定



・ .env
  1. DB_HOST=localhost
  2. DB_DATABASE=l5blog
  3. DB_USERNAME=root
  4. DB_PASSWORD=secret

データベースのドライバーはデフォルトで mysql です。
他のドライバーを使用したい場合は config/database.php で設定してください。

◯ データベースの作成



  1. mysql> CREATE DATABASE `l5blog`;

◯ マイグレーション



ここでいうマイグレーションとは、データベースのテーブルやカラムの追加や変更の定義を管理することを指します。

・ マイグレーションファイルの生成



  1. $ php artisan make:migration create_articles_table
  2. Created Migration: 2015_02_17_114821_create_articles_table

・ テーブル定義の作成



・ database/migrations/2015_02_17_114821_create_articles_table.php
  1. <?php
  2.   
  3.   use Illuminate\Database\Schema\Blueprint;
  4.   use Illuminate\Database\Migrations\Migration;
  5.   
  6.   class CreateArticlesTable extends Migration
  7.   {
  8.   
  9.       /**
  10.        * Run the migrations.
  11.        *
  12.        * @return void
  13.        */
  14.       public function up()
  15.       {
  16.           Schema::create('articles', function (Blueprint $table) {
  17.               $table->increments('id');
  18.               $table->string('title');
  19.               $table->text('body');
  20.               $table->timestamps();
  21.           });
  22.       }
  23.   
  24.       /**
  25.        * Reverse the migrations.
  26.        *
  27.        * @return void
  28.        */
  29.       public function down()
  30.       {
  31.           Schema::drop('articles');
  32.       }
  33.   
  34.   }

・ マイグレーションの実行



  1. $ php artisan migrate
  2. Migration table created successfully.
  3. Migrated: 2014_10_12_000000_create_users_table
  4. Migrated: 2014_10_12_100000_create_password_resets_table
  5. Migrated: 2015_02_17_114821_create_articles_table

これでデータベースに articles というテーブルが追加されました。
同時にいくつか追加されたテーブルがありますが今回使用しないため気にする必要はありません。

◯ シーダー(初期データ)



シーダーを生成するコマンドは標準でないので通常通りファイルを作成します。

・ 記事シーダーの作成



・ database/seeds/ArticlesTableSeeder.php
  1. <?php
  2.   
  3.   use Illuminate\Database\Seeder;
  4.   
  5.   class ArticlesTableSeeder extends Seeder
  6.   {
  7.   
  8.       public function run()
  9.       {
  10.           DB::table('articles')->truncate();
  11.   
  12.           DB::table('articles')->insert([
  13.               [
  14.                   'title'      => 'Laozi',
  15.                   'body'       => 'When there is no desire, all things are at peace.',
  16.                   'created_at' => '2015-01-31 23:59:59',
  17.                   'updated_at' => '2015-01-31 23:59:59',
  18.               ],
  19.               [
  20.                   'title'      => 'Leonardo da Vinci',
  21.                   'body'       => 'Simplicity is the ultimate sophistication.',
  22.                   'created_at' => '2015-02-01 00:00:00',
  23.                   'updated_at' => '2015-02-01 00:00:00',
  24.               ],
  25.               [
  26.                   'title'      => 'Cedric Bledsoe',
  27.                   'body'       => 'Simplicity is the essence of happiness.',
  28.                   'created_at' => '2015-02-01 00:00:01',
  29.                   'updated_at' => '2015-02-01 00:00:01',
  30.               ],
  31.           ]);
  32.   
  33.       }
  34.   
  35.   }

記事シーダーを作成したら下記のコマンドを実行してください。

  1. $ composer dump-autoload
  2. //もしくは
  3. $ php artisan optimize
※ 8egsさん、ご報告ありがとうございます!

・ database/seeds/DatabaseSeeder.php
  1. <?php
  2.   
  3.   use Illuminate\Database\Seeder;
  4.   use Illuminate\Database\Eloquent\Model;
  5.   
  6.   class DatabaseSeeder extends Seeder
  7.   {
  8.   
  9.       /**
  10.        * Run the database seeds.
  11.        *
  12.        * @return void
  13.        */
  14.       public function run()
  15.       {
  16.           Model::unguard();
  17.   
  18.           $this->call('ArticlesTableSeeder');
  19.       }
  20.   
  21.   }

・ シーダーの実行



  1. $ php artisan db:seed
  2. Seeded: ArticlesTableSeeder

デフォルトでDatabaseSeederが実行されるので記事データがインサートされます。
2回目以降であれば下記コマンドが便利です。

  1. $ php artisan migrate:refresh --seed
  2. Rolled back: 2015_02_17_114821_create_articles_table
  3. Rolled back: 2014_10_12_100000_create_password_resets_table
  4. Rolled back: 2014_10_12_000000_create_users_table
  5. Nothing to rollback.
  6. Migrated: 2014_10_12_000000_create_users_table
  7. Migrated: 2014_10_12_100000_create_password_resets_table
  8. Migrated: 2015_02_17_114821_create_articles_table
  9. Seeded: ArticlesTableSeeder

いよいよブログアプリの作成に進みます。

◯ 記事モデルの作成



はじめはモデルを作りましょう。

  1. $ php artisan make:model Article
  2. Model created successfully.

さっそく生成されたArticleモデルを確認してみます。

・ app/Article.php
  1. <?php namespace App;
  2.   
  3.   use Illuminate\Database\Eloquent\Model;
  4.   
  5.   class Article extends Model
  6.   {
  7.   
  8.       //
  9.   
  10.   }

モデルはappディレクトリ直下に生成されます。モデルがアプリの中枢を担うことになりますので妥当かもしれませんね。もちろん新たにModelディレクトリを作成してそこに配置してもLaravelでは何も問題ありません。

ひな形へ肉付けしていきます。

・ app/Article.php
  1. <?php namespace App;
  2.   
  3.   use Illuminate\Database\Eloquent\Model;
  4.   
  5.   class Article extends Model
  6.   {
  7.   
  8.       /**
  9.        * The table associated with the model.
  10.        *
  11.        * @var string
  12.        */
  13.       protected $table = 'articles';
  14.   
  15.       /**
  16.        * The attributes that are mass assignable.
  17.        *
  18.        * @var array
  19.        */
  20.       protected $fillable = ['title', 'body'];
  21.   
  22.   }

対応するテーブル名や保存が可能なフィールドを定義しました。(テーブル名はDRYに従っていれば実質不要なのですが明示的にするため記載しました。)
もし時間があるならばAricleモデルが継承している Illuminate\Database\Eloquent\Model を確認してみてください。他にどのようなプロパティが設定できるのか知っておくことは大切です。例えば今回定義しなかった「$perPage」はページネーションで1ページに表示する件数を指定することができます。

◯ コントローラー



コントローラーのひな形を生成します。

  1. $ php artisan make:controller ArticlesController
  2. Controller created successfully.

生成されたファイルはリソースコントローラーを前提とするアクションがずらっと定義されています。ですが今回は暗黙的コントローラーとして実装していきたいので一旦すべてのメソッドを削除してください。(暗黙的コントローラーについては後ほど簡単に説明します)

・ app/Http/Controllers/ArticlesController.php
  1. <?php namespace App\Http\Controllers;
  2.   
  3.   use App\Http\Requests;
  4.   use App\Http\Controllers\Controller;
  5.   
  6.   use Illuminate\Http\Request;
  7.   
  8.   class ArticlesController extends Controller
  9.   {
  10.   }

すっきりしたところで 一覧、詳細、作成、編集、削除 のアクションをそれぞれ定義していきます。

  1. <?php namespace App\Http\Controllers;
  2.   
  3.   use App\Article;
  4.   use App\Http\Requests;
  5.   use App\Http\Controllers\Controller;
  6.   
  7.   use Illuminate\Http\Request;
  8.   
  9.   class ArticlesController extends Controller
  10.   {
  11.   
  12.      /**
  13.       * @var Article
  14.       */
  15.      protected $article;
  16.   
  17.      /**
  18.       * @param Article $article
  19.       */
  20.      public function __construct(Article $article)
  21.      {
  22.          $this->article = $article;
  23.      }
  24.   
  25.      public function getIndex()
  26.      {
  27.   
  28.      }
  29.   
  30.      public function getShow()
  31.      {
  32.   
  33.      }
  34.   
  35.      public function getCreate()
  36.      {
  37.   
  38.      }
  39.   
  40.      public function postCreate()
  41.      {
  42.   
  43.      }
  44.   
  45.      public function getEdit()
  46.      {
  47.   
  48.      }
  49.   
  50.      public function postEdit()
  51.      {
  52.   
  53.      }
  54.   
  55.      public function postDelete()
  56.      {
  57.   
  58.      }
  59.   
  60.   }

暗黙的コントローラーでは、URIとHTTPメソッドで対応するアクションが決定します。上記ではgetCreate()とpostCreate()では対応するURIは同じになりますが対応するHTTPメソッドが異なります。またPATCHやDELETEといった他のHTTPメソッドにも対応可能ですが今回は割愛します。

◯ ルーティング



作成したコントローラーをルーティングへ追加します。
'/'へのアクセスは記事一覧、'/articles'は暗黙的コントローラーとして定義します。

・ app/Http/routes.php
  1. <?php
  2.   
  3.   Route::get('/', 'ArticlesController@getIndex');
  4.   Route::controller('articles', 'ArticlesController');

ここでコントローラーのネームスペースが指定する必要がないのは、 routes.php が App\Providers\RouteServiceProvider で読み込まれているためです。App\Providers\RouteServiceProviderで 'App\Http\Controllers' をネームスペースとするグループのルーティングだと定義されているおかげです。

◯ 記事の一覧



次に一覧の作成に取り掛かります。インサートした記事をすべて表示させましょう。
すべて記事を取得してビューへ渡すアクションを作成します。

・ 記事一覧アクション



  1. <?php ...
  2.  
  3.     /**
  4.      * 記事の一覧
  5.      *
  6.      * @return \Illuminate\View\View
  7.      */
  8.     public function getIndex()
  9.     {
  10.         $articles = $this->article->all();
  11.  
  12.         return view('articles.index')->with(compact('articles'));
  13.     }

view()の中身はドット繋ぎでディレクトリ構造を表現できます。with()にはビューで使いたいデータを配列で渡してあげればOKです。

次にビューを作成します。テンプレートエンジンはLaravelデファクトのBladeを使用します。
アプリらしくViewExtends、共通のビューと個別のビューを別々に作成します。

・ 共通のビュー



・ resources/views/app.blade.php
  1. <!DOCTYPE html>
  2.   <html lang="ja">
  3.   <head>
  4.       <meta charset="UTF-8">
  5.       <title>L5Blog</title>
  6.       <link href="/css/app.css" rel="stylesheet">
  7.   </head>
  8.   <body>
  9.       <div class="container">
  10.           <div class="row">
  11.               <h1>L5Blog</h1>
  12.               <div class="col-md-12">
  13.                   @yield('content')
  14.               </div>
  15.           </div>
  16.       </div>
  17.   </body>
  18.   </html>

・ 記事一覧のビュー(個別のビュー)



・ resources/views/articles/index.blade.php
  1. @extends('app')
  2.   
  3.   @section('content')
  4.       <h2 class="page-header">記事一覧</h2>
  5.       <table class="table table-striped table-hover">
  6.           <thead>
  7.           <tr>
  8.               <th>タイトル</th>
  9.               <th>本文</th>
  10.               <th>作成日時</th>
  11.               <th>更新日時</th>
  12.           </tr>
  13.           </thead>
  14.           <tbody>
  15.           @foreach($articles as $article)
  16.               <tr>
  17.                    <td>{{{ $article->title }}}</td>
  18.                    <td>{{{ $article->body }}}</td>
  19.                    <td>{{{ $article->created_at }}}</td>
  20.                    <td>{{{ $article->updated_at }}}</td>
  21.               </tr>
  22.           @endforeach
  23.           </tbody>
  24.       </table>
  25.   @endsection

ホストのルート'/'へアクセスしてみてください!一覧が表示されるはずです!

◯ 記事の詳細



次は記事の詳細を表示するページを作成していきます。

・ 記事詳細アクション



  1. <?php ...
  2.  
  3.     /**
  4.      * 記事の詳細
  5.      *
  6.      * @param $id
  7.      * @return \Illuminate\View\View
  8.      */
  9.     public function getShow($id)
  10.     {
  11.         $article = $this->article->find($id);
  12.  
  13.         return view('articles.show', compact('article'));
  14.     }

データはview()の第二引数から渡す方法もあります。

・ 記事詳細のビュー



・ resources/views/articles/show.blade.php
  1. @extends('app')
  2.   
  3.   @section('content')
  4.       <h2 class="page-header">記事詳細</h2>
  5.       <table class="table table-striped">
  6.           <tbody>
  7.           <tr>
  8.               <th>タイトル</th>
  9.               <td>{{{ $article->title }}}</td>
  10.           </tr>
  11.           <tr>
  12.               <th>本文</th>
  13.               <td>{{{ $article->body }}}</td>
  14.           </tr>
  15.           <tr>
  16.               <th>作成日時</th>
  17.               <td>{{{ $article->created_at }}}</td>
  18.           </tr>
  19.           <tr>
  20.               <th>更新日時</th>
  21.               <td>{{{ $article->updated_at }}}</td>
  22.           </tr>
  23.           </tbody>
  24.       </table>
  25.   @endsection

これで 'articles/show/2' へアクセスしてみてください!暗黙的コントローラーにより id:2 の記事の詳細が表示されます!

記事の一覧に詳細ページへのリンクを追加してみましょう。

・ resources/views/articles/index.blade.php
  1. @extends('app')
  2.   
  3.   @section('content')
  4.       <h2 class="page-header">記事一覧</h2>
  5.       <table class="table table-striped table-hover">
  6.           <thead>
  7.           <tr>
  8.               <th>タイトル</th>
  9.               <th>本文</th>
  10.               <th>作成日時</th>
  11.               <th>更新日時</th>
  12.               <th></th>
  13.           </tr>
  14.           </thead>
  15.           <tbody>
  16.           @foreach($articles as $article)
  17.               <tr>
  18.                    <td>{{{ $article->title }}}</td>
  19.                    <td>{{{ $article->body }}}</td>
  20.                    <td>{{{ $article->created_at }}}</td>
  21.                    <td>{{{ $article->updated_at }}}</td>
  22.                    <td><a href="/articles/show/{{{ $article->id }}}" class="btn btn-default btn-xs">詳細</a></td>
  23.               </tr>
  24.           @endforeach
  25.           </tbody>
  26.       </table>
  27.   @endsection

一覧から詳細リンクをクリックすると詳細ページに遷移されるようになりました。
Laravelが初めての方でもなんとなくイメージは掴めてきたでしょうか?

次は投稿処理です。

◯ 記事の投稿



投稿は一覧や詳細と違いPOSTを受け付けます。

- GET /articles/create の場合は getCreate()
- POST /articles/create の場合は postCreate()

上記を理解していればアクションとフォームで何をしなくてはいけないかハッキリしますね。

・ 記事投稿のアクション



  1. <?php ...
  2.  
  3.     /**
  4.      * 記事の投稿
  5.      *
  6.      * @return \Illuminate\View\View
  7.      */
  8.     public function getCreate()
  9.     {
  10.         return view('articles.create');
  11.     }
  12.  
  13.     /**
  14.      * 記事の投稿
  15.      *
  16.      * @param Request $request
  17.      * @return \Illuminate\Http\RedirectResponse
  18.      */
  19.     public function postCreate(Request $request)
  20.     {
  21.         $data = $request->all();
  22.         $this->article->fill($data);
  23.         $this->article->save();
  24.  
  25.         return redirect()->to('articles/index');
  26.     }

L5ではアクションなどでメソッドインジェクションによる依存性の注入が可能です。

・ 記事投稿のビュー



と、ここで問題発生です。

記事投稿用のフォームの作成をしていきますが、ワタクシここでハマりました。。。
L4ではFormクラスとHTMLクラスといういわゆるヘルパークラスがありそれを使おうとしてもなぜか使えずに悩んでいました。IDEでファサードが補完されない時点で「オヤ?」と思いサービスプロバイダーを確認したところ見当たらずロードされていないことに気が付きました。どうやらL5からFormクラスとHTMLクラスは統合されなくなったようで別途Composerによるインストールが必要なことが分かりました。

という訳で、あった方が便利なので準備します。

illuminate/htmlのインストール


  1. $ composer require "illuminate/html:5.0.*"

サービスプロバイダーとファサードの追加


サービスプロバイダーに'Illuminate\Html\HtmlServiceProvider'を追加します。

・ config/app.php
  1. <?php ...
  2.  
  3.     'Illuminate\Hashing\HashServiceProvider',
  4.     'Illuminate\Html\HtmlServiceProvider',
  5.     'Illuminate\Mail\MailServiceProvider',

ファサードに'Form'=>'Illuminate\Html\FormFacade'と'HTML'=>'Illuminate\Html\HtmlFacade'を追加します。

・ config/app.php
  1. <?php ...
  2.  
  3.     'File'      => 'Illuminate\Support\Facades\File',
  4.     'Form'      => 'Illuminate\Html\FormFacade',
  5.     'Hash'      => 'Illuminate\Support\Facades\Hash',
  6.     'HTML'      => 'Illuminate\Html\HtmlFacade',
  7.     'Input'     => 'Illuminate\Support\Facades\Input',

これでHTMLクラスとFormクラスの準備は完了です。
L4からやってる人はハマるだろうなぁと思いました。笑

気を取り直して、記事投稿ビューの作成です。

・ resources/views/articles/create.blade.php
  1. @extends('app')
  2.   
  3.   @section('content')
  4.       <h2 class="page-header">記事投稿</h2>
  5.       {!! Form::open() !!}
  6.           <div class="form-group">
  7.               <label>タイトル</label>
  8.               {!! Form::input('text', 'title', null, ['required', 'class' => 'form-control']) !!}
  9.           </div>
  10.           <div class="form-group">
  11.               <label>本文</label>
  12.               {!! Form::textarea('body', null, ['required', 'class' => 'form-control']) !!}
  13.           </div>
  14.           <button type="submit" class="btn btn-default">投稿</button>
  15.       {!! Form::close() !!}
  16.   @endsection

'/articles/create'へアクセスしてください!フォームが表示され投稿が可能になったはずです。

◯ 記事の編集



編集は既に投稿を作っているため特筆することがありませんが、せっかくなのでソースを見ないで自分で作ってみるのも理解への近道かもしれませんね。

・ 記事編集のアクション



  1. <?php ...
  2.  
  3.     /**
  4.      * 記事の編集
  5.      *
  6.      * @param $id
  7.      * @return \Illuminate\View\View
  8.      */
  9.     public function getEdit($id)
  10.     {
  11.         $article = $this->article->find($id);
  12.  
  13.         return view('articles.edit')->withArticle($article);
  14.     }
  15.  
  16.     /**
  17.      * 記事の編集
  18.      *
  19.      * @param Request $request
  20.      * @param         $id
  21.      * @return \Illuminate\Http\RedirectResponse
  22.      */
  23.     public function postEdit(Request $request, $id)
  24.     {
  25.         $article = $this->article->find($id);
  26.         $data = $request->all();
  27.         $article->fill($data);
  28.         $article->save();
  29.  
  30.         return redirect()->to('articles/index');
  31.     }

with()はマジックメソッドとしても利用可能です。
上記の withArticle($article) は with('article' => $article) と同じです。

・ 記事編集のビュー



・ resources/views/articles/edit.blade.php
  1. @extends('app')
  2.   
  3.   @section('content')
  4.       <h2 class="page-header">記事編集</h2>
  5.       {!! Form::open(['action' => ['ArticlesController@postEdit', $article->id]]) !!}
  6.           <div class="form-group">
  7.               <label>タイトル</label>
  8.               {!! Form::input('text', 'title', $article->title, ['required', 'class' => 'form-control']) !!}
  9.           </div>
  10.           <div class="form-group">
  11.               <label>本文</label>
  12.               {!! Form::textarea('body', $article->body, ['required', 'class' => 'form-control']) !!}
  13.           </div>
  14.           <button type="submit" class="btn btn-default">編集</button>
  15.       {!! Form::close() !!}
  16.   @endsection

編集ページヘの導線を作成しましょう。(先程の投稿もついでに)

・ resources/views/articles/index.blade.php
  1. @extends('app')
  2.   
  3.   @section('content')
  4.       <h2 class="page-header">記事一覧</h2>
  5.       <div>
  6.           <a href="/articles/create" class="btn btn-primary">投稿</a>
  7.       </div>
  8.       <table class="table table-striped table-hover">
  9.           <thead>
  10.           <tr>
  11.               <th>タイトル</th>
  12.               <th>本文</th>
  13.               <th>作成日時</th>
  14.               <th>更新日時</th>
  15.               <th></th>
  16.           </tr>
  17.           </thead>
  18.           <tbody>
  19.           @foreach($articles as $article)
  20.               <tr>
  21.                   <td>{{{ $article->title }}}</td>
  22.                   <td>{{{ $article->body }}}</td>
  23.                   <td>{{{ $article->created_at }}}</td>
  24.                   <td>{{{ $article->updated_at }}}</td>
  25.                   <td>
  26.                       <a href="/articles/show/{{{ $article->id }}}" class="btn btn-default btn-xs">詳細</a>
  27.                       <a href="/articles/edit/{{{ $article->id }}}" class="btn btn-success btn-xs">編集</a>
  28.                   </td>
  29.               </tr>
  30.           @endforeach
  31.           </tbody>
  32.       </table>
  33.   @endsection

これで編集も出来ましたね!最後は削除です。

◯ 記事の削除



もしGETで受け付けた場合は'/articles/delete/1'にアクセスした時点で削除されます。それは厳しいと思いますのでPOSTでのみ受け付けることにします。

・ 記事削除のアクション



  1. <?php ...
  2.  
  3.     /**
  4.      * 記事の削除
  5.      *
  6.      * @param $id
  7.      * @return \Illuminate\Http\RedirectResponse
  8.      */
  9.     public function postDelete($id)
  10.     {
  11.         $article = $this->article->find($id);
  12.         $article->delete();
  13.  
  14.         return redirect()->to('articles/index');
  15.     }

・ 記事削除のビュー



・ resources/views/articles/index.blade.php
  1. @extends('app')
  2.   
  3.   @section('content')
  4.       <h2 class="page-header">記事一覧</h2>
  5.       <div>
  6.           <a href="/articles/create" class="btn btn-primary">投稿</a>
  7.       </div>
  8.       <table class="table table-striped table-hover">
  9.           <thead>
  10.           <tr>
  11.               <th>タイトル</th>
  12.               <th>本文</th>
  13.               <th>作成日時</th>
  14.               <th>更新日時</th>
  15.               <th></th>
  16.           </tr>
  17.           </thead>
  18.           <tbody>
  19.           @foreach($articles as $article)
  20.               <tr>
  21.                   <td>{{{ $article->title }}}</td>
  22.                   <td>{{{ $article->body }}}</td>
  23.                   <td>{{{ $article->created_at }}}</td>
  24.                   <td>{{{ $article->updated_at }}}</td>
  25.                   <td>
  26.                       <a href="/articles/show/{{{ $article->id }}}" class="btn btn-default btn-xs">詳細</a>
  27.                       <a href="/articles/edit/{{{ $article->id }}}" class="btn btn-success btn-xs">編集</a>
  28.                       {!! Form::open(['action' => ['ArticlesController@postDelete', $article->id]]) !!}
  29.                       <button type="submit" class="btn btn-danger btn-xs">削除</button>
  30.                       {!! Form::close() !!}
  31.                   </td>
  32.               </tr>
  33.           @endforeach
  34.           </tbody>
  35.       </table>
  36.   @endsection

・ resources/views/articles/show.blade.php
  1. @extends('app')
  2.   
  3.   @section('content')
  4.       <h2 class="page-header">記事詳細</h2>
  5.       <ul class="list-inline">
  6.           <li>
  7.               <a href="/articles/edit/{{{ $article->id }}}" class="btn btn-primary pull-left">編集</a>
  8.           </li>
  9.           <li>
  10.               {!! Form::open(['action' => ['ArticlesController@postDelete', $article->id]]) !!}
  11.               <button type="submit" class="btn btn-danger pull-left">削除</button>
  12.               {!! Form::close() !!}
  13.           </li>
  14.       </ul>
  15.       <table class="table table-striped">
  16.           <tbody>
  17.           <tr>
  18.               <th>タイトル</th>
  19.               <td>{{{ $article->title }}}</td>
  20.           </tr>
  21.           <tr>
  22.               <th>本文</th>
  23.               <td>{{{ $article->body }}}</td>
  24.           </tr>
  25.           <tr>
  26.               <th>作成日時</th>
  27.               <td>{{{ $article->created_at }}}</td>
  28.           </tr>
  29.           <tr>
  30.               <th>更新日時</th>
  31.               <td>{{{ $article->updated_at }}}</td>
  32.           </tr>
  33.           </tbody>
  34.       </table>
  35.   @endsection

削除ボタンをクリックすればデータが削除されるようになりましたでしょうか?
確認ボックスもなしにイキナリ削除なんて驚いたと思いますが、これにてブログアプリは完成です!お疲れさまでした〜!

◯ まとめ



L5でブログアプリを開発してみましたがどうでしょうか?正直シンプルすぎる構成ゆえL5の魅力をお伝え出来たとは思っていません(自分も全然満足していません)。個人的に注目しているのは新しくなったバリデーション、扱いやすくなったサービスプロバイダー、モデルとルーティングのバインド、メソッドインジェクションによる依存性の注入、他にも様々な機能が盛りだくさんで正直一記事で説明するのは無理があると思いました。なので、それらも今後発信していけたらと思います。

記事のソースでエラーが出たとかあればコメントください!それでは〜!(ソースは欲しい方いれば公開します。)

「クラウドでできるHTML5ハイブリッドアプリ開発」で紹介されているサンプルプロジェクトの使い方

$
0
0

先日、Monaca公式ガイドブックとしてクラウドでできるHTML5ハイブリッドアプリ開発が出版されました。本書では多くのサンプルプロジェクトを通してMonacaの利用法を紹介しています。



サンプルプロジェクトはMonaca - Monaca公式ガイドブック「クラウドでできるHTML5ハイブリッドアプリ開発」のページにてダウンロードができますが、今回はそのプロジェクトを使う方法を紹介します。



必要なもの





サンプルプロジェクトの選択



サンプルプロジェクトはMonaca - Monaca公式ガイドブック「クラウドでできるHTML5ハイブリッドアプリ開発」にてご覧いただけます。全32種類のプロジェクトが登録されています。今回はMonacaカウンターを使ってみます。




サンプルプロジェクト一覧

サンプルプロジェクト一覧



まずプロジェクト名の下にあるダウンロードを右クリックしてURLをコピーします。ダウンロードする必要はありません。




ダウンロードを右クリックしてURLをコピー

ダウンロードを右クリックしてURLをコピー



Monacaにて新しいプロジェクトの作成



Monacaにログインして、プロジェクトの作成をクリックします。




プロジェクトの作成をクリック

プロジェクトの作成をクリック



プロジェクトテンプレートが並んでいるのが確認できると思います。そして右上にあるImport Projectをクリックします。




Import Projectをクリック

Import Projectをクリック



モーダルウィンドウが表示されます。その中のインポート方法で、URLを指定してインポートを選択し、先ほどコピーしたURLを貼り付けます。プロジェクト名は適当に決めてください。




URLを貼り付け

URLを貼り付け



後はインポートボタンを押せば完了です。




プロジェクト一覧に登録

プロジェクト一覧に登録



インポートが無事終わると、左側のプロジェクト一覧に新規作成したプロジェクトが登録されているのが確認できるかと思います。これでデスクトップ側の作業は終わりです。



Monacaシミュレータを起動



続いてiOSまたはAndroid側で実行してみましょう。使うのはMonaca デバッガーです。iOSはApp Store、AndroidはGoogle Play(通常版ハイパフォーマンス版)をそれぞれダウンロードできますのでインストールしてください。Monaca デバッガーを起動すると、最初にログイン画面が表示されます。MonacaのIDとパスワードでログインしてください。




プロジェクト一覧

プロジェクト一覧



ログインすると先ほど登録したプロジェクトが表示されているかと思います。タップするとコードをMonacaクラウドからダウンロードし、実行します。




ダウンロード中

ダウンロード中




Monacaカウンター実行中

Monacaカウンター実行中



このようにしてソースコードに一切触れることなくプロジェクトが試せるようになっています。






もちろんプロジェクトはサンプルなので、Monaca IDEを使ってソースコードを見たり、カスタマイズができます。クラウドでできるHTML5ハイブリッドアプリ開発と一緒にご利用ください。

「アプリ開発教育普及プロジェクト」第一弾として教育機関向けにMonaca公式ガイドを無料配布します

$
0
0
先日、お陰様をもちましてMonacaの登録ユーザーが8万人を突破致しました。

Monacaは、企業での本格的なアプリ開発でご活用頂く一方で、アプリ開発の学習ツールとして、王立プノンペン大学、慶應義塾大学、東京工科大学、日本電子専門学校等多くの教育機関でご採用頂いています。

最近では、中学校や高校からもご相談を頂くことも増えてきておりまして、アプリ開発教育の裾野の広がりと注目度の高さを感じています。

各校での活用の様子は、Monacaアカデミックプランのページに掲載しているので是非ご覧ください。

この度、さらにこのアプリ開発学習の機会をできるだけ多くの学生や生徒の皆さんにお届けをしたいと思いまして「アプリ開発教育普及プロジェクト」なるものを開始いたしました。



まずは第一弾として2月17日発売の初のMonaca公式ガイド本『クラウドでできるHTML5ハイブリッドアプリ開発』を、教育機関を対象に先着50校に無償配布致します。

好評の場合は更に配布数を増やすことも検討しますので、多くの教育機関の皆様からの応募をお待ちしております。

詳細、ご応募はこちらからご覧ください。

今後も、ツール提供だけでなく教材開発など、様々な取り組みを行っていきたいと思いますので、是非ご注目ください!

Onsen UI version 1.2.2リリースのお知らせ

$
0
0

HTML5モバイルアプリを開発するのに最適なUIフレームワーク、Onsen UIの最新バージョン1.2.2がリリースしました。今回は大きな機能追加が二つあります。



  • ・Pull to Refresh
  • ・Infinite List


こちらの機能について解説します。



Pull to Refresh



Pull to Refreshは表示領域を下に引っ張ってイベントを起こす機能です。ネイティブアプリではよく知られた機能で、通常は情報更新する際に利用されます。こちらはまずデモで動作をご覧ください。実際に動かせるようになっていますので、その操作感を確かめてください。




See the Pen Alert, confirm and prompt dialogs by Onsen & Monaca (@onsen) on CodePen.





実際に利用する際には次のようにHTMLコードを書きます。



  1. <ons-page ng-controller="MyController">
  2.   <ons-pull-hook var="loaded" ng-action="load($done)">
  3.     <span ng-switch="loader.getCurrentState()">
  4.       <span ng-switch-when="initial">Pull down to refresh</span>
  5.       <span ng-switch-when="preaction">Release to refresh</span>
  6.       <span ng-switch-when="action">Loading data. Please wait...</span>
  7.     </span>
  8.   </ons-pull-hook>
  9.   <ons-list>
  10.     <ons-list-item ng-repeat="item in items">
  11.       Item #{{ item }}
  12.     </ons-list-item>
  13.   </ons-list>
  14. </ons-page>

JavaScriptは次のようになります。



  1. ons.bootstrap()
  2. .controller('MyController', function($scope, $timeout) {
  3.   $scope.items = [3, 2 ,1];
  4.   $scope.load = function($done) {
  5.     $timeout(function() {
  6.       $scope.items.unshift($scope.items.length + 1);
  7.       $done();
  8.     }, 1000);
  9.   };
  10. });

<ons-pull-hook var="loaded" ng-action="load($done)"> と書かれている通り、引っ張って離したタイミングで $scope.load が呼ばれます。ここでリストをリフレッシュしたり、追記したりすることができます。



詳しくはons-pull-hook | Onsen UIをご覧ください。



Infinite List



無限リストの機能になります。こちらもまずはデモでご覧ください。





See the Pen Alert, confirm and prompt dialogs by Onsen & Monaca (@onsen) on CodePen.







情報を一覧するリストでは時に大量になることがあります。スマートフォンのブラウザも高機能になっているとは言え、大量のDOMを描画するとどんどん動作が重たくなっていきます。そこで表示領域から消えたデータについてDOM Elementを削除し、メモリが逼迫したり動作が重たくなるのを防ぐ必要があります。そういった工夫は実装しようと思うと面倒なものです。そこで使って欲しいのがInfinite Listです。DOMの削除や復元を行うコントロールになります。



HTMLは次のようになります。



  1. <ons-list ng-controller="MyController">
  2.   <ons-list-item ons-lazy-repeat="MyDelegate"`>
  3.     {{ item }}
  4.   </ons-list-item>
  5. </ons-list>

ons-lazy-repeat要素を追加し、MyDelegateを指定しておきます。続いてJavaScriptは次のように書きます。



  1. ons.bootstrap()
  2.  
  3. .controller('MyController', function($scope) {
  4.   $scope.MyDelegate = {
  5.     countItems: function() {
  6.       // Return number of items.
  7.       return 1000000;
  8.     },
  9.  
  10.     calculateItemHeight: function(index) {
  11.       // Return the height of an item in pixels.
  12.       return 45;
  13.     },
  14.  
  15.     configureItemScope: function(index, itemScope) {
  16.       // Initialize scope
  17.       itemScope.item = 'Item #' + (index + 1);
  18.     },
  19.  
  20.     destroyItemScope: function(index, itemScope) {
  21.       // Optional method that is called when an item is unloaded.
  22.       console.log('Destroyed item with index: ' + index);
  23.     }
  24.   };
  25. });

リストのアイテム数、アイテムの高さ、スコープ設定、そしてDOMから削除した時の処理を呼び出せます。



これで大量のリスト項目を次々に読み込んでいったとしても安定した描画と動作を保てるようになります。その他、細かな点はons-lazy-repeat | Onsen UIをご覧ください。



その他のアップデート



1.2.2ではこの他、細かなアップデートが行われています。



  • ・<ons-carousel> が auto-refresh 指定可能に。
  • ・ユーザがメインページをタップしたらスライドメニューが閉じるようになりました。これはネイティブアプリによくあるUIに似せています。
  • ・<ons-tab>にpersistent要素を追加。この要素が指定されているタブはコンテンツの再ロードをしません。
  • ・ons.navigatorやons.slidingMenuといった自動的に生成されていた変数は削除されました。これにより既存のコードが影響を受ける場合があります。
  • ・Android 5(Lollipop)でテストされるようになりました。
  • ・カルーセルはドラッグイベントをスライドメニューに伝えなくなりました。また、スクロールコンテンツとカルーセルを一緒に使った場合もうまく動くようになりました。
  • ・その他小さなバグフィックス。





Onsen UIをお使いの方はぜひ最新版の1.2.2をお使いください。大量のリスト表示はよくある描画なので、速度や安定性の向上に役立つはずです。



HTML5モバイルアプリをもっと速く、もっと美しく | Onsen UI

Monaca公式ガイドブック出版記念「アプリ開発セミナー全国キャラバン」を開始しました

$
0
0
こんにちは塚田です。

2月17日に翔泳社より出版されたMonaca公式ガイド『クラウドでできるHTML5アプリ開発』は、お陰様を持ちましてAmazonのモバイルプログラミングのカテゴリで1位にランキングされるなど、大変ご好評を頂いております。ありがとうございます。

昨日、本書の発売を記念して開催するアプリ開発セミナーの全国キャラバンの記念すべき第一回が東京で開催されました。



会場は、TAMさんのコワーキングスペースをお借りしたのですが、開放感があって非常に心地のよい会場でした。



セミナーではアシアルの岡本が最近のMonacaやCordova関連の動向の解説を加えつつ、MonacaとOnsen UIを使ったアプリ開発手法に関してポイント解説をさせていただきました。



満席の会場からは質問やご意見なども多く頂きまして、非常に熱いセミナーとなりました。

セミナー終了後は、参加者の皆さんと記念撮影。



「キャラバン頑張ってくださいね!」
等の暖かいお声も頂きました。

皆さん本当にありがとうございました。

今後の予定ですが、北は札幌、南は沖縄まで全国7都市、計10回のセミナーを開催致します。

若干ですがまだお席の残っている会場もございますので、是非ご参加ください。

・大阪 3月6日 19時〜(満員)
沖縄 3月11日 19時〜(残席あり)
福岡 3月12日 19時〜(残席あり)
札幌 3月13日 19時〜(残席あり)
・東京 3月17日 19時〜(満席)
・名古屋 3月19日 19時〜(満席)
・京都 3月20日 19時半〜(満席)
東京 3月28日 10時〜(残席あり)
東京 3月28日 14時〜(残席あり)

AndroidでカードUIの実装に便利なプラグイン

$
0
0
こんにちは、細井です。

Androidから少し離れている内に、GoogleがMaterial DesignとかAndroid Studioを使え、とか言っていて取り残されています。。
この記事では、Material Designの概念のうち、カードUIをAndroidで実装する際に便利なプラグインを紹介します。

ListViewAnimations
https://github.com/nhaarman/ListViewAnimations
カードのスクロールにアニメーションを付けたり、カードのドラッグアンドドロップやスワイプでの削除を簡単に行えるようになります。
カードUIでは、スクロールで読み込む前のカードにはアニメーションを付けて、読み込んだ後のカードにはアニメーションを付けないことで、何処まで読み込んだか感覚的に分かるようにすることが推奨されているようです。
今回は、それも実現できるアニメーション付与の機能を試してみます。

StaggeredGridView
https://github.com/etsy/AndroidStaggeredGrid
カードをGridViewで複数列並べた時に、カードの高さが均一になってしまうのを解消してくれるGridViewです。

使ってみた
実際に使って、カードUIの一覧画面っぽいものを作ってみました。
アニメーションは、スクロール時に下からどんどん現れてくるような動きをします。



実装
どちらもGradleでモジュールをダウンロードできます。
build.gradleに以下のdependenciesを追加します。

  1. dependencies {
  2.     // ListViewAnimations
  3.     compile 'com.nhaarman.listviewanimations:lib-core:3.1.0@aar'
  4.     compile 'com.nhaarman.listviewanimations:lib-manipulation:3.1.0@aar'
  5.     compile 'com.nhaarman.listviewanimations:lib-core-slh:3.1.0@aar'
  6.     // Githubでは指定無しですが、無いと動かなかったです
  7.     compile 'com.nineoldandroids:library:2.4.0'
  8.     
  9.     // StaggeredGridView
  10.     compile 'com.etsy.android.grid:library:1.0.5'
  11.     
  12.     // Lollipopで追加されたCardViewも使ってみます
  13.     // support-v7で用意されているので、下位バージョンでも使用できます
  14.     compile "com.android.support:cardview-v7:+"
  15. }

LayoutのxmlはMainActivityのものと、GirdViewに表示するカードのものを用意しました。

【activity_main.xml】
  1. <RelativeLayout
  2.     xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     android:padding="5dp">
  6.     <com.etsy.android.grid.StaggeredGridView
  7.         xmlns:app="http://schemas.android.com/apk/res-auto"
  8.         android:id="@+id/grid_view"
  9.         android:layout_width="match_parent"
  10.         android:layout_height="match_parent"
  11.         app:item_margin="5dp"
  12.         app:column_count="2"/> <!-- GridViewの列数を指定 -->
  13. </RelativeLayout>

【view_card.xml】
  1. <android.support.v7.widget.CardView
  2.     xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:card_view="http://schemas.android.com/apk/res-auto"
  4.     android:layout_width="match_parent"
  5.     android:layout_height="wrap_content"
  6.     card_view:cardCornerRadius="3dp"> <!-- カードの角丸を指定 -->
  7.     <LinearLayout
  8.         android:layout_width="match_parent"
  9.         android:layout_height="wrap_content"
  10.         android:orientation="vertical"
  11.         android:padding="10dp">
  12.         <ImageView
  13.             android:id="@+id/card_image"
  14.             android:layout_width="match_parent"
  15.             android:layout_height="match_parent"
  16.             android:adjustViewBounds="true"
  17.             android:src="@drawable/card1" />
  18.         <TextView
  19.             android:id="@+id/card_message"
  20.             android:layout_width="match_parent"
  21.             android:layout_height="wrap_content"
  22.             android:text="@string/card_message_1"
  23.             android:paddingTop="10dp"/>
  24.     </LinearLayout>
  25. </android.support.v7.widget.CardView>

次は、Activity側のソースになります。
基本的にはGridViewやAdapterのオブジェクトを置き換えるだけです。簡単。

【MainActivity.java】
  1. public class MainActivity extends Activity {
  2.  
  3.     @Override
  4.     protected void onCreate(Bundle savedInstanceState) {
  5.         super.onCreate(savedInstanceState);
  6.         setContentView(R.layout.activity_main);
  7.  
  8.         // GridViewの代わりに、StaggeredGridViewを使用
  9.         StaggeredGridView gridView = (StaggeredGridView) findViewById(R.id.grid_view);
  10.  
  11.         // 適当なAdapterを作成
  12.         MyAdapter myAdapter = new MyAdapter();
  13.  
  14.         // 作成したAdapterをListViewAnimationsのクラスに渡して、AnimationAdapterに
  15.         SwingBottomInAnimationAdapter animationAdapter = new SwingBottomInAnimationAdapter(myAdapter);
  16.         animationAdapter.setAbsListView(gridView);
  17.  
  18.         // StaggeredGridViewにAnimationAdapterをセット
  19.         gridView.setAdapter(animationAdapter);
  20.     }
  21.     
  22.     // BaseAdapterを継承した適当なAdapter
  23.     private class MyAdapter extends BaseAdapter {
  24.        ・・・
  25.     }
  26. }

ListViewAnimationsには、SwingBottomInAnimationAdapterクラス以外にも以下のクラスが用意されています。

・ AlphaAnimationAdapter
・ ScaleInAnimationAdapter
・ SwingLeftInAnimationAdapter
・ SwingRightInAnimationAdapter

クラス毎にアニメーションが異なります。
アニメーションの動作は、ListViewAnimationsのデモアプリで確認できます。

まとめ
既存のコードにも組み込みやすいプラグインなので、
あまり時間はかけられないけど、それっぽい画面を作りたい時には役立つと思います!

ng-japanに参加しました

$
0
0
こんにちは。宇都宮です。今回は、週末に参加したイベントのレポートです。

3/21(土)に、ng-japanという日本初のAngularJSのカンファレンスが開催されました。会場は渋谷マークシティ13Fにある、サイバーエージェントさんのセミナールームでした。

今回のカンファレンスは、スピーカーにAngularJSのコアチームのメンバーが3名いるのが最大の特長でしょう。当然トークは英語なのですが、英=>日の逐次通訳付きなので、英語が苦手な人でも大丈夫なカンファレンスでした。

参加者の最大の関心事は「Angular 2はどうなるのか?」という点にあったと思います。私自身は、今回のカンファレンスに参加して、Angular 2について前向きな気持ちになれました。

以前は、「Angular 1系から2系への移行は無理」「1系はあと2年くらいでサポート終了」と思っていましたが、1系から2系へはアップグレードの道筋がつけられていること、1系のサポート期間はもう少し長くなるかも、といった情報を得ることができました。

プレゼンは全て映像化されていて、youtubeで視聴できます。



以下、各セッションについて簡単にまとめていきます。

Angular 1.4 and beyond



Chirayu Krishnappa(@chirayuk)氏による、AngularJS 1.4と、その周辺のお話でした。

今週にもリリース予定のAngularJS 1.4.0では、いくつかの新機能の追加、パフォーマンス改善とバグフィックスがあり、かつ、1.3系との強い後方互換性があります(破壊的変更は$cookieのみ)。そのため、1.3系のユーザーは、リリース後速やかに1.4.0にアップグレードすべき、とのことでした。

もう1つの話題はAngularJSのコミュニティでした。AngularJSのコミュニティはどんどん成長していて、AngularJSのソースに対するコミットは、現在では、Googleのコアチームよりも、コミュニティによって行われるものの方が多くなっている、とのことでした。

また、AngularJSにコントリビュートするためのお作法や、貢献を必要としている分野(たとえば、すでに解決済みなのに閉じられていないissueを閉じる等)なども紹介されていました。

スライドはhttp://ngjapan2015.chirayuk.com/#/です。

AngularとOnsen UIで作る最高のHTML5ハイブリッドアプリ



弊社の久保田(@anatoo)も、AngularJS製のUIフレームワーク・Onsen UIについて講演しました。



タイトルだけ見るとOnsen UIの紹介がメインのように見えますが、実際は、ハイブリッドアプリの概要から始まり、HTML5アプリのパフォーマンスチューニングの話題が主要な部分を占めます。

ハイブリッドアプリにはUIフレームワークが欠けていた、だからOnsen UIを作ったのだ、という開発の経緯がよくわかるプレゼンでした。

スライドにない部分としては、Onsen UIと同じくハイブリッドアプリ用のUIフレームワークであるionicとの比較について、会場からの質問がありました。

OnsenUIのionicと比べた利点としては以下がある、とのことです。

- (ionicが初期はiOSにフォーカスしていたのに対して) OnsenUIはAndroidでもパフォーマンスの最適化を行っている
- OnsenUI 1.3ではWindows Phoneサポートを追加する予定
- OnsenUIは日本語ドキュメントがある

Routing your way in an Angular app



Brian Ford(@briantford)氏による、AngularJS用の新しいルーターコンポーネント(New Router)のお話でした。

新しいルーターは、以下のリポジトリで開発が進められています。
https://github.com/angular/router

新しいルーターは、Angular 2向けに設計されているものの、Angular 1でも動くように作られています。

また、1系から2系への移行の話題もあり、1系と2系は何らかの手段で共存できるような仕組みが用意され、機能単位で少しずつ移行を進める、といったことができる、とされていました(具体的な移行手順はまだ策定中のようです)。

その他、新しいルーターの機能紹介などが実際のコードを伴って紹介されていました。詳細は以下のスライドを参照してください。
http://goo.gl/YpKc6e

TypeScript+Angular 1.3



わかめ まさひろ氏(@vvakame)による、TypeScriptとAngularJSの関わりについての講演でした。



以前、Angular 2.0はAtScriptという、TypeScriptの機能強化版で実装される、という話がありましたが、最近になって、AtScriptではなくTypeScriptで実装されることになりました。TypeScriptの開発チームとAngularJSの開発チームがディスカッションした結果、TypeScriptに、AngularJSチームが求める機能が入ることになった、という経緯があるらしいです。

Angular 2ではTypeScriptでも開発できるようになるので、早めに慣れておいたほうが良いのでは、ということで、TypeScriptの構文の簡単な紹介から、TypeScript + Angular 1.3におけるプロジェクトのテンプレートの紹介まで、実践的な内容が豊富でした。

ちなみに、一般的なJavaScriptライブラリをTypeScriptで使うには、TypeScript用の型定義ファイルというものが必要になります。Onsen UIには現在、TypeScript用の型定義ファイルが無いのですが、Onsen UI 1.3では型定義ファイルが用意されるとかされないとか…。

Angular 2



Igor Minar(@igorminar)氏による、Angular 2についての講演です。

冒頭、Google内部では2000ものアプリケーションがAngularJSで構築されている、というお話が出てきて、驚きました。社内のみで利用されるアプリケーションがほとんどらしいですが、それにしてもすごい数です。

Angular 2は以下のテーマに基いて構築されているそうです。

- Simpler
- Consistent
- Flexible
- Fast
- Productive

中でも熱心に説明されていたのが、「Fast」、パフォーマンスについてでした。Angular 2は素の状態でもAngular 1の3倍近く、View Cacheを使えば8倍近いパフォーマンス(パフォーマンス最適化の理論上の最適値に近いパフォーマンス)を出すことも可能、とのことです。

また、Angular 1が対応する言語はJavaScriptだけで、AltJSは公式のサポート対象ではありませんでしたが、Angular 2ではTypeScriptがサポート対象に加わります。

今年の5月には、Angular 2.0をGoogle社内で使い始めるらしいです。

また、気になる1系から2系への移行の話ですが、ほとんどの人が1系から2系に移行完了するまでは1系をサポートすること、移行のための機能やツールを用意すること、など、既存ユーザーのための移行パスを設けることを強調していました。

スライドはhttp://goo.gl/plXk7dです。

スポンサーLT



Piece of Cakeの今さんとLIGの林さんのLTのテーマがモロに被っていたのが印象的でした。
どちらも、Angular 1.3から加わった機能・ワンタイムバインディングと、digest loopが走るタイミングについてのプレゼンでした。





要するに、ワンタイムバインディングを使ってwatcherの数を減らすこと、digest loopの数を減らすことは、パフォーマンス改善のために非常に重要である、ということですね。

おわりに



以上、各セッションの内容を簡単にまとめてきました。
AngularJSを実際に作っている人の話が聞けるというのは、とても貴重な経験だったと思います。

ロジック暗号化もできる。Monacaエンタープライズ版のご紹介

$
0
0

Monacaでは大企業向けアプリ開発・運用基盤としてMoancaエンタープライズを提供しています。業務アプリ開発などで規模の大きい企業において求められるセキュリティ、業務要件をサポートし、既存システムとの連携も容易にできるようなっています。



今回はそんなMonacaエンタープライズの機能をいくつか紹介します。



企業システムとの接続



Monacaはエンタープライズ向けmBaaS(Mobile Backend as a Service)を提供するKidoZenと提携しています。そのKidoZenを使うことで、容易かつセキュアにモバイルアプリと既存システムとを連携させられます。




KidoZen連携

KidoZen連携



エンタープライズに求められるプラグイン群



アプリロジック暗号化



アプリ内のファイルを暗号化することで解読、複製を防止できます。ソースコードが見えてしまうのがハイブリッドアプリの採用に至らない要因の一つと言われていますが、アプリロジック暗号化を用いることでクリアできます。




アプリのロジックを暗号化

アプリのロジックを暗号化



セキュアストレージ



デバイス上に保存されるデータを暗号化して保存します。端末の盗難、紛失などに伴う情報漏洩を防止します。デバイスには重要なデータがどんどん蓄積されています。それだけに紛失時にデータが盗まれないよう予め準備しておく必要があります。




セキュアストレージ

セキュアストレージ



In-App アップデーター



アプリのコンテンツをアプリストアを介することなくアップデートします。アプリの再配布のような手間がなく、常に最新のアプリを保つことができます。こちらはアプリのロジック暗号化とも組み合わせて利用が可能となっています。




In-App アップデーター

In-App アップデーター






アプリのロジック暗号化やセキュアストレージはエンタープライズレベルにおいて重要な要件になるでしょう。また、社内の業務システムとの連携やプッシュ通知などが簡単にできるようになれば、ハイブリッドアプリで業務フローをどんどん効率化していけるはずです。



ぜひMonacaエンタープライズをチェックしてください!



Moancaエンタープライズ - 大企業向けHTML5ハイブリッドアプリ開発プラットフォーム

Monaca公式Twitter日本語版の運用開始のお知らせ

$
0
0
こんにちはマーケティング担当の塚田です。

今までMonaca公式Twitterは英語のみで運用しておりましたが、日本語でもTwitterでの情報を希望する声を多数いただきましたので、それにお応えする形で3月22日からMonaca公式Twitter日本語版の運営を開始しました。



主な投稿内容は以下の通りです。Monaca公式Facebookアカウントと同じ内容を投稿しています。

・Monaca技術情報
・Monaca関連イベント・セミナー情報
・Monaca事例
・Monaca新パートナーのご紹介

Twitterでの情報提供をご希望な方はこちらのアカウントをフォローしてください。

Monaca日本語公式Twitterアカウント
https://twitter.com/monaca_ja

なお、公式Facebookページ日本語版も運用しております。
Facebookでの情報をご希望される方は以下をご覧ください。
https://www.facebook.com/monaca.io

なお、公式Facebookアカウント同様Twitterでもご質問への回答は行っておりません。

Monacaに関するお問い合わせは、Monaca公式Webサイト上の「お問い合わせ」からお願いいたします。

それでは引き続き宜しくお願いいたします。

MonacaでCrosswalk版を使おう

$
0
0

Intelが中心となって絶賛開発中のCrosswalkですが、最も大きな利点として「AndroidデバイスにおいてHTML5の先端のAPIが安心して使える」があります。もちろんデバイスによってハードウェア的に取り除かれているものは動きませんが、Blink(WebKit)のバージョンが固定化できることによって、これまでのAndroidデバイスで行っていたテスト工数が大幅に削減できるはずです。



さて、そんなCrosswalkですがMonacaではとても簡単に利用できます。ぜひお試しください。



Androidアプリ設定を行う



Crosswalkを使ったビルドを行うためのメニューは設定メニューの中のAndroidアプリ設定になります。




設定メニュー

設定メニュー



Android設定の中にWebViewエンジンという項目があります。これをハイパフォーマンス版に切り替えるだけです。




Crosswalk版に切り替え

Crosswalk版に切り替え



ビルドしてみよう



ビルド自体は大きくは変わりませんが、一点だけ変更があります。それはCPUアーキテクチャの選択が追加されることです。




CPUアーキテクチャ選択

CPUアーキテクチャ選択



通常はARMで良いですが、必要に応じて切り替えるようにしてください。



後はリモートビルドが完了し、ダウンロードできるようになります。




ビルド完了

ビルド完了



サイズはどれくらい増えるのか?



Crosswalk版はWebViewエンジンをアプリの中に内包するのが特徴になります。それにより個々のデバイスにあるWebViewのバージョンなどに左右されることなく動作可能になります。



唯一の欠点としてはアプリのサイズがWebViewの分、肥大化することでしょう。これはおおよそ18MBくらいになります。ごくごく小さなアプリの場合、数倍になるかも知れませんが、最近のアプリはリソースが高品質化することでサイズが大きくなる傾向があるので18MBくらいであれば許容範囲と言えるのではないでしょうか。また、アプリの自動アップデートも使われるようになっていますので、ユーザがアプリサイズを気にすることは殆どないかも知れません。






Crosswalkはこれまで問題視されていたデバイスごとの動作誤差をなくしてくれる素晴らしい仕組みです。Android 4.0以降に限定されてしまうのですが、既に2.x系のシェアは十分に小さくなっていますので今後開発される際にはCrosswalkで提供してみてはいかがでしょう。



Crosswalk - build world class hybrid apps


Monacaアップデート: Cordova互換性向上とiOS言語設定

$
0
0
Monacaでは利用者の依頼や要望にもとづき日々改良を重ねています。最近、比較的大きなリリースを行いましたので、その内容と注意点について紹介します。

Cordovaプロジェクトのインポートに対応しました



ご要望の大きかった、Cordovaプロジェクトからのインポートを行えるようにいたしました。MonacaもCordovaを使用していますが、アプリの構成を定義するconfig.xmlの書式が異なっていることから、これまではインポートする際の入力チェックで失敗していました。

今回のアップデートで、Cordovaで作成したプロジェクトのフォルダを圧縮してzip形式にすることで、MonacaクラウドIDEでエクスポートしたファイルと同様の手順でインポートを行うことができるようになりました。インポートの手順に関する詳細は、下記のドキュメントを参照してください。

Monacaドキュメント:プロジェクトのインポートとエクスポート

Cordovaプロジェクトをインポートする際の注意点:

1. config.xml ファイルやplatformsフォルダはインポート時に無視されるため、IDEからAndroid/iOSアプリ設定を開いて必要な設定を行ってください。

2. JS/CSSコンポーネントを用いるために、index.htmlに以下を記載してください。

  1. <script src="components/loader.js"></script>
  2. <link rel="stylesheet" href="components/loader.css">

Android/iOSアプリ設定の一部を共通化しました



上記の対応に伴い、今後新規作成したプロジェクトでは、以下に示すAndroid/iOSアプリ設定項目が共通化されます。

  • ・アプリケーション名
  • ・パッケージ名(App ID)
  • ・バージョン
  • ・許可する外部URL
  • ・オーバースクロールを無効

これは、これまでiOSとAndroidで別れていたconfig.ios.xmlとconfig.android.xmlをconfig.xmlに統合し、Cordova形式に準拠したことによるものです。




iOSの対応言語が指定できるようになりました



iOSアプリ設定で、対応言語を指定できるようになりました。

対応言語を指定すると、ビルドしたiOSアプリのネイティブUIメッセージが指定した言語で表示されるようになります。たとえばテキストをタップしたときに表示される「コピー」「貼り付け」などの文言です。これまでは未指定のためデフォルトで日本語が表示されていました。

なお新規作成したプロジェクトでは、Englishのみが選択された状態となりますので、ご注意ください。既存のプロジェクトについては、特に何も選択されていない状態となり、その場合は日本語が適用されます。

Burp Suiteで脆弱性診断

$
0
0
こんにちは。坂本です。

今回は脆弱性診断ツールができるBurp Suiteというツールを紹介します。



このセキュリティ界隈では知らない人はいない有名なツールです。

Burp Suiteは脆弱性診断に必要な機能を揃えています。
・Webサイトへリクエストする情報を改ざんして脆弱性がないか確認する機能
・WebサイトをクローリングしてURLのリストを取得する機能
・取得したURLに対して脆弱性がないか診断をする機能
などなど

この機能を実現するためBurp Suiteはプロキシサーバとなります。
プロキシとなったBurp SuiteはWebサイトとブラウザの間に入りリクエストを傍受し脆弱性診断を行うことができます。



Burp Suiteの購入から起動


Burp Suiteで脆弱性診断をするにはライセンスを購入する必要があります。
まずは公式サイトでBurp Suiteのダウンロードを行います。

http://portswigger.net/burp/

2015年4月3日の価格では1年当たり1人2.99ドルが必要になります。
高いと思われると思いますがBurp Suite以外の信頼性のあるツールに比べると100倍安かったりします。

Burp Suiteの本体はjarファイルとなっておりMacであればダブルクリックで
Windowsであればbatファイルからの起動となります。

起動するとシンプルが画面が表示されます。



Burp Suiteの設定


購入したライセンスをBurp Suiteに適用させると脆弱性診断の機能を利用することができます。

Burpのプロキシ設定


診断を行う前にプロキシの設定を行う必要があります。
Proxyタブ中のOptionsタブを開きます。


AddボタンをクリックしてBind to portにポート番号を入力します。
ここでは8080を使用します。


プロキシ設定が上手くいけばリストに127.0.0.1:8080が追加されます。
これでBurp SuiteはIPが127.0.0.1で8080ポートを使ったプロキシが立ち上がります。


ブラウザのプロキシ設定


ブラウザの設定にプロキシの設定があるはずなので以下のようにHTTPプロキシと
SSL(HTTPS)プロキシに127.0.0.1と8080ポートを指定します。


これにより以降のブラウザのアクセスはすべてBurp Suiteプロキシを介したアクセスとなります。

脆弱性診断サイト設定


このままでは脆弱性診断ができないので診断するサイトを設定します。

ScannerタブのLive scanningタブを開いてください。


Include in scopeのAddをクリックして診断するサイトを追加します。
ここでは仮にwww.test.comとなっていますが実際には自分のサイトのドメインを入力してください。
間違っても関係のない有名なサイトのドメインを入力してはいけません。


入力がうまくいけばリストに追加されます。


診断開始


以上の設定が終わりましたらブラウザで自分のサイトにアクセスしてみてください。
URLに対して脆弱性診断が開始されます。
1つのURLに対して行われるリクエスト数はGET、POSTパラメータによって変わります。


脆弱性を含むサイトだった場合はScannerタブのResultsタブに結果が表示されます。
以下の例では致命的な脆弱性は出ていませんがXSSやSQLインジェクションが検出されると赤字で結果が表示されます。


どのような脆弱性を検出するかはScannerタブのOptionsタブで設定することができます。


さいごに


いかがでしたでしょうか?
脆弱性診断は面倒と思われますがこんなに簡単に検出できます。
逆に言うと少しの知識があればあっという間に脆弱性を悪用されてしまうことを意味しています。

最近はセキュリティを考慮したフレームワークを利用することがスタンダードだと思いますが
思いがけない穴が見つかることもあります。

くれぐれも気をつけてサイトを構築していってください。

Onsen UIをWebサイトで使ってみよう

$
0
0

HTML5のUIフレームワークであるOnsen UIはMonacaとの相性を考えて開発されていますが、必ずしもハイブリッドアプリ専用という訳ではありません。Webサイト開発にも利用が可能です。



GoogleがWebサイトのモバイル対応が行われているかどうかを検索順位に反映することを発表していたり、HTML5によってWebもどんどん多機能になっている中、Onsen UIを使うことで高速な描画で使いやすいWebサイトが構築できるはずです。



そこで今回はOnsen UIをWebサイト開発に利用する方法について紹介したいと思います。



準備



Onsen UI自体はJavaScript/スタイルシートで出来ていますのでダウンロードして配置するだけですが、今回はbowerを使って行いたいと思います。Onsen UIはbowerからコマンド一つでインストール可能です。bowerはnode.jsのパッケージ管理、npmを使ってインストールします。




  1. node.jsのインストール(npmもインストールされます)
  2. Gitのインストール
  3. bowerのインストール



node.jsはNode.js Downloadからダウンロード/インストールができます。GitはMac OSXであればHomebrewやMacPortsから、WindowsであればGit for Windowsをダウンロード/インストールしてください。終わったら続いてbowerをインストールします。



  1. $ npm install -g bower

これでインストールは完了です。



作業用ディレクトリの作成



続いてWebサイトを作るディレクトリ(フォルダ)を作成します。今回は onsenui_for_website としています。そのディレクトリの中でbowerコマンドを実行します。



  1. $ bower install onsenui
  2. bower cached        git://github.com/OnsenUI/OnsenUI.git#1.2.2
  3. bower validate      1.2.2 against git://github.com/OnsenUI/OnsenUI.git#*
  4. bower cached        git://github.com/angular/bower-angular.git#1.3.15
  5. bower validate      1.3.15 against git://github.com/angular/bower-angular.git#~1.3.0
  6. bower install       onsenui#1.2.2
  7. bower install       angular#1.3.15
  8. onsenui#1.2.2 bower_components/onsenui
  9. └── angular#1.3.15
  10. angular#1.3.15 bower_components/angular

Onsen UIがダウンロードされて、 bower_components 以下に展開されます。




Onsen UIのファイル一覧

Onsen UIのファイル一覧



Onsen UIを使う上で関連付いているAngularJSも一緒に展開されます。これでほぼ準備は完了です。



Gulpの準備



そのまま使っても良いのですが、 bower_components というフォルダに入ってしまっていたり、実際の運用時には不要なファイルも多いので Gulp を使ってまとめることにします。既にnpmは入っていますので、インストールは簡単です。まず最初にnpmで必要なパッケージを管理するようにします。



  1. $ npm init
  2. This utility will walk you through creating a package.json file.
  3. It only covers the most common items, and tries to guess sane defaults.
  4. See `npm help json` for definitive documentation on these fields
  5. and exactly what they do.
  6. Use `npm install <pkg> --save` afterwards to install a package and
  7. save it as a dependency in the package.json file.
  8. Press ^C at any time to quit.
  9. name: (onsenui_for_website) 
  10. version: (1.0.0) 0.0.1
  11. description: Web site that use the Onsen UI
  12. entry point: (index.js) 
  13. test command: 
  14. git repository: 
  15. keywords: 
  16. author: Atsushi Nakatsugawa
  17. license: (ISC) MIT
  18. About to write to /Users/nakatsugawa/Dropbox/DevRel/Monaca/onsenui_for_website/package.json:
  19. {
  20.   "name": "onsenui_for_website",
  21.   "version": "0.0.1",
  22.   "description": "Web site that use the Onsen UI",
  23.   "main": "index.js",
  24.   "scripts": {
  25.     "test": "echo \"Error: no test specified\" && exit 1"
  26.   },
  27.   "author": "Atsushi Nakatsugawa",
  28.   "license": "MIT"
  29. }
  30. Is this ok? (yes) yes

そうすると package.json というファイルが作成されて、ライブラリを管理できるようになります。後はGulpと必要なライブラリをインストールしていきます。



  1. $ npm install --save-dev -g gulp
  2. $ npm install --save-dev gulp-changed # ここから下はGulpのプラグインです。
  3. $ npm install --save-dev gulp-concat
  4. $ npm install --save-dev gulp-coffee
  5. $ npm install --save-dev gulp-uglify
  6. $ npm install --save-dev gulp-sourcemaps
  7. $ npm install --save-dev gulp-webserver
  8. $ npm install --save-dev del

後はGulp用の設定ファイル、gulpfile.js を作成します。



  1. // gulpfile.js
  2. var gulp = require('gulp');
  3. var coffee = require('gulp-coffee');
  4. var concat = require('gulp-concat');
  5. var uglify = require('gulp-uglify');
  6. var webserver = require('gulp-webserver');
  7. var sourcemaps = require('gulp-sourcemaps');
  8. var del = require('del');
  9.  
  10. var paths = {
  11.   scripts: ['app/js/**/*.coffee', '!app/external/**/*.coffee']
  12. };
  13.  
  14. // Webサーバの機能です
  15. gulp.task('webserver', function() {
  16.   gulp.src(&quot;./&quot;)
  17.     .pipe(webserver({
  18.       livereload: true,
  19.     }));
  20. });
  21.  
  22. // スクリプトの結合と配置を行っています
  23. gulp.task('scripts', function() {
  24.   return gulp.src([
  25.       './bower_components/onsenui/build/js/angular/angular.min.js',
  26.       './bower_components/onsenui/build/js/onsenui_all.min.js'
  27.   ])
  28.     .pipe(concat('all.js'))
  29.     .pipe(gulp.dest('./javascripts/'));
  30. });
  31.  
  32. // ファイルの変更を監視しています(今回は使っていません)
  33. gulp.task('watch', function() {
  34.   gulp.watch(paths.scripts, ['scripts']);
  35. });
  36.  
  37. gulp.task('default', ['webserver', 'scripts', 'watch']);

これで $ gulp scripts と実行すると、AngularJSとOnsen UIのJavaScriptファイルがくっついた状態で javascripts/all.js として生成されます。なおスタイルシートについても同様の操作が可能ですが、今回は bower_components/onsenui/build/css/ を プロジェクトルート直下に stylesheets という名称でコピーしています。



その結果、次のようなファイル構成になっていればOKです。




Onsen UIのファイル構成

Onsen UIのファイル構成



index.htmlの編集



では実際に表示を行うindex.htmlを作成しましょう。まず最初に次のようにHTMLファイルを作成します。



  1. <!DOCTYPE html>
  2. <html class="">
  3.   <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="robots" content="noindex">
  6.     <link rel="stylesheet prefetch" href="stylesheets/onsenui.css">
  7.     <link rel="stylesheet prefetch" href="stylesheets/onsen-css-components.css">
  8.   </head>
  9.   <body>
  10.   <script src="javascripts/all.js"></script>
  11.   <script>
  12.       ons.bootstrap();
  13.       //@ sourceURL=pen.js
  14.     </script>
  15.   </body>
  16. </html>

この形が Onsen UIの基本形になります。後はこの <body>〜</body>の間にコンテンツを書くだけです。JavaScript | Onsen UIには多くのコンポーネントを用意しています。例えばチェックボックスを表示します。内容はPattern: Checkbox List | Onsen UIにもありますが、bodyタグの中に次のように記述します。



  1. <ons-page>
  2.   <ons-toolbar>
  3.     <div class="center">Checkboxes</div>
  4.   </ons-toolbar>
  5.   <ons-list>
  6.     <ons-list-header>Favorite Sports</ons-list-header>
  7.  
  8.     <ons-list-item modifier="tappable">
  9.       <label class="checkbox checkbox--list-item">
  10.         <input type="checkbox">
  11.         <div class="checkbox__checkmark checkbox--list-item__checkmark"></div>
  12.         Baseball
  13.       </label>
  14.     </ons-list-item>
  15.  
  16.     <ons-list-item modifier="tappable">
  17.       <label class="checkbox checkbox--list-item">
  18.         <input type="checkbox">
  19.         <div class="checkbox__checkmark checkbox--list-item__checkmark"></div>
  20.         Soccer
  21.       </label>
  22.     </ons-list-item>
  23.  
  24.     <ons-list-item modifier="tappable">
  25.       <label class="checkbox checkbox--list-item">
  26.         <input type="checkbox" checked="checked">
  27.         <div class="checkbox__checkmark checkbox--list-item__checkmark"></div>
  28.         Basketball
  29.       </label>
  30.     </ons-list-item>
  31.  
  32.     <ons-list-item modifier="tappable">
  33.       <label class="checkbox checkbox--list-item">
  34.         <input type="checkbox" checked="checked">
  35.         <div class="checkbox__checkmark checkbox--list-item__checkmark"></div>
  36.         Golf
  37.       </label>
  38.     </ons-list-item>
  39.  
  40.     <ons-list-header>Favorite Food</ons-list-header>
  41.  
  42.     <ons-list-item modifier="tappable">
  43.       <label class="checkbox checkbox--noborder checkbox--list-item">
  44.         <input type="checkbox" checked="checked">
  45.         <div class="checkbox__checkmark checkbox--noborder__checkmark checkbox--list-item__checkmark"></div>
  46.         Hamburger
  47.       </label>
  48.     </ons-list-item>
  49.  
  50.     <ons-list-item modifier="tappable">
  51.       <label class="checkbox checkbox--noborder checkbox--list-item">
  52.         <input type="checkbox">
  53.         <div class="checkbox__checkmark checkbox--noborder__checkmark checkbox--list-item__checkmark"></div>
  54.         Beefsteak
  55.       </label>
  56.     </ons-list-item>
  57.  
  58.     <ons-list-item modifier="tappable">
  59.       <label class="checkbox checkbox--noborder checkbox--list-item">
  60.         <input type="checkbox" checked="checked">
  61.         <div class="checkbox__checkmark checkbox--noborder__checkmark checkbox--list-item__checkmark"></div>
  62.         Spaghetti
  63.       </label>
  64.     </ons-list-item>
  65.  
  66.     <ons-list-item modifier="tappable">
  67.       <label class="checkbox checkbox--noborder checkbox--list-item">
  68.         <input type="checkbox">
  69.         <div class="checkbox__checkmark checkbox--noborder__checkmark checkbox--list-item__checkmark"></div>
  70.         Natto
  71.       </label>
  72.     </ons-list-item>
  73.   </ons-list>
  74. </ons-page>

この内容を書いたら、 gulp コマンドを実行します。そうすると8000番ポートでWebサーバが立ち上がるので、 http://localhost:8000/ にアクセスします。




チェックボックス一覧

チェックボックス一覧



プロフィール風画面を作る



同じようにbodyタグの内容を次のように変更します。



  1. <ons-page>
  2.   <ons-toolbar>
  3.     <div class="left"><ons-back-button>Back</ons-back-button></div>
  4.     <div class="center">Profile</div>
  5.     <div class="right">
  6.       <ons-toolbar-button><ons-icon icon="ion-gear-a" style="vertical-align: -4px; font-size: 28px;"></ons-icon></ons-toolbar-button>
  7.     </div>
  8.   </ons-toolbar>
  9.  
  10.   <div class="profile-card">
  11.     <img src="images/profile-image-01.png" class="profile-image">
  12.     <div class="profile-name">Dave Graham</div>
  13.     <div class="profile-id">@davegraham</div>
  14.     <div class="profile-desc">Freelance designer, software engineer and cyclist</div>
  15.   </div>
  16.  
  17.   <ons-list>
  18.     <ons-list-item>
  19.       <ons-row>
  20.         <ons-col class="info-col">
  21.           <div class="info-num">87</div>
  22.           <div class="info-unit">Comments</div>
  23.         </ons-col>
  24.         <ons-col class="info-col">
  25.           <div class="info-num">40</div>
  26.           <div class="info-unit">Following</div>
  27.         </ons-col>
  28.         <ons-col class="info-col">
  29.           <div class="info-num">38</div>
  30.           <div class="info-unit">Followers</div>
  31.         </ons-col>
  32.       </ons-row>
  33.     </ons-list-item>
  34.   </ons-list>
  35.  
  36.   <ons-list modifier="inset" style="margin-top: 10px">
  37.     <ons-list-item modifier="chevron">
  38.       Write a comment
  39.     </ons-list-item>
  40.     <ons-list-item modifier="chevron">
  41.       See details
  42.     </ons-list-item>
  43.     <ons-list-item modifier="chevron">
  44.       Save to the list
  45.     </ons-list-item>
  46.   </ons-list>
  47.   <br>
  48. </ons-page>


この場合は、別途スタイルシートが必要です。stylesheets/profile.cssなどとして次の内容でファイルを作成してください。また、HTML側でlinkタグを使って読み込み指定してください。



  1. .profile-card {
  2.   width: 100%;
  3.   text-align: center;
  4.   color: white;
  5.   padding: 30px 0;
  6.   line-height: 1.4;
  7.   background-color: #33393c;
  8.   text-shadow: rgba(0, 0, 0, 0.4) 0px 1px 0px;
  9. }
  10.  
  11. .profile-image {
  12.   height: 100px;
  13.   width: 100px;
  14.   border-radius: 50%;
  15.   -webkit-border-radius: 50%;
  16.   background-color: black;
  17.   border 1px solid white;
  18.   box-shadow:rgba(0, 0, 0, 0.2) 0px 2px 0px 0px;
  19.   -webkit-box-shadow:rgba(0, 0, 0, 0.2) 0px 2px 0px 0px;
  20. }
  21.  
  22. .profile-name {
  23.   margin: 20px 0 0 0;
  24.   font-weight: 600;
  25.   font-size: 17px;
  26. }
  27.  
  28. .profile-id {
  29.   margin: 0 0 5px 0;
  30.   font-size: 14px;
  31.   opacity: 0.6;
  32. }
  33.  
  34. .profile-desc {
  35.   font-size: 15px;
  36.   opacity: 0.6;
  37.   width: 90%;
  38.   text-align: center;
  39.   margin: 0 auto;
  40. }
  41.  
  42. .info-col {
  43.   height: 60px;
  44.   line-height: 1;
  45.   padding: 12px 0 12px 4px;
  46. }
  47.  
  48. .info-num {
  49.   font-size: 16px;
  50.   font-weight: 500;
  51.   opacity: 0.8;
  52. }
  53.  
  54. .info-unit {
  55.   margin-top: 6px;
  56.   font-size: 14px;
  57.   opacity: 0.4;
  58. }

後、こちらの画像をダウンロードして、 images/profile-image–01.png として保存してください。作業が完了すると、次のように表示されるはずです。




Onsen UIを使ったプロフィールページ

Onsen UIを使ったプロフィールページ



他にもサムネイル付きリストページのテンプレートパターンもあります。こういったデザインはブログやメディアサイトの記事一覧でも利用できるのではないでしょうか。




サムネイル付きリストページ

サムネイル付きリストページ






Onsen UIのアイコンはFont AwesomeやIoniconsを使えるようになっていますので、フラットUIなWebサイトを構築する際にも便利に使えます。よりスタイリッシュで高パフォーマンスなモバイルWebサイトを実現するためにOnsen UIをぜひご利用ください!



Onsen UI - A Custom Elements-Based HTML5 UI Framework | Onsen UI

Ajaxによるmultipart/postでの画像ファイルアップロード その3

$
0
0
こんにちは。内藤です。

前回
http://blog.asial.co.jp/1271
前々回
http://blog.asial.co.jp/1260
は、それぞれFormタグ、Cameraプラグインで画像を取得し、それをFormDataオブジェクトにBlobとして付与して、それをAjaxでサーバーにアップロードする方法について紹介しました。

今回は、FormDataではなく、手動でMultipart Postを生成してアップロードする方法について紹介します。FormDataは便利なのですが、Multipartの仕組みがすべてブラックボックス化されてしまっているため、内部の動作がよく分かりません。今回紹介する方法は、Multipartを自分で作成するため、他の言語で同様の機能を実装するのにも役立つかと思います。

かつては、JavaAppletなどでMultipart送信をするためによく使われた方法なのですが、最近ではあまり情報がないようなので、まとめてみました。


Multipartの基本的な仕組み


Multipartはもともと1つのメールに複数の添付ファイルを付与する方法を実現するために提唱されたもので、簡単にいうと、複数の添付ファイル(データ)を、boundaryと呼ばれる区切り文字で区切って、つなげたものをやり取りします。詳しくは
http://www.atmarkit.co.jp/ait/articles/0104/18/news002.html
などを確認してみて下さい。

WebのPostでもメールと同様に1回のPostに複数の添付ファイルを付与することが出来るようになっています。ただし、メールと異なる部分もあるので、注意が必要です。
http://www.ietf.org/rfc/rfc2616.txt
http://www.spencernetwork.org/reference/rfc2616-ja-HTTP1.1.txt
の19.4に、違いが記されています。特に、Content-Transfer-Encodingが利用出来ないことには注意です。このため、画像などは(base64ではなく)binaryとして送信する必要があります。

簡単なMultipartのサンプル


まずは、テキストのみでMultipartを実現する方法を確認してみます。

  1. function sendPost() {
  2.     var request = new XMLHttpRequest();
  3.     request.open("POST",'http://your.server.url',true);
  4.     var boundary = createBoundary();
  5.     request.setRequestHeader( "Content-Type", 'multipart/form-data; boundary=' + boundary );
  6.     var body = '';
  7.     body += '--' + boundary + '\r\n' + 'Content-Disposition: form-data; name="myfield"\r\n\r\n';
  8.     body += "hogehoge";
  9.     body += '\r\n';
  10.     body += '--' + boundary + '--';
  11.     request.send( body );
  12.     alert("send!");
  13.  
  14. function createBoundary() {
  15.     var multipartChars = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  16.     var length = 30 + Math.floor( Math.random() * 10 );
  17.     var boundary = "---------------------------";
  18.     for (var i=0;i < length; i++) {
  19.         boundary += multipartChars.charAt( Math.floor( Math.random() * multipartChars.length ) );
  20.     }
  21.     return boundary;
  22. }
  1. <div onClick="sendPost();">Click!</div>

こんな感じになります。これは、HTMLでいうと、次のものと同じになります。
  1. <form action="your.server.url" method="post" enctype="multipart/form-data">
  2.   <input type="text" name="myfield" />
  3.   <input type="submit" name="Send" />
  4. </form>

boundary文字列は、適当に作ったものなので、文字種と長さが正しければ、なんでも構いません。


画像をUploadする場合


 テキストと同じように、画像のUploadも出来るのですが、一つ大きな問題があります。
それは、画像がバイナリファイルであるため、テキストのように文字列オブジェクトで送ることが出来ないことです。

 メールの場合は、base64などのエンコードを行って添付することも出来るのですが、Webページでは先に記述したようにContent-Transfer-Encodingに対応していないため出来ません。

 そこで、ArrayBufferまたはUint8Array、Blobなどの形式で送ることが必要になります。これは、XHR2 (XmlHttpRequest 2)が必要となります。残念ながら、Android 2.3のストックブラウザはXHR2に対応していないので、この方法は利用出来ません。Android 2.3の場合、サーバー側でbase64エンコードしたファイルを扱うようにするか、もしくは、CordovaのFileTransferオブジェクトを利用して実現するのが良いと思います。

 話を元に戻して、XHR2が使える前提で考えてゆきます。例えば、sample.jpgという画像(wwwの直下の画像)をアップロードする場合、sendPost関数は次のようになります。

  1. function sendPost() {
  2.     
  3.     var oReq = new XMLHttpRequest();
  4.     oReq.open("GET","sample.jpg", true);
  5.     oReq.responseType = "arraybuffer";
  6.     oReq.onload = function(oEvent) {
  7.         var arrayBuffer = oReq.response;
  8.         console.log( "len = " +  arrayBuffer.byteLength );
  9.         
  10.         var request = new XMLHttpRequest();
  11.         request.open("POST",'http://your.server.url',true);
  12.         var boundary = createBoundary();
  13.         request.setRequestHeader( "Content-Type", 'multipart/form-data; boundary=' + boundary );
  14.         
  15.         var buffer = unicode2buffer( 
  16.             '--' + boundary + '\r\n' + 'Content-Disposition: forname="userfile"; filename="myimage.png"\r\n'
  17.                                      + 'Content-Type: image/jpeg\r\n\r\n'
  18.         );
  19.         
  20.         var buffer = appendBuffer( buffer , 
  21.             arrayBuffer
  22.         );
  23.         
  24.         var buffer = appendBuffer( buffer , 
  25.             unicode2buffer(
  26.                 '\r\n' + '--' + boundary + '--'
  27.             )
  28.         );
  29.         
  30.         request.send( buffer );
  31.         alert("send!");
  32.     }
  33.     oReq.send(null);
  34.     
  35. }
  36.  
  37. function unicode2buffer(str){
  38.  
  39.     var n = str.length,
  40.         idx = -1,
  41.         byteLength = 512,
  42.         bytes = new Uint8Array(byteLength),
  43.         i, c, _bytes;
  44.  
  45.     for(i = 0; i < n; ++i){
  46.         c = str.charCodeAt(i);
  47.         if(c <= 0x7F){
  48.             bytes[++idx] = c;
  49.         } else if(c <= 0x7FF){
  50.             bytes[++idx] = 0xC0 | (c >>> 6);
  51.             bytes[++idx] = 0x80 | (c & 0x3F);
  52.         } else if(c <= 0xFFFF){
  53.             bytes[++idx] = 0xE0 | (c >>> 12);
  54.             bytes[++idx] = 0x80 | ((c >>> 6) & 0x3F);
  55.             bytes[++idx] = 0x80 | (c & 0x3F);
  56.         } else {
  57.             bytes[++idx] = 0xF0 | (c >>> 18);
  58.             bytes[++idx] = 0x80 | ((c >>> 12) & 0x3F);
  59.             bytes[++idx] = 0x80 | ((c >>> 6) & 0x3F);
  60.             bytes[++idx] = 0x80 | (c & 0x3F);
  61.         }
  62.         if(byteLength - idx <= 4){
  63.             _bytes = bytes;
  64.             byteLength *= 2;
  65.             bytes = new Uint8Array(byteLength);
  66.             bytes.set(_bytes);
  67.         }
  68.     }
  69.     idx++;
  70.     
  71.     var result = new Uint8Array(idx);
  72.     result.set(bytes.subarray(0,idx),0);
  73.     
  74.     return result.buffer;
  75. }
  76.  
  77.  
  78. function appendBuffer(buf1,buf2) {
  79.     var uint8array = new Uint8Array(buf1.byteLength + buf2.byteLength);
  80.     uint8array.set(new Uint8Array(buf1),0);
  81.     uint8array.set(new Uint8Array(buf2),buf1.byteLength);
  82.     return uint8array.buffer;
  83. }

Stringではなく、ArrayBufferとしてContentを結合してゆきます。
なお、サーバー側のコードは、以前
http://blog.asial.co.jp/1260
と同じです。

Formのように画像を選択せずに、直接、ファイルをアップロードすることが出来ます。

Android 2.3への対応


先にも述べたように、XHR2に対応していないAndroid 2.3では、上記の方法は使えません。
http://blog.asial.co.jp/1313
では、Android 2.3用にArrayBufferやUint8Arrayクラスを作成しましたが、これは、あくまでCordovaを騙してArrayBufferやUint8Arrayがあるように見せかけるためのクラスなので、ブラウザの標準機能のみで実装する場合は、この方法は使えません。

そこで、ここでは簡単にFileTransferプラグインを利用する方法を示します。

上記と同様の処理を実現するためには、

  1. function sendPost6() {
  2.     var oReq = new XMLHttpRequest();
  3.     oReq.open("GET","sample.jpg", false);
  4.     oReq.overrideMimeType('text/plain; charset=x-user-defined');
  5.     oReq.onload = function(oEvent) {
  6.         var response = oReq.responseText;
  7.         var length = response.length;
  8.         console.log( "length = " + length);
  9.         
  10.         var array = new Array();
  11.         for (var i=0;i<length;i++) {
  12.             array.push(  response.charCodeAt(i) & 0xff );
  13.         }
  14.         var uint8array = new Uint8Array( array );
  15.         var b64data = b64utils.encode( uint8array );
  16.         var imageUrl = "data:image/jpeg;base64," + b64data;
  17.         var options = new FileUploadOptions();
  18.         options.fileKey = "userfile";
  19.         options.fileName = "myimage.png";
  20.         var ft = new FileTransfer();
  21.         ft.upload( imageUrl , encodeURI("http://your.server.url"), 
  22.           function() { alert("success!"); },
  23.           function() { alert("fail!"); }  ,
  24.           options );
  25.         
  26.     }
  27.     oReq.send(null);
  28. }

のようになります。

ここで、Uint8Arrayやb64utilsは、
http://blog.asial.co.jp/1313
で使ったものと同じものです。

ローカルのsample.imgを読み込むときも工夫していることに注意して下さい。
http://www.html5rocks.com/ja/tutorials/file/xhr2/
に述べられていますが、XHR1でバイナリファイルを読み込むために事実上標準的に用いられる方法です。

この場合、1バイトが(UTF8の)1文字として格納されますが、当然、UTF8の1文字は1バイトとは限らないので、1文字ずつ取り出して0xffで和をとり、array型に代入しています。
それから、Uint8Array型に変換しているのは、以前のサブルーチンを再利用するためだけなのですが、b64utilsを使って、base64化し、データスキームでURLを作ります。
あとは、FileTransferでアップロードを行えば、完了です。


まとめ


Ajaxによるmultipart/postでの画像ファイルアップロードについて紹介しました。
これと、CordovaのFile APIを使うと、画像ファイル(バイナリファイル)の取り回しが自由になります。
ぜひ、アプリ開発の参考にして下さい。

おまけ


UTF8の文字列と、そのバイト表現についての対応を記載しておきます。

1文字cが

c <= 0x7F の場合 
1バイト表現 
1バイト目 0xxxxxxx

0x7F < c <= 0x7FF の場合
2バイト表現
1バイト目 上位5ビット 110xxxxx
2バイト目 下位6ビット 10xxxxxx

0x7FF < c <= 0xFFFF の場合
3バイト表現
1バイト目 上位4ビット 1110xxxx
2バイト目 中位6ビット 10xxxxxx
3バイト目 下位6ビット 10xxxxxx

0xFFFF < c <= 0x1FFFFF の場合
4バイト表現
1バイト目 上位3ビット 11110xxx
2バイト目 中上位6ビット 10xxxxxx
3バイト目 中下位6ビット 10xxxxxx
4バイト目 下位6ビット 10xxxxxx

Onsen UI を使用して、HTML5ハイブリッドアプリを作ってみよう

$
0
0
今回の記事は、Onsen UI blogで2月に公開した"Creating Google Maps Sample App with AngularJS and Onsen UI"の翻訳記事です。

ハイブリッドアプリ開発のお話を、最近はあちらこちらで耳にするようになりました。プログラム知識が乏しい初心者マークの方、手っ取り早くアプリを開発したい方には、ネイティブアプリ開発のハードルは、高いのが現状です。ネイティブアプリを開発するためには、各プラットフォーム専用のプログラム言語を学び、かつ、開発対象の端末側の機能も学ぶ必要があります。
もちろん、パフォーマンスが良い、端末側のリソースが利用できるなど、ネイティブアプリの開発にも、利点はたくさんあります。



一方、ハイブリッドアプリで使用するテクノロジーは、Web アプリで使用するもの ( HTML、CSS、JavaScript ) と同様であり、プラットフォームには依存しません。Web アプリのテクノロジーに関するノウハウは、膨大で、かつ、簡単に、インターネットから入手できます。
また、ハイブリッドアプリの開発時には、Web 開発で使用していたツールやフレームワークを、そのまま流用できます。jQuery や AngularJS が良い例です。よって、Web アプリ開発者も、ハイブリッドアプリ開発に転向しやすいのではないでしょうか。
ハイブリッドアプリは、ネイティブアプリよりも性能が劣ると、一般的に思われていますが、以前よりもパワフルになった、現在の端末では、ユーザーがその差に気付くことはありません。

ここでは、ハイブリッドアプリのサンプルとして、メモ帳アプリを構築し、併せて、Onsen UIの使用方法も学びます。Onsen UI を使用すれば、洗練されたユーザーインターフェイス ( UI ) を簡単に構築できます。また、アプリの開発には、Monaca クラウド IDEを使用します。Monaca クラウド IDE は、Onsen UI をサポートし、かつ、デバッガーも実装されています ( 機能制限なしの無料アカウントを、こちらで作成できます )。Monaca クラウド IDE 上では、アプリの確認・修正を行え、実機上では、アプリの確認を行えます。こちらから、無料で、端末用のデバッガーを入手できます。また、アプリ開発に不慣れな方でも、アプリへのプラグインのインポート、デバッグ、ビルドは、Monaca 側で行ってくれるので安心です。他の IDE を使用する場合には、必要なプラグインを手動で組み込んでください。

Onsen UI と AngularJS



Onsen UI は、HTML5 フレームワークです。Onsen UI を使用すれば、モダンで、見栄えのするユーザーインターフェイスを作成できます。これにより、UI 開発に費やしていた時間を縮小でき、
その分、アプリ本体の性能・機能の充実に、時間を充てることができます。Onsen UI は、AngularJS の使用を前提に設計されていますが、jQuery や他のフレームワークとも併用できます。ここでは、AngularJS を使用しますが、Onsen UI に焦点を当てるため、AngularJS に関しては、込み入った箇所のみ、解説します。

ここで作成するアプリは、メモ帳アプリです。このアプリでは、作業の一覧の保存、作業カテゴリー別のソート、作業詳細の編集・削除を行います。以下の Onsen UI コンポーネントを使用して、アプリを構築します。


  • ons-navigator

  • ons-toolbar

  • ons-sliding-menu

  • ons-list

  • ons-carousel

  • ons-template

  • ons-popover



これらのコンポーネント ( 要素 ) の使用方法も、順次、解説します。スライディングメニュー表示を行うページを指定したり、または、カルーセルを使用して、複数ある表示用コンテンツをまとめるなど、表示機能のオプションも充実しています。Onsen UI コンポーネントのドキュメントは、こちらでご確認ください。また、こちらも併せてご確認ください。

ここでは、Onsen UI 1.2.1 を使用します。Monacaをご利用の方は、ダッシュボードに表示されている 「 Onsen UI 最小限のテンプレート 」 を開いてください。このテンプレートでは、AngularJS は、ライブラリーとして、デフォルトで組み込まれています。Monaca を利用しない場合には、Onsen UI のドキュメントを確認して、必要なライブラリーを組み込んでください。

最初に、このアプリにおける、AngularJS の取り扱い方法を解説します。AngularJS では、アプリを構成する各ページまたはメインとなる各要素 ( ) に、それぞれ、1 個のコントローラーを紐付けます。コントローラーでは、紐付けされたページで使用するスコープ ( Scope ) の定義、および、必要な変数と関数の定義を行います。
たとえば、登録した作業の一覧をメインページに表示する場合、メインページ用のコントローラーを作成して、スコープを定義して、作業データを格納した配列を、そのスコープに代入する処理を行います。また、このコントローラー内に、配列データの編集・削除用の関数なども置けます。しかし、作業別にコントローラーを作成して、処理を行った方が良い場合もあります。このサンプルアプリでは、使用しているページの役割がそれぞれ異なるため、処理を分け、データのみ、コントローラー間で共有します ( 作業の 「 登録 」 ページ、「 詳細表示 」 ページなど、処理は異なりますが、いずれも作業詳細のデータを共有します )。



よって、データ共有の際には、コントローラー間の交信が必要となります。このアプリでは、serviceを 1 個使用して、登録済み作業の保存、および、コントーラー間で共通する処理の制御を行います。このようにすることで、各コントローラーから、必要に応じて、この service を呼び出せます。
登録された作業と作業一覧は、オブジェクトであり、models/Memo.js 内で定義されています。各作業のオブジェクトには、必要な情報 ( 名前、カテゴリー、説明、作成日、進捗状態 ) が格納されます。このような設計 ( model ディレクトリーの設置とオブジェクトの定義 ) になっていますが、これは、Onsen UI 使用時のお手本ではなく、一例ですので、設計は、開発者が自由に行ってください。サンプルコードは、GitHub から入手できます。

前置きが長くなりました。ここからは、実際にコードを確認してみましょう。

メモ帳アプリのコード

このアプリのコードは、GitHubから入手できます。不明確な点がある場合には、コードの中をご確認ください。また、コードを確認する前に、以下で、アプリを実際に操作してみましょう。



スタイルとデザインは、自由に、カスタマイズできます。

デザインとコード

Onsen UI 要素と起動時のページ

Onsen UI では、メインとなる要素は、1 つに絞ることを推奨します。このメインの要素は、アプリの 「 型 ( pattern ) 」となり、ページ制御に適用・使用されます。
たとえば、ページ遷移の制御を行うなら、スライディングメニュー型、タブバー型などがあります。ここでは、最も頻繁に使用されるナビゲーション型を使用します。この型を使用すると、親子関係がページ間に設定されます ( つまり、スタック内にページが置かれ、それぞれを行き来します )。
よって、ここでは、ons-navigator を、メインの要素として、index.html に置きます。

  1. <ons-navigator var="myNavigator">
  2.   <ons-page>
  3.     <ons-toolbar fixed-style>
  4.       <div class="center">Memo Onsen UI App Example</div>
  5.     </ons-toolbar>
  6.         <div style="margin: auto; width: 95%;">
  7.           <div class="margins">
  8.             <span style="color:#666"><ons-icon icon="fa-check-square-o" size="22em"></ons-icon></span>
  9.           </div>
  10.         </div>
  11.     <ons-button modifier="large--cta" onclick="myNavigator.resetToPage('slidingmenu.html')">Start</ons-button>
  12.   </ons-page>
  13. </ons-navigator>

var=”myNavigator” を指定して、ナビゲーター ( ons-navigator ) の名前を宣言します。これにより、グローバル変数として、後々、名前で参照できます。ナビゲーター内では、ons-page を使用して、起動時のページを指定します。このページ上では、ons-toolbar を使用して、アプリのタイトルを表示します。

Tip 1 : class=”center” を使用して、タイトルを設定しても、アプリを実行する OS 側が、スタイルを決定します。iOS では、中央揃えとなり、Android では、左揃えとなります。タイトルを中央に固定する場合には、ons-toolbar 内で、fixed-style を設定します。

表示イメージは自由に設定できますが、ここでは、ons-icon を使用して、アイコンを表示します。Onsen UI では、IoniconsFontawesomeのアイコンも使用でき、どの端末上でも支障なく表示できます。アプリ起動時のページで使用する最後の要素は、スタートボタンです。スタートボタンをクリックすると、アプリのメインページに遷移します。ここでは、ボタンに関しては、ons-button を使用して、また、アプリの外見の選択に関しては、modifierを使用します。ボタンのクリック時、ナビゲーターが、ページを遷移させます。ここでは、pushPage( … ) の代わりに、resetToPage( … ) を使用して、前のページをスタックからすべて削除して、slidingmenu.html 内で指定されているページを表示します ( 0 から開始 )。このような処理をすることで、メインページに遷移した後、戻るボタンを押しても、起動時のページに戻ることはありません。

メニュー

メインページを解説します。こちらのメインページ上で、アプリに登録された作業の一覧が表示されます。スライディングメニューをこのページ上に置くので、メインページの親として、このメニューの要素を設定します。slidingmenu.html を作成して、このページ上に、スライディングメニュー本体を設定します。Onsen UI では、テンプレート ( ons-template ) を使用すれば、index.html 内に、別の HTML ページを作成して、配置でき、通常の HTML と同様に動作します。各 HTML のページがコンパクトであれば、1 ページ上にすべてのページが収まります。

  1. <!-- SLIDING MENU -->
  2. <ons-template id="slidingmenu.html">
  3.   <ons-page>
  4.     <ons-sliding-menu var="slidingMenu" swipeable="false" menu-page="menu.html" main-page="memo.html"  side="left" type="overlay" max-slide-distance="200px">
  5.     </ons-sliding-menu>
  6.   </ons-page>
  7. </ons-template>
ons-sliding-menu を使用して、menu-page=”menu.html” から、メニュー用コンテンツを取得します。また、スライディングメニューは、main-page=”memo.html” 上に表示されます。ここでは、作業一覧に設定されているカルーセルの誤作動を避けるため、swipeable=”false” にします。

menu.html の内容を見てみましょう。

  1. <!-- MENU -->
  2. <ons-template id="menu.html">
  3.   <ons-page fixed-style style="background-color: white">
  4.     <ons-toolbar fixed-style>
  5.       <div class="center">Categories</div>
  6.       <div class="right" style="margin-top:5px"><ons-button modifier="quiet" ng-click="slidingMenu.closeMenu()"><ons-icon icon="fa-chevron-left" size="25px" fixed-width="false" style="color: #5087c3"></ons-icon></ons-back-button></div>
  7.     </ons-toolbar>
  8.  
  9.         <!-- List of items -->
  10.     <ons-list id="categoryList" ng-controller="categoryController">

こちらは、ons-list-item の静的な部分です。

  1. <ons-list-item
  2.     modifier="tappable" class="list__item__line-height"
  3.     ng-click="setViewRefresh('*'); slidingMenu.closeMenu();">
  4.     <i class="ion-home fa-lg" style="color: #666"></i>
  5.     &nbsp; All
  6.     <span class="item-label">{{countAll}}</span>
  7.   </ons-list-item>
  8.   <ons-list-item
  9.     modifier="tappable" class="list__item__line-height"
  10.     ng-click="setViewRefresh('~'); slidingMenu.closeMenu();">
  11.     <i class="ion-checkmark" style="color: #666"></i>
  12.     &nbsp; Completed
  13.     <span class="item-label">{{completedCount ? completedCount : 0}}</span>
  14.   </ons-list-item>
  15.   <ons-list-header>
  16.     <div style="text-align: center;"><ons-icon icon="ion-minus-round"></ons-icon></div>
  17.   </ons-list-header>
  18.   <ons-list-item
  19.     modifier="tappable" class="list__item__line-height"
  20.     ng-click="setViewRefresh('=', ' '); slidingMenu.closeMenu();">
  21.     <i class="ion-qr-scanner fa-lg" style="color: #666"></i>
  22.     &nbsp; No category
  23.     <span class="item-label">{{countCategories[' '] ? (countCategories[' '].total - countCategories[' '].completed) : 0}} ({{countCategories[' '] ? countCategories[' '].total : 0}})</span>
  24.   </ons-list-item>

こちらは、ons-list-item の動的な部分です ( AngularJS の ng-repeat を使用 )。

  1. <ons-list-item
  2.         modifier="tappable" class="list__item__line-height"
  3.         ng-click="setViewRefresh('=', item); slidingMenu.closeMenu();" ng-repeat="item in categoryList">
  4.         <i class="ion-folder fa-lg" style="color: #666"></i>
  5.         &nbsp; {{item}}
  6.         <span class="item-label">{{countCategories[item].total - countCategories[item].completed}} ({{countCategories[item].total}})</span>
  7.       </ons-list-item>
  8.     </ons-list>
  9.   </ons-page>
  10. </ons-template>

ons-template を使用しているので、こちらも index.html 内に置けます。また、ons-toolbar を使用して、メニューのタイトルと閉じるボタンを設定しています。このメニューでは、作業に紐付けされたカテゴリーに応じて、該当する作業を一覧化します。
カテゴリー一覧の内容は、ng-controller="categoryController" から取得します。静的な部分には、3 つの固定メニューがあります ( すべて表示、完了した作業を表示、未カテゴリーの作業の表示 )。こちらは、メニューの例なので、自由に編集してください。

固定メニューの表示後に、AngularJS の ng-repeat を使用して ( 最後の ons-list-item を参照 )、ons-list-item を繰り返します。この設定で、すべてのカテゴリーを、メニュー上に表示できます。また、ここでは、各カテゴリーに該当する作業数を表示するため、categoryController から、その情報を取得します。このサンプルでは、countAll と呼ぶカウンター変数を使用して、メモ帳アプリ内に登録されている作業の総数を取得します。この変数は、service ( memoService ) 内に置かれ、コントローラー経由で変更 ( 作業の登録・削除時 ) できます。また、ここでは、categoryController 内に、この変数に対して、リスナーを設定します。これにより、作業数に変更があれば、AngularJS 側で、自動的に値を更新してくれます ( View の更新 )。

  1. $scope.$watch(function() {
  2.   return memoService.countRawMemo();
  3. }, function(newValue) {
  4.   $scope.countAll = newValue;
  5. }, true);

categoryController の setViewRefresh(...) メソッドを使用して、表示内容を変更します ( View の更新 )。

メインページ

メインページ ( memo.html ) の内容を確認しましょう。ここで、登録済み作業が一覧化されます。

  1. <ons-page ng-controller="memoController">
  2.   <ons-toolbar fixed-style ng-controller="slidingMenuController">
  3.     <div class="left"><ons-toolbar-button ng-click="slidingMenu.openMenu(); checkSlidingMenuStatus();"><ons-icon icon="bars"></ons-icon></ons-toolbar-button></div>
  4.     <div class="center">My tasks</div>
  5.     <div class="right">
  6.       <ons-button modifier="quiet" onclick="myNavigator.pushPage('additem.html')">
  7.           New <ons-icon icon="fa-plus-circle "></ons-icon>
  8.       </ons-button>
  9.     </div>
  10.   </ons-toolbar>

作業を一覧化します。カルーセル表示 ( 各作業の表示時 ) を使用します。

  1. <ons-carousel-item class="list-action-menu">
  2.           <!-- ACTIONS -->
  3.           <div class="main-container">
  4.             <div class="fixer-container">
  5.               <div class="blockInline">
  6.                 <ons-button ng-click="deleteItem($index); carousel['id'+$index].setActiveCarouselItemIndex(1);">
  7.                   Delete
  8.                   <ons-icon icon="ion-trash-a"></ons-icon>
  9.                 </ons-button>
  10.               </div>
  11.               <div class="blockInline">
  12.                 <ons-button ng-click="carousel['id'+$index].setActiveCarouselItemIndex(1); completeItem($index);" ng-hide="item.completed">
  13.                   Complete
  14.                   <ons-icon icon="ion-checkmark-round"></ons-icon>
  15.                 </ons-button>
  16.               </div>
  17.               <div class="blockInline">
  18.                 <ons-button ng-click="setSelected($index); myNavigator.pushPage('itemdetails.html');">
  19.                   Details
  20.                   <ons-icon icon="ion-clipboard"></ons-icon>
  21.                 </ons-button>
  22.               </div>
  23.             </div>
  24.           </div>
  25.         </ons-carousel-item>

カルーセルのインデックス番号 0 には、3 つの処理 ( 3 つのボタン ) を設定します。

  1. <ons-carousel-item class="list-action-item" ng-click="setSelected($index); myNavigator.pushPage('itemdetails.html');">
  2.           <div class="name">
  3.             {{item.name}} <span class="desc"><ons-icon icon="ion-checkmark-round" ng-show="item.completed"></ons-icon></span>
  4.           </div>
  5.           <div class="desc">
  6.             {{item.date.getFullYear() + "/" + (item.date.getMonth() + 1) + "/" + item.date.getDate()}}
  7.           </div>
  8.         </ons-carousel-item>
  9.       </ons-carousel>
  10.     </ons-list-item>
  11.     </ons-list>
  12. </ons-page>

カルーセルのインデックス番号 1 には、作業詳細の表示設定をします。


このページは、重要で、大きいため、ons-template を使用して、index.html 内に置くのではなく、別個のページを用意します。index.html 内に、まとめて置く場合には、上述したスライディングメニューなど、比較的、短い記述に限定します。いずれの場合でも、ons-toolbar を使用して、
タイトル、新規のページへのリンク ( additems.html の説明は後ほど )、スライディングメニューの表示ボタンを設定します。

Tip 2 : スライディングメニューに設定してある、ちょっとした作り込みをご紹介します。スライディングメニューは、表示されているときだけ、スワイプでき、非表示のときは、スワイプ不可になっています。これにより、作業一覧に組み込まれたカルーセルと衝突しません。ここでは、スライディングメニューの動作を変更するため、以下のように、2 つのイベントを用意します。

  1. myApp.controller('slidingMenuController', function($scope){
  2.    $scope.slidingMenu.on('postclose', function(){ $scope.slidingMenu.setSwipeable(false); });
  3.    $scope.slidingMenu.on('postopen', function(){ $scope.slidingMenu.setSwipeable(true); });
  4. });

また、表示する作業がない場合には、ng-hide を使用して、メッセージを表示します。また、ons-list を動的に使用して、かつ、ons-list 内の item ( ons-list-item ) 毎に、ons-carousel 設定を行って、作業の一覧を表示します。ここでは、ng-repeat を使用して、memoController 側から受け取った、作業を一覧表示します。また、各作業 ( ons-list-item ) には、ons-carousel が設定されています。カルーセルには、インデックス番号 ( 0、1 ) があり、1 には作業詳細、0 には処理ボタン ( ons-carousel-item ) を設定しています。作業一覧の表示時には、インデックス番号 1 の内容が表示され、右方向へスワイプすると、0 の内容が表示されます。

Tip 3 : インデックス番号 0 のボタンの縦位置・横位置は、その数に関わらず、中央揃えになります。



CSS の記述を、以下に記します。

  1. .main-container {
  2.     float: left;
  3.     position: relative;
  4.     left: 50%;
  5. }
  6.  
  7. .fixer-container{
  8.     float: left;
  9.     position: relative;
  10.     left: -50%;
  11. }
  12.  
  13. .blockInline{
  14.     margin-left: 3px;
  15.     margin-right: 3px;
  16.     display: inline;
  17.     position: relative;
  18.     top: 50%;
  19.     transform: translateY(-50%);
  20. }

作業一覧から、作業を削除する場合は、memoController 内に記述された、削除用の関数を実行します。また、作業内容の変更や作業完了のマーク付けも、対応する関数を実行して行います。作業完了の処理を行う関数では、作業一覧の再表示時に、完了作業の横に、チェックマークアイコンを表示するように、かつ、インデックス番号 1 の内容を表示するように、「 対応する 」 カルーセルを更新しています。

Tip 4 : カルーセルを更新して、表示を元に戻すには、一覧上のカルーセル毎に、一意の名前を、動的に割り振ります。これにより、後から、その名前を参照でき、また、インデックス番号も更新できます ( よって、上述の 「 対応する 」 カルーセルを更新できます )。ここでは、var="{{'carousel.id' + $index}}" を使用して、carousel.idX 形式で、カルーセルに名前を割り振ります。この X は、ons-list 内の item ( ons-list-item ) のインデックス番号です。静的な方法 ( 例 : var=”myCarousel” ) で、item ( ons-list-item ) の名前を振った場合、ng-repeat 下では、旧 item ( ons-list-item ) の名前がすべて上書きされ、よって、myCarousel を使用して呼び出せるのは、最後の item だけになってしまいます。また、setActiveCarouselItemIndex(1) 関数を呼び出す際には、carousel['id'+$index].setActiveCarouselItemIndex(1); のように、ドット記法ではなく、ブラケット記法を使用します。

作業詳細の表示と変更

作業詳細の表示と変更に関して、解説します。itemdetails.html の内容を見てみましょう。ここでは、コントローラーを 1 つ設定しています。

  1. <ons-page ng-controller="detailsController">
  2.   <ons-toolbar fixed-style>
  3.     <div class="left"><ons-back-button>Back</ons-back-button></div>
  4.     <div class="center"> Task details </div>
  5.         <div class="right">
  6.       <ons-button modifier="quiet" ng-click="modifyItem();">
  7.       Save <ons-icon icon="ion-checkmark"></ons-icon>
  8.       </ons-button>
  9.         </div>
  10.   </ons-toolbar>
  11.   <div style="text-align: center">
  12.     <br />
  13.     <ons-list id="itemList">
  14.       <ons-list-item class="item">
  15.         <ons-row>
  16.           <ons-col width="60px">
  17.             <div class="item-thum"></div>
  18.           </ons-col>
  19.           <ons-col>
  20.             <header>
  21.               <span id="item-name" class="item-name"><input type="text" ng-model="item_name" placeholder="Name" class="text-input text-input--transparent" style="margin-top:8px; width: 100%;"></span>
  22.               <span id="item-category" class="item-name"><input type="text" ng-model="item_category" placeholder="Category" class="text-input text-input--transparent" style="margin-top:8px; width: 100%;"></span>
  23.               <span id="item-description" class="item-name"><textarea type="text" ng-model="item_description" placeholder="Description"  class="textarea textarea--transparent" style="margin-top:8px; width: 100%;"></span>
  24.             </header>
  25.           </ons-col>
  26.         </ons-row>
  27.       </ons-list-item>
  28.     </ons-list>
  29.   </div>
  30. </ons-page>

このページは、myNavigator.pushPage( … ) を使用して、メインページから呼び出されます。myNavigator.pushPage( … ) が行う処理は、ons-navigator 内のスタックへ、新たなページを追加することです。追加後は、myNavigator.popPage() または ons-back-button を使用すれば、スタックに置かれている、前のページに戻れます。

このページ上では、指定された作業の内容を、HTML の input 内に表示します。HTML の input を使用することにより、表示と同時に、変更も行えます。また、各 input には、ng-model を設定 ( 紐付け ) して、コントローラーから新しい値を参照できるようにします。たとえば、ここでは、作業名と ng-model=”item_name” を紐付けして、detailsController 内から、$scope.item_name を使用して、作業名を参照しています。

新規作業の追加とポップアップ表示



新規作業の追加処理は、additem.html で行います。非常に簡単な処理です。前述のように、HTML の input と ng-model の紐付けを行い、addItemController 内で、入力値を確認した後、memoService の作業一覧へ新規作業を追加します。
また、ここでは、名前用の input が未入力の場合、警告を出し、新規作業の作成を行えないようにします。この処理を行う場合、最初に、index.html 内に、ポップアップ ( ons-popover ) を、以下のように追加します。

  1. <!-- POPOVER -->
  2. <ons-template id="popover.html">
  3.   <ons-popover direction="up down" cancelable>
  4.     <div style="text-align: center; opacity: 0.5;">
  5.       <p>Name input is empty!</p>
  6.       <p><small>Enter a name for your task to create or modify it.</small></p>
  7.     </div>
  8.   </ons-popover>
  9. </ons-template>

次に、addItemController と detailsController のコントローラーから、変更の保存時に、ポップアップを呼び出せるように処理します。

  1. ons.createPopover('popover.html').then(function(popover) {
  2.   $scope.popover = popover;
  3. });
  4. $scope.popover.show('#item-name');

最後の行では、HTML 要素 の '#item-name' 上に、ポップアップを表示します。ここでは、input が未入力の場合に、ポップアップを表示しますが、表示のタイミングは、制御する必要があります。

備考

ここで使用したサンプルアプリでは、Onsen UI と AngularJS に焦点を当てたため、window.localStorage、Web SQL、IndexedDB などを使用した、データの保存方法に関しては、触れていません。もちろん、実装できますが、ここでは、固定のサンプルデータを使用して、アプリの動作を即検証できるようにしています。

結論

ここでは、Onsen UI が提供してくれる、使えるユーザーインターフェイスを使用して、簡単なハイブリッドアプリを開発しました。また、開発に役立つ Tip も併記しました。AngularJS の使用は、必須ではありませんが、Onsen UI と相性が良いため、使用した方が効率が良くなります。前述のように、ここで使用したコードは、GitHub上に置いてありますので、自由に、触ってみてください。

以上ですが、開発を簡単にしてくれる、Onsen UI のようなツールがあれば、ハイブリッドアプリの開発も難しくはありません。質問がある方は、このブログにコメントを残すか、スタックオーバーフロー ( onsen-ui タグ下 )に寄稿してください。Onsen UI の使用例に関しては、今後もブログにアップしていく予定です。
Viewing all 298 articles
Browse latest View live