アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

App Storeの新基準 (iOS 8、64bitサポート義務) に対するMonacaの対応につきまして

平素より、Monacaをご利用いただきありがとうございます。

この度Apple社より発表があり、2015年2月1日よりApp Storeで配布するアプリについて「64bit対応」およびiOS 8対応」の2つが要件として義務づけられます。



詳細を見る (英語)


Monacaでは現状「Cordova3.5形式のプロジェクトであること」およびXcode 6でビルドすること」という2つの条件を満たすことによって、App Storeで新たに定められる2つの要件に対応することが可能でございます。

下記に、App Storeの新しい要件に対応するための2つの方法を記載致します。

1: Cordova 3.5形式であることの確認方法
2: Xcode 6でビルドを行うための設定方法




1: Cordova 3.5形式であることの確認方法


Monacaダッシュボードを開いていただき、プロジェクト名の右下にある「歯車のマーク」をクリックします。


そこで「新しい形式に変換」というメニューが現れない場合、そのプロジェクトはCordova3.5形式のプロジェクトです。「新しい形式に変換」というメニューがある場合、そのプロジェクトはCordova2.9形式のプロジェクト (Appleの新要件に未対応) です。



※ 画像はCordova2.9形式の場合です。


※ Cordova2.9形式のプロジェクトの場合「新しい形式に変換」というメニューをクリックすることで、3.5形式へのアップデートが可能です。2.9から3.5にアップデートする際は必ずプロジェクトのコピーを行い、バックアップを取ってから行ってください。2.9から3.5へのアップデートに伴う機能変更に関してはこちらの記事をご覧ください。







2: Xcode 6でビルドを行うための設定方法


Monaca IDEでプロジェクトを開き上部メニューの「設定」から、iOSアプリ設定」をクリックします。



「その他」Xcodeバージョン」のセレクトボックスから「バージョン6」を選択した後、ページ下部の「保存する」ボタンをクリックして設定を保存します。上記手順でプロジェクトがXcode 6のビルドシステムでビルドされるように設定されます。









Cordova 2.9形式でのApp Store新基準への対応につきまして


Cordova2.9形式のプロジェクトでApp Storeの新基準に対応可能かどうかは現在、調査中でございます。

何卒よろしくお願い申し上げます。

Monacaデバッガーの種類と使い分けについて

7月31日のリニューアルにより、利用可能なデバッガーの種類が増えました。ここでは、それぞれのデバッガーの特徴と役割についてまとめさせていただきます。

App Store/Google Playストア版とカスタムビルド版デバッガー



 7月31日より、新規で作成されるプロジェクトはCordova 3.5フレームワークにアップデートされました(過去のプロジェクトはCordova 2.9で動作します)。詳細につきましては、こちらの記事を参考にしてください。

 App Store/Google Playストア版デバッガーは、それぞれApp Store/Google Playストアからダウンロードしてすぐに利用が可能です。ストアに公開されるものはバージョンが3.0にアップグレードされ、Cordova 3.5フレームワークが搭載されています。なお、Android用はすでにGoogle Playから提供が開始されておりますが、iOS用は申し訳ありませんが、審査中となっておりますので、後述するカスタムデバッガーをお使い頂きますようお願いいたします。

 このデバッガーを使ってCordova 2.9用のプロジェクトを実行しようとすると、警告が表示されます。Cordova 2.9用のプロジェクトでも無視して実行することは可能ですが、細かい挙動が異なることから期待通りに動かない可能性があります。

 ストア版デバッガーは、下記の注意点があります。
  • Monaca Backendから送られるプッシュ通知を受けることが出来ます。
  • Monacaの標準Cordovaプラグイン以外は組み込まれていません

 カスタムデバッガーには、Cordova 2.9版とCordova 3.5版があります。カスタムデバッガーは、ストア上には掲載されておらず、IDEからインストールできるデバッガーです。ただし、iOS版は証明書が必要になるため、Apple Developer Centerのアカウントが必要となります。

 カスタムデバッガーは、それぞれCordova 2.9用または3.5用のプロジェクトを実行出来ますが、Monaca BackendのPush通知には対応していません。Professionalプラン以上のユーザーの方は、カスタムCordovaプラグインの組み込みにも対応いたしました。

 以上をまとめると、現在配布しているMonacaデバッガーの一覧と特長は以下の表のようになります。

バイスデバッガー特徴
iOSバージョン3.0(App Store版)※現在、申請審査中
Cordova 3.5ベース
Push通知を受け取れる
カスタムプラグインは追加不可
バージョン3.0(カスタムビルド版)Cordova 3.5ベース
ビルドが必要
Push通知を受け取れない
カスタムプラグインを追加可能(Professionalプラン以上)
バージョン2.3(カスタムビルド版)Cordova 2.9ベース
ビルドが必要
Push通知を受け取れない
Androidバージョン3.0(Google Playストア版)Cordova 3.5ベース
すぐに利用が可能
バージョン3.0(カスタムビルド版)Cordova 3.5ベース
ビルドが必要
Push通知を受け取れない
カスタムプラグインを追加可能(Professionalプラン以上)
バージョン2.9(カスタムビルド版)Cordova 2.9ベース
Push通知が受け取れない


Android用ハイパフォーマンス版デバッガー


 さらに、Cordova 3.5版Androidデバッガーには、通常版とハイパフォーマンス版の2種類が種類が存在します。

 ハイパフォーマンス版は、ベータ版という扱いではありますが、下記の特徴があります。
 

JS/CSSコンポーネントとloader.jsについて

新しいJS/CSSコンポーネント



6/28に行われたMonacaのアップデートにより、以前は


<script src="plugins/plugin-loader.js"></script>
<link rel="stylesheet" href="plugins/plugin-loader.css">


のように記述してきた部分が


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

のように変わりました。

 これは、単純に記載方法が変更されたのではなく、仕組みそのものが大幅に変更されたためです。

 アップデート前のplugin-loader.jsも、アップデート後のloader.jsも、どちらも、IDEで設定したプラグイン・JS/CSSコンポーネントJavaScriptファイルを、一度に読み込むという機能を持っています。

 その違いについて、説明させていただきます。

プラグインとJS/CSSコンポーネントの機能の分離



 まず、6/28のリニューアルに伴い、これまで「プラグイン設定」として用意されていた機能が、「JS/CSSコンポーネントの追加と削除」「Cordovaプラグインの管理」の2つの機能に分離しました。



 「JS/CSSコンポーネント」とは、JavascriptCSSだけで記述されたコンポーネント(モジュール)で、例えば、jQueryやOnsen UIなどです。以前は、予め用意された10数個プラグインからしか選べませんでしたが、新しい「JS/CSSコンポーネント」では、後述するように、Bowerリポジトリに登録されているJavascript/CSSを自由に組み込むことが出来ます。

 「Cordovaプラグイン」の方は、BarcodeScannerやChildBrowser、あるいはそれ以外のカスタムCordovaプラグインなど、HTML5だけでは実現出来ない機能を、ネイティブコード(iOSならObjective-C,AndroidならJava)で作り、ハイブリッドアプリから利用出来るようにしたものです。こちらは、現在のところ以前と同様に最初から用意されている8個から選ぶしかありませんが、(Professionalプラン以上であればカスタムプラグインを導入することが出来ます)今後は、より便利にしていく予定です。


Bowerの導入



 JS/CSSコンポーネントの追加と削除では、Bowerフロントエンドパッケージマネージャと連動するようになりました。

 Bowerとは、Twitter社が作ったJavaScriptCSSモジュールのパッケージマネージャです。node.jsでいうnpm、RHELでいうyumと同様の機能を持っています。これにより、MonacaはBowerリポジトリに登録されている大量のモジュールの中から、自由に好きなモジュールを選んで組み込むことが出来るようになりました。

 この組み込みを簡単にする新しい仕組みが、loader.jsになります。

自動読み込みと手動読み込み



 今までのplugin-loader.jsは、設定したプラグインのjsファイルをすべて自動で組み込むようになっていました。

 一方、loader.jsは「IDEでローダー設定したファイルだけを読み込む」ようになっています。

 Monaca用のいくつかのJS/CSSコンポーネント、例えば、jQuery (Monaca Version)の場合は、IDEから設定を行うと、自動的にloader.jsにも組み込まれます。





 しかしながら、BowerライブラリからjQueryを組み込む場合は、loader.jsに入れるかどうかは、ユーザーが自分で決定することが出来ます。操作の流れとしては、まず、JS/CSS Componentsの画面の検索ボックスからjqueryで検索を行い、検索結果から組み込みたいコンポーネントを選択します。



 次にバージョンを設定し、loader.jsに組み込むかどうかを設定します。






 loader.jsに組み込んだ場合は、index.htmlファイル上は、何もしなくてもすでにjqueryが使えるようになっています。

 一方、loader.jsに組み込まない場合は、index.htmlファイル上で自分で


<script src="components/jquery/dist/jquery.js"></script>

のような記述をする必要があります。

 基本的にはどちらの書き方でも良いのですが、利用するjavascriptが変更になる度に、scriptタグをたくさん記述するのは冗長なため、loader.jsを利用した方が簡単です。

 新しいMonacaでは、Bowerに登録されているJS/CSSコンポーネントを自由に組み込んで使えるようになったため、中には、loader.jsに組み込んでしまうと、他のjsコードと競合してうまく動作しないものもあるかも知れません。(例えば、内部でstrict宣言をしているなど) その場合は、loader.jsを使わずに、scriptタグを記述して読み込むようにして下さい。

いずれにしても、loader.jsを使う/使わないことをユーザー側で選択出来るようになったので、開発初期はloader.jsで素早く作り、実装後半のチューニング的な段階になったら、きめ細かくscriptタグでの記述に変える、といったことが出来ます。


ユーザーによる編集が可能



 また、loader.jsは、plugin-loader.jsと違って、中身を修正出来ます。削除も出来ます。

 初心者にはお勧めではありませんが、loader.jsは、IDEから直接編集が可能です。
 このため、デバッグ時にJS/CSSコンポーネント内で何か起こっているけど、分からないのでログを出したい、、といった場合、直接loader.jsを変更して、対応することが可能です。

例えば、jqueryajaxで、リクエストヘッダーを生成する部分


// Caches the header
setRequestHeader: function( name, value ) {
  var lname = name.toLowerCase();
  if ( !state ) {
    name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
    requestHeaders[ name ] = value;
  }
  return this;
},

に、ログ出力を組み込んで


// Caches the header
setRequestHeader: function( name, value ) {
  console.log( name + ":" + value ); // For Debug
  var lname = name.toLowerCase();
  if ( !state ) {
    name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
    requestHeaders[ name ] = value;
  }
  return this;
},

のようにすれば、ajaxがうまく動作していないときに、ヘッダ情報を確認することが出来ます。

 ただし、IDEからローダーの再設定をすると、編集した箇所は元に戻ってしまうので、loader.jsの修正は、あくまでデバッグコードなど一時的な変更のみにとどめておいて下さい。また、loader.jsが壊れてしまうと、アプリが正常に動作しなくなりますので、編集には十分注意して下さい。

 上記のようにjQueryの部分だけを変更した場合、JS/CSSコンポーネントの設定から、jQueryの部分だけ再度、ローダー設定を行えば、loader.jsはもとの状態に戻ります。

 loader.jsを編集したことで、うまく動作しなくなってしまって戻せなくなってしまった場合は、loader.jsを削除して、再度、作り直す必要があります。まず、IDEのファイルツリーから、直接loader.jsを削除して下さい。その後、JS/CSSコンポーネントの追加と削除から、必要なコンポーネントを全て選択して「ローダー設定」をやり直して下さい。



 Monaca IDEは、loader.jsの中身を解析して、現在ローダー設定されているJS/CSSコンポーネントを判定しています。
 loader.jsを削除した場合、JS/CSSコンポーネントから設定を確認すると、すべてのローダー設定が空になっているのが分かります。



自動でローダーに組み込まれるMonaca用のコンポーネントもすべてなくなった状態なので、設定画面からすべてのJS/CSSコンポーネントを再設定して下さい。特にCordova (PhoneGap) LoaderとMonaca Core Utilityは、必須なので、かならず設定し直して下さい。



 loader.jsには、システム側が付与した以下のようなコメント文がありますが、これは削除しないで下さい。ローダー設定されているコンポーネントの判別に利用しています。



/*** <Start:monaca-onsenui> ***/
/*** <Start:monaca-onsenui LoadJs:"components/monaca-onsenui/js/onsenui_all.js"> ***/
...
/*** <End:monaca-onsenui LoadJs:"components/monaca-onsenui/js/onsenui_all.js"> ***/
/*** <End:monaca-onsenui> ***/




まとめ


 loader.jsの導入は、BowerによるいろいろなJS/CSSコンポーネントMonacaで利用出来るようにするために必要な変更でした。これは、この後、Cordova 3.5への対応にもつながっています。

 Monacaは、次のリリースでいよいよCordova 3.5への対応を予定しています。楽しみにお待ち下さい。

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

今回の課題


前回の記事
http://blog.asial.co.jp/1260
で、Formタグで画像を選択していましたが、この方法は、Android 4.4では出来なくなっています。(Android 4.4.2で確認。今後のバージョンアップで改善される可能性はあります)

そこで、ここではFormタグからではなく、File APIから画像を取得してファイルをアップロードする実装を考えてみます。今回は、サンプルとして、getPictureメソッドを使って、デバイス内の画像ファイルを選択してサーバーにアップするものを考えます。

注意事項:
BlobがWebViewで使用出来る必要があります。Nexus 5では確認していますが、4.4より以前のAndroid端末などでBlobが使えないと、この記事の方法は出来ません。

【2014/07/3捕捉】
Android 4.4.4では上記の問題が改善され、Formタグでも画像が選択出来るようになりました。

サーバー側の実装


サーバー側の実装は、前回の記事とまったく同じなので、説明は割愛します。
サーバー側は、通常のフォーム処理と同じで良いところがこの方法の優れた点です。(レスポンスをjsonにするところだけは違います)

クライアント側の実装


最初に、コードの全体を示します。



        function getPhoto () {
            navigator.camera.getPicture(movePic, onFail, 
                { quality: 50,destinationType: Camera.DestinationType.FILE_URI,
                    sourceType: navigator.camera.PictureSourceType.SAVEDPHOTOALBUM });
        }

        function movePic(imageuri){ 
            window.resolveLocalFileSystemURI(imageuri, resolveOnSuccess, resOnError); 
        }

        function onFail (message) {
            alert('ERROR' + message);
        }
        
        function resolveOnSuccess(entry) {
            entry.file( function(file) { 
                var reader = new FileReader();
                reader.onloadend = function(evt) {
                    var formData = new FormData();
                    formData.append("userfile", new Blob([evt.target.result],{"type":file.type}), "uesrfile.png");
                    upload(formData);
                };
                reader.readAsArrayBuffer( file );
            }, resOnError );
        }

        function resOnError(error) {
            alert(error.code);
        }
    
        function upload(fd) {
            $.ajax(
            'http://[server url]/uploader.php',
                {
                type: 'post',
                processData: false,
                contentType: false,
                data: fd,
                dataType: "json",
                success: function(data) {
                    alert( data.message );
                    console.log(data);
                },
                error: function(XMLHttpRequest, textStatus, errorThrown) {
                    alert( "ERROR" );
                    alert( textStatus );
                    alert( errorThrown );
                }
            });
            return false;
        }


また、body部に記述するhtmlは次のようになります。



    <h1>Select File</h1>
    <input type="button" onclick="getPhoto()"; value="Select File"><br/>


プログラムの中身ですが、まず前回と違って、body部にformタグがありません。inputタグはありますが、単にgetPhoto()メソッドを読んでいるだけになります。

次に、javascript部分について。uploadメソッドを呼ぶところは、基本的に前回と同様です。引数のfdをそのまま送っているところだけ、少し違います。

そして、前回と大きく違う今回のポイントは、最初に呼ばれたgetPhoto()メソッドから、実際にファイルをアップロードするupload()メソッドまでの間の処理になります。
まず最初に、movePic()メソッドが呼ばれて、選択した画像ファイルをfileEntryオブジェクトに変換します。
次に、resolveOnSuccess()メソッドが呼ばれて、fileEntryオブジェクトをfileオブジェクトに変換します。さらに、そのfileオブジェクトをArrayBufferとして読み込んで、blobオブジェクトを作り、FormDataに結合して、upload()メソッドを呼び出します。

上記の仕組みにより、navigator.camera.getPicture()メソッドで取得した画像ファイルを、Formデータとしてサーバーに送信することが出来ます。

捕捉



上記の処理は、ちょっと冗長に感じると思います。そもそも、fileEntryオブジェクトのfileメソッドでfileオブジェクトを取得出来ているので(ややこしくてすみません)、これをそのままformdataにappendすれば簡単です。本来、FileクラスはBlobクラスの子クラスなので、そのままappendできて良いと思いますが、、、。しかしながら、実際に試してみると、そのやり方では現行のMonaca (Cordova 2.9相当)では、formdataはmultipartとして認識されず、通常のpostデータとして送られてしまいます。
(PHP側では、$_FILESではなく$_POST変数に値が入ります) このため、一度、ArrayBufferクラスを経由して、再度blobオブジェクトを作り直しています。

この問題は、おそらくですが、FileEntryやFileクラスがCordovaで定義されているクラスであるのに対し、Blobクラスはブラウザがもともともっているクラスであるため、FileクラスがBlobクラスの子クラスとして認識されないからだと思います。

Cordova 3系以後では、File Apiプラグイン扱いになり、外すことも出来るので、その場合は、上記のように一度ArrayBufferで読み直すことなく動作させることが出来るようになると思います。


まとめ



HTML5の持つFile APIは非常に強力で、ハイブリッドアプリを作る上でのデータ処理にはとても重要なのですが、その使い方はやや複雑だと思います。今回の記事では、FormとしてFile APIで取得したファイルの送信を例としてあげさせていただきました。Blobを持つ機種については、応用することで、写真をCampasに表示して加工を行い、それをファイルにしてアップロードしたりなども出来ますので、参考にして下さい。

「Onsen CSS Components」をリリースいたしました!

この度、Onsen UIプロジェクトの新しいWebサービスとして「Onsen CSS Components」をリリースさせていただきました。





Onsen CSS Componentsとは?




Onsen CSS Components」は「Onsen UI」で作成されたモバイルアプリのUIに対してテーマローラー機能を提供するサービスです。「Onsen CSS Components」にアクセスすると、左側にモバイルアプリのUIがあるのを確認することができると思います。




Onsen CSS Components」を使うことで、HTMLとCSSで作成されたアプリのUIのテーマを簡単にカスタマイズして自分のHTML5アプリに組み込むことができます。「Onsen CSS Components」の右側から好きなカラーを選択することでモバイルアプリのUIのカラーを変更することができます。





「Onsen CSS Components」の使い方



テーマローラー機能






右側のカラーパレットで色を選択すると、左側にあるモバイルアプリのUIのカラーが変更されます。カラーを変更したUIは画面上部からダウンロードでき、作成したテーマを共有することもできます。





UIパターン




左側の「Overview」パネルでは、UIパターンを総覧することができます。このUIパターンをクリックすることで、実際のソースコードを閲覧、コピーすることができます。使用できるUIパターンは今は少なめですが、今後はモバイルのUIパターンの数を増やしていく予定です。


もし、希望のモバイルアプリUIのパターンがあれば、「Onsen CSS Components」ページ内の「request」ボタンを押してご連絡いただけると嬉しいです。


Onsen CSS Components」で、皆様のモバイルアプリUIの作成がより一層、手軽になることを願っております。

今後とも、「Onsen UI」および「Onsen CSS Components」をよろしくお願い申し上げます。

AngularJSに触れてみる その2




前回のブログに引き続き、AngularJSの機能を触っていきたいと思います。 こちらは今回機能紹介のために用意したPC版のデモです。モバイルでは見にくいので、でうまく動かない場合はPCに最新版のブラウザ (最新版のGoogle Chromeなど) をダウンロードしてからご覧ください。



今回はデモで用いられているAngularJSの機能、主にngViewについて紹介していきたいと思います。ngViewを用いることでURLの切り替えによって読み込むコンテンツを切り替えることができます。

上記デモはボタンをクリックするごとにURLを切り替えて、そのURLに対応したHTMLテンプレートとコントローラーを読み込ませて表示を行なっています。また、切り替える時のアニメーションにはngAnimateというAngularJSのアニメーション機能を使っています。

まずはindex.htmlソースコードを掲載します [※ソースは紹介に必要のない部分は削除しています] 。なお、画像を除いたソースコードは最下部に置いてあります。

index.html






<!DOCTYPE html>
<html ng-app="MonaApp">
  <head>
    <meta name="viewport" content="width=device-width; initial-scale=1.0;">
    <base href="/blog1017/" />
    <link rel="stylesheet" href="css/style.css"/>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <script src="http://code.angularjs.org/angular-1.2.0-8336b3a/angular.min.js"></script>
    <script src="http://code.angularjs.org/1.2.0-rc.2/angular-animate.min.js"></script>
    <script src="http://code.angularjs.org/1.2.0-rc.2/angular-route.min.js"></script>   
    <script src="js/app.js"></script>
  </head>
  <body>

     <div id="header">
        <p id="title">AngularJS Books</p>
    </div>

    <div id="container" ng-controller="MonaCtrl">
        <div  ng-view class="view-demo"></div>
        <div id="sidebar">
	  <ul>
              <li id="book1"><a href="book1">Book1</a></li>
              <li id="book2"><a href="book2">Book2</a></li>
              <li id="book3"><a href="book3">Book3</a></li>
              <li id="book4"><a href="book4">Book4</a></li>
              <li id="book5"><a href="book5">Book5</a></li>
         </ul>
        </div>
     </div>  
  </body>
</html>


app.js





var app = angular.module('MonaApp', ['ngRoute', 'ngAnimate']);

app.config(function($routeProvider, $locationProvider) {

  $routeProvider.when('/book1', {
    templateUrl: 'templates/book.html',
    controller:book1Ctrl
  });

  $routeProvider.when('/book2', {
    templateUrl: 'templates/book.html',
    controller:book2Ctrl
  });


  $routeProvider.when('/book3', {
    templateUrl: 'templates/book.html',
    controller: book3Ctrl
  });
  });
});


app.config(function($locationProvider) {
      $locationProvider.html5Mode(true);
});


function MonaCtrl($location, $scope) {

    var pager = 1;

    setInterval(function() {
      $scope.$apply(function(){
        if(pager === 6){
          pager = 1;
        }

        $location.path('/book'+pager);
        pager++;
      });
    }, 5000); 
  }
}

function book1Ctrl($scope) {

  angular.element("#sidebar ul li").css("background", "#24100F");
  angular.element("#book1").css("background", "#D0B29A");

  $scope.MonaItems = [];

  $scope.MonaItems.push({
         "title"  : "Mastering Web Application Development with AngularJS",
         "author" : "Author: Pawel Kozlowski, Peter Bacon Darwin",
         "image"  :  "images/1.png" ,
         "link"   : "http://www.amazon.co.jp/Mastering-Application-Development-AngularJS-ebook/dp/B00EQ67J30/ref=sr_1_4?ie=UTF8 &qid=1381665653 &sr=8-4 &keywords=AngularJS" 
  });
}


function book2Ctrl($route, $routeParams, $location, $scope) {

  angular.element("#sidebar ul li").css("background", "#24100F");
  angular.element("#book2").css("background", "#D0B29A");

  $scope.MonaItems = [];

  $scope.MonaItems.push({
         "title"  : "AngularJS",
         "author" : "Author: Brad Green, Shyam Seshadri",
         "image"  :  "images/2.png" ,
         "link"   : "http://www.amazon.co.jp/AngularJS-Brad-Green/dp/1449344852/ref=tmm_pap_title_0?ie=UTF8 &qid=1381668266 &sr=1-1"  
  });
}


function book3Ctrl($route, $routeParams, $location, $scope) {


  angular.element("#sidebar ul li").css("background", "#24100F");
  angular.element("#book3").css("background", "#D0B29A");

$scope.MonaItems = [];

  $scope.MonaItems.push({
         "title"  : "Angularjs in Action",
         "author" : "Author: Brian Ford, Lukas Ruebbelke ",
         "image"  :  "images/3.png" ,
         "link"   : "http://www.amazon.co.jp/Angularjs-Action-Brian-Ford/dp/1617291331/ref=sr_1_6?ie=UTF8 &qid=1381731976 &sr=8-6 &keywords=AngularJS"
  });
}


フォルダ構成は下記になります。




ではngViewの紹介に移っていきます。

ngView




ngViewを使うことでindex.htmlに読み込むHTMLテンプレートおよびコントローラー等をURLによって切り替えることができます。URLが切り替わるたびにそのURLに紐づけられたHTMLテンプレートとコントローラーに切り替わります。

上記デモでテンプレートが切り替わっている場所はindex.htmlに定義してある下記の場所です。divタグに属性としてng-viewが記述されていることが確認できると思います。



<div ng-view class="view-demo"></div>


具体的にapp.jsのコードを見ていきましょう。



var app = angular.module('MonaApp', ['ngRoute', 'ngAnimate']);


AngularJSではモジュールという機能があります。モジュールという機能によってアプリが起動 (ブート) する際の設定や挙動などを定義することができます。詳細は本家ドキュメントをご覧ください。


ここでは MonaAppという自分で作成したモジュールに、ngRoute (ngViewのルーティングのために必要) およびngAnimate (ngAnimateというAngularJSのアニメーション機能を用いるためにver1.2から必要 ) というモジュールを読み込んでいます。

このモジュールを読み込むためには、以下のJSファイルを読み込む必要があります。これらのファイルはindex.htmlでそれぞれロードしています。



<script src="http://code.angularjs.org/angular-1.2.0-8336b3a/angular.min.js"></script>
<script src="http://code.angularjs.org/1.2.0-rc.2/angular-animate.min.js"></script>
<script src="http://code.angularjs.org/1.2.0-rc.2/angular-route.min.js"></script>  


また、ngRouteを使う場合にはindex.htmlのタグ中のタグで設定しておきます。私の場合はblog1017という名前のフォルダー直下にベースURLを設定してあるので以下のようにindex.htmlのタグに記述しています。




    <base href="/blog1017/" />




下記ではngRouteロードされた$routeProviderの設定を行っています。$routeProviderはangular-route.jsで読み込まれるサービスであり、ルートプロバイディングの設定を行います。



app.config(function($routeProvider) {

  $routeProvider.when('/book1', {
    templateUrl: 'templates/book.html',
    controller:book1Ctrl
  });

  $routeProvider.when('/book2', {
    templateUrl: 'templates/book.html',
    controller:book2Ctrl
  });

   .....

});


$routeProvider.whenでテンプレートとコントローラーの設定を行います。今回は全て同じtemplates/book.htmlというテンプレートを使い回しています。



  $routeProvider.when('/book1', {
    templateUrl: 'templates/book.html',
    controller:book1Ctrl
  });


上記の記述は


1:ベースURL/book1にURLが切り替わった時に




<div  ng-view class="view-demo"></div>

2:上記に対してtemplates/book.htmlというHTMLテンプレートを読み込ませて


3:book1Ctrlというコントローラーを割り当てる


という設定を行っています。


PCでこのブログをご覧の方は実際にこちらのデモで試してみましょう。うまく動かない場合には最新のGoogle Chromeなどをダウンロードしてお試しください。



上記のURLは[http://s3.asial.co.jp/~ataru/blog1017/index.html]ですが、book1ボタンを押した際に、aタグでURLを変更しています。その際に

1:templates/book.htmlというテンプレートが読み込まれ


2:book1Ctrlというコントローラーが割り当てられます





そうすれば、[http://s3.asial.co.jp/~ataru/blog1017/book1]にURLが切り替わった時にng-view属性を指定した箇所に読み込まれるテンプレートとコントローラーが切り替わります。


割り当てられたbook1Ctrlコントローラーを見てみましょう。




function book1Ctrl($scope) {

  angular.element("#sidebar ul li").css("background", "#24100F");
  angular.element("#book1").css("background", "#D0B29A");

  $scope.MonaItems = [];

  $scope.MonaItems.push({
         "title"  : "Mastering Web Application Development with AngularJS",
         "author" : "Author: Pawel Kozlowski, Peter Bacon Darwin",
         "image"  :  "images/1.png" ,
         "link"   : "http://www.amazon.co.jp/Mastering-Application-Development-AngularJS-ebook/dp/B00EQ67J30/ref=sr_1_4?ie=UTF8 &qid=1381665653 &sr=8-4 &keywords=AngularJS" 
  });
}



MonaItemsという配列の中に本のタイトルや著者名、画像、リンクなどのオブジェクトを入れています。これが下記のテンプレートであるtemplates/book.html中に記述されたngRepeatの中でitemとして展開されます。それをtemplates/book.htmlの中で、{{item.title}}や{{item.author}}、{{item.link}}という形でAngularJSのExpressionsで記述しています。Expressionsは前回のブログで紹介しています。

template/book.html





<div class="contents" ng-repeat = "item in MonaItems" >
    <h1>{{item.title}}</h1>
    <h2>{{item.author}}</h2>
 
    <a href={{item.link}} target=”_blank”><img src={{item.image}} /></a>
    <a href={{item.link}} target=”_blank”>Purchase this book on Amazon</a>
</div>


今回はテンプレートとして用いているのはtemplates/book.html1つですが、book1Ctrlbook2CtrlなどバインドされたコントローラーごとにMonaItemsという配列に代入される値は異なるので、URLが切り替わるたびに、コンテンツの異なるtemplates/book.htmlが表示されます。



ngAnimate



ngAnimateはAngularJSが提供しているアニメーションのための機能です。上記デモでもngAnimateを使ってアニメーションを行なっています。

ngAnimateの仕組みは1.1.5から1.2にAngularJSがアップグレードする際に仕組みが変わっています。現在AngularJSのStable版の最新は1.0.8 (2013/10/17現在) なので、まだまだngAnimateの仕様は今後変更される可能性があります。

詳細はyear of mooというこちらブログが詳しいので興味のある方はご覧ください。

Animation in AngularJS 1.2

ngAnimateの仕組みについて紹介します。ngAnimateをサポートするディレクティブについては本家ドキュメントのngAnimateの項目をご覧ください。ngRepeatやngView、ngIncludeなどがサポートされています。

上記デモでngAnimateでアニメーションしている箇所は以下です。ここではclassとして指定されているview-demoに着目してください。



<div ng-view class="view-demo"></div>


ngAnimateではアニメーションのイベントが発火した際にCSSのクラスが指定要素に追加される形でアニメーションを行ないます。幾つか使い方があるのですが、ngAnimateを使用したい場合には、例えばngRepeat、ngView、ngIncludeなどngAnimateをサポートしているディレクティブにクラスを設定します。ここではview-demoと設定しています。そして、そのview-demoに関連して、ng-enterng-leaveなどの幾つかのクラスのCSSを記述します。以下のCSSを見てみましょう。.view-demoに.ng-enter、.ng-enter-active、.ng-leave,.ng-leave-asctiveなどのクラスを記述しています。


ngViewではHTMLテンプレートや何らかのコンテンツが読み込まれて表示された時にenterイベントが、コンテンツが表示されなくなった時にleaveイベントが発火します。enterイベントが発火した時には.ng-enterと.ng-enter-activeクラスが対象の要素に対して追加されます。leaveイベントが発火した際には、ng-leave、ng-leave-activeクラスが対象の要素に追加されます。アニメーションが完了するとこれらの付加されたCSSは取り除かれます。

例えば、URLが切り替わって[ book.html & book1Ctrl ]という組み合わせのコンテンツが消え、[ book.html & book2Ctrl ]という組み合わせのコンテンツが新しく表示されるとき、ng-enterおよびng-enter-activeが新しく表示される[ book.html & book2Ctrl ]に適用され、ng-leaveおよびng-leave-activeが表示されなくなる[ book.html & book1Ctrl ]に適用されます。アニメーションが完了した時にはこれらのクラスは取り除かれます。




style.css





/*対象の属性 (view-demo) を持つ要素に追加されるCSS*/
	.view-demo.ng-enter, .view-demo.ng-leave {
  		-webkit-transition-duration: 1s;
  		-moz-transition: 1s;
  		-o-transition: 1s;
  		transition:1s
     display:block;
  		position:absolute;
	}
 /*コンテンツが表示される時に対象の要素に追加されるCSS(始点)*/
	.view-demo.ng-enter {
  		left:100%;
	}
 /*コンテンツが表示される時に対象の要素に追加されるCSS*/
	.view-demo.ng-enter-active {
  		left:0%;
	}
 /*コンテンツが表示されなくなる時に対象の要素に追加されるCSS(始点)*/ 
	.view-demo.ng-leave { 
		opacity: 1;
  		left:0%;
	}
 /*コンテンツが表示されなくなる時に対象の要素に追加されるCSS*/ 
	.view-demo.ng-leave-active {
  		opacity: 0;
  		left:100%;
	}



このCSSを定義することで実際にURLが変わってテンプレートが切り替わった時には

1:新しく表示されるコンテンツのアニメーションの始点 (最初の状態) として


	.view-demo.ng-enter {
  		left:100%;
	}

が適用されます。

2:そして次に、新しく表示されるコンテンツに対して



	.view-demo.ng-enter-active {
  		left:0%;
	}


が適用されます。結果として、新しく入ってくるコンテンツはleftが100%の状態からleftが0の状態になるので、表示されるときには右から左へとスライドアニメーションで入ってきます。そして表示されなくなるコンテンツの場合は

3:表示されなくなる元のコンテンツのアニメーションの始点 (最初の状態) として



	.view-demo.ng-leave { 
		opacity: 1;
  		left:0%;
	}


が適用されます。

4:そして次に、表示されなくなる元のコンテンツに対して下記が適用されます。



	.view-demo.ng-leave-active {;
  		opacity: 0;
  		left:100%;
	}



表示されなくなるコンテンツに対しては最初はleft:0%;から始まり、そしてleft:100%およびopacity:0;が指定されます。すなわち、表示されなくなるコンテンツは透明になりながら、左から右側にスライドしつつ消えていきます。

下記でアニメーションの時間は1秒に設定して、position:absolute;にしてあります。どうやらngAnimateで移動させるコンテンツはposition:absolute;をかける必要があるようです。



	.view-demo.ng-enter, .view-demo.ng-leave {
  		-webkit-transition-duration: 1s;
  		-moz-transition: 1s;
  		-o-transition: 1s;
  		transition:1s
     display:block;
  		position:absolute;
	}

※ 一番上のスマホのデモはデスクトップのデモとは異なりleave-activeをleft:100%;ではなく、left:-100%;にして右ではなく左にスライドしていくようにCSSを下記のように切り替えています。


/*アニメーション*/ 
.view-demo.ng-leave { 
 	left:0%;
}

.view-demo.ng-leave.ng-leave-active {
  		left:-100%;
}

画像を除いたソースコードは全てこちらに添付しておきます。相変わらず自分自身勉強不足であるのと場当たり的に作ったので非効率な部分や不要な記述があると思いますがこちらに掲載しておきます。

ダウンロード




=======================================================

参考リンク


*ngViewドキュメント
*$routeProviderドキュメント
*ngAnimateドキュメント
*year of moo
*AngularJSでsetTimeout()やAjaxを併せて使う場合の注意点 ($scope.$apply)
*ngViewを使った時に画面を更新すると404になる場合の対策

スマホアプリ開発の見積もりで気をつけたいいくつかのこと

こんにちは、鴨田です。

普段はプロジェクトマネージャーやデザインディレクション、デザイナーとして、
働いている時間が長いのですが、営業として他社様に出向き、
案件ヒアリングや見積もりをすることがあります。

スマホ案件に携わることが多いため、大体の場合はスマホアプリ案件なのですが、
見積もり時に注意すべき事が多々あります。

今日は、スマホアプリ開発の見積もりで注意すべき点について、
いくつかご紹介できればと思います。



1.対応OSのバージョン


対応OSに関しては、おそらくiOSAndroid両対応であったり、
どちらかをリリースしてから、もう一方を作るというケースが多いと思います。

重要なのは、どのバージョンを対象としてる作るのか、です。

iOS6.0以上、Android4.0以上、ということであれば、
ほとんど問題なく、開発を進めることが出来ます。

これが、iOS5.0以上とかAndroid2.2以上とかになると、
いろいろと気をつけることが多くなってくるため、
要件定義、設計、開発、テスト、とほぼ全ての行程において、
前者の開発よりもコストがかかってきます。

クライアントの希望や、コスト感に合わせて、
どのバージョンまでサポートするかを決めて、
見積もりを行いましょう。

また、iOSの場合はアプリがリリースされる時期と、
OSアップデートの時期が重なるときは注意が必要です。

まとめ:
出来るのであれば、最新メジャーバージョンを対象と出来れば吉。
対象を広げるとしても、Androidは2.3以上だと見積もりは抑えられます。
iOSは最新版が普及するのが早いので、最新版リリース時期と被るのであれば、
最新版+一つ前のバージョンとし、それ以外の場合は、
最新版のみでもシェアは確保できると考えられます。





2.検証端末


対象OS以上に、悩ましいのが検証端末です。
iOSであれば、そこまでパターンはないので、
最新機種+最新OSプラスαで問題ないと思います。

Androidは、あまりに機種がありすぎるため、
社内の開発機+クライアントの検証端末程度としたいところです。

また、機種によってパフォーマンスに相当の違いが出るため、
あまりスペックが高くない機種でもテストをし、
そちらに合わせてチューニングを行った方がよいです。

社内にない機種が検証端末となるようであれば、
開発時は他機種で行いつつ、テスト段階では必ず該当機種を用意するか、
検証センターに行って、確認しましょう。

最近は端末をレンタルしてくれるサービスも多々ありますが、
最新機種は人気が高く、すぐにレンタルできない事もありますので、
注意が必要です。

まとめ:
検証端末は予め2~3程度を決めておくこと。
ハイスペック端末だけでなく、ロースペック端末でも検証すること。
必要に応じて、検証センター、端末レンタルを行いましょう。





3.タブレット対応・画面の向き


アプリによっては、タブレット対応や画面の向きに応じて、
デザインのレイアウトを変える必要が出てくる場合があります。

もし、そのような対応を行う場合、
デザインや実装、テストにおいて、追加の工数が発生します。

特に指定がない場合は、
タブレットは最悪スマホのデザインをそのまま大きくすることも可能ですが、
あまり見栄えがしないことが多いので、レイアウト変更した方が無難です。

スマホの縦横対応に関しては、どちらか固定で作る方が開発はスムーズに済み、
コスト・工数においても削減することが出来ます。

最終的には、アプリの特性、ユーザビリティを考えて、
見積もりに反映させるのが良いかと思います。

まとめ:
要件次第ではあるが、コスト・工数面を考えると、
縦横対応しない方が開発はスムーズ。
タブレットや縦横対応する場合は、単なるレイアウト変更だけでなく、
工夫を凝らして、縦が面と横画面で機能的に使い分けができると、
アプリのUXが向上するだけでなく、完成度も上がります。





4.WebViewアプリ、Webアプリの問題点


ネイティブではなく、主にWebViewを使用したアプリ、
Webアプリの場合、気をつけるべき点があります。

iPhoneであれば、特に気にする必要はありませんが、
Androidでは、JavaScriptCSSでのアニメーションを多く行うと、
カクカク動いたり、動作が遅くなることがあります。

また、CSS3の機能を使用して、
影を付けたオブジェクトを多数配置すると、
スクロールが遅くなったりすることもあります。

そのため、アニメーションさせることが考えられる案件では、
チューニングに気を遣うことがあるので、
その分を考えて、見積もりを行うか、
非機能要件として、何らか定義を行うか、
などのケアをしておくといいと思います。

まとめ:
WebViewアプリ、Webアプリは、
iPhone/Andorid両対応が比較的簡単に出来ますが、
凝った作りにするとパフォーマンスに影響が出てくるので、
チューニングも視野に入れて、工数を見積もりましょう。
特に、Androidでのアニメーションは要注意です。






スマホアプリに限った話ではないですが、
見積もりが正しくないと、いろいろな意味で良くないことが多いので、
要件にあった正しい見積もりをするための参考になればと思います。

実際には、経験してみないとわからないこともあるのですが、
経験した後に、振り返りで改めて確認してもらえたら幸いです。

Monacaが正式リリースしました!

はじめまして!Monacaエバンジェリストの生形です。
長い間パブリックベータ版として皆様にご愛顧頂いておりましたMonacaが、
9/12、ついに正式リリースを迎えました!

本日は、正式リリースで追加された新機能のうち、目玉の2機能をご紹介します!

UIフレームワーク Onsen UI


Onsen UIは、シンプルなコードでモバイル用UIを構築することができる、HTML5ベースのUIフレームワークです。

ここでは、基本的な利用方法を解説します。
まず、プロジェクトのプラグイン設定で、Onsen UIを有効にします。


続いて、ページを構成するhtmlファイルにOnsen UIをロードするための記述を追記します。


以上で、Onsen UIを利用するための準備が整いました。

Onsen UIには"ons-"で始まる様々な独自タグが用意されており、それらをhtmlファイルに記述することで、
モバイルアプリライクなリストやボタンなどのコンポーネントを簡単に作ることができます。

今回は、コンポーネントの1つである、タブバーを定義するタグの使い方を見てみましょう。

htmlファイルの構成は以下の通りです。

  • index.htmlタブバーを定義

  • left.html左側のタブに関連付いたページを定義

  • right.html右側のタブに関連付いたページを定義


index.htmlは以下のように定義します。

[index.html]


<body>
    <ons-tabbar>
        <ons-tabbar-item page="left.html" active="true">
            left
        </ons-tabbar-item> 
        <ons-tabbar-item page="right.html">
            right
        </ons-tabbar-item> 
    </ons-tabbar>
</body>

<ons-tabbar>タグは、タブバー全体を定義します。
<ons-tabbar-item>タグは、タブバー内の1つ分の項目を定義します。
page属性にはタブ選択時に表示するページのURLを指定します。
また、active属性をtrueに設定することで、タブが選択された状態にすることができます。
今回の例では、初期表示時に左側のタブが選択された状態にしています。

left.htmlとright.htmlはそれぞれ以下のようになっています。

[left.html]


<body>
    <h1>ひだり</h1>
</body>


[right.html]


<body>
    <h1>みぎ</h1>
</body>


実行すると、以下のような画面になります。




Onsen UIの詳細は、以下のドキュメントをご確認ください。
Onsen UI

チーム開発機能(一部機能は有料プランのみ利用可能)


これまでご要望の多かった、1つのプロジェクトを複数名で開発できるチーム開発機能がMonaca IDEに追加されました。

・開発者としての参加(プロジェクトの編集、チームメンバの管理)

Professional、Business、Enterpriseプランのみ利用可能

・テスターとしての参加(Monacaデバッガーによるテスト、チャット機能)

無料プランを含むすべてのプランで利用可能

チーム開発機能のイメージ




さらに、今回の正式リリースに伴い、Monacaデバッガーが2.0.0にバージョンアップしました。
(9/12時点でAndroid版のみ。iOS版は近日中に配信予定)
新機能として、アプリのスクリーンショットをキャプチャし、IDEにアップロードしてチームで共有することが可能になりました。

チャット画面




これらの機能により、中規模以上のアプリ開発時にチーム内での連携作業をスムーズに行うことができるようになります。


その他の新機能や各種料金プランの詳細が知りたい方は、以下のページをご確認ください。

正式リリース案内
料金プラン

今後も新機能の第二弾、第三弾が控えております!
パワーアップしたMonacaを、これからもどうぞよろしくお願いいたします。

【CSS】ハイブリッドアプリを作成するときにいつも書くようにしているCSSプロパティいくつか!

こんにちは、相変わらずドラクエ10三昧の橋本です。
最近はライノス道場に通っています。


さて、今日はハイブリッドアプリのCSSを書く際に毎回指定するようにしているプロパティを備忘録がてらいくつか書いていこうと思います(いつも忘れるので)。

-webkit-tap-highlight-color: rgba(0, 0, 0, 0)



iPhoneAndroidでリンクなどの要素をタップしたときに、iPhoneでは薄いグレー、Androidでは緑やオレンジの枠がデフォルトで表示されます。
-webkit-tap-highlight-colorというプロパティに色を指定することで、この枠の色を変えることができます。

ハイブリッドアプリを作成する際には、この枠が出ると如何にもWebっぽくなってしまうため、透明色を-webkit-tap-hightlight-colorに指定して、枠が表示されないようにしています。



* {
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}


リストの項目など、敢えて選択時に色を付けたい場合には、個別にtap-hightlight-colorを指定するといいかと思います。


-webkit-touch-callout: none



iOSでリンクを長押しした際に表示されるポップアップメニューを消すためにこのプロパティを設定しています。
ポップアップメニューが出るとネイティブっぽくないですもんね



* {
    -webkit-touch-callout: none;
}



-webkit-user-select: none



スマホのヘッダやフッター、またはボタンなどの要素の文字列や画像を選択してコピーできてしまうと、一気にネイティブっぽくなくなりますよね。
そんなときには、-webkit-user-selectにnoneを設定することで、要素を選択できなくすることができます。



* {
    -webkit-user-select: none;
}


ただし、このままだと、input要素で文字入力ができなくなってしまったり、何かと不都合があるので、ユーザーからの選択を許可したい箇所には、以下のように-webkit-user-selectにautoを入れて選択できるようにする必要があります。



input[type=text] {
    -webkit-user-select: auto;
}


もしくは、以下のように最初からinputは対象外にするのもいいかもです。



*:not(input){
    -webkit-user-select: none;
}



-webkit-overflow-scrolling: touch



スマホのネイティブアプリの特徴の1つに、コンテンツの慣性スクロールがあると思います。
-webkit-overflow-scrollingプロパティにtouchを指定することで、オーバーフローしたコンテンツに対して慣性スクロールを適用することができます。



div.contents-ga-overflow-suruyo {
    -webkit-overflow-scrolling: touch;
}


ただ、慣性スクロールは非常に重い処理になるので、端末とコンテンツによっては動きがガクガクになる場合があります(iPhone3GS、iPhone4など)。
そういう場合には、コンテンツにGPUアクセラレーションを効かせるために、以下の指定を入れます。



div.contents-ga-overflow-suruyo > * {
    -webkit-transform: translateZ(0px);
}


今回は-webkit-transform: translateZ(0px)を指定していますが、GPUアクセラレーションを効かせることが出来る指定なら、なんでもいいかと思います。
ただ、iOS6からは、「-webkit-transform: preserve-3d」ではGPUアクセラレーションが効かなくなっているので、それだけは要注意です。


box-sizing: border-box



これはハイブリッドアプリに限ったものではないのですが、ハイブリッドアプリを作成する際には、必ずこの指定を全ての要素に対して入れるようにしています。



* {
  box-sizing: border-box;    
}


box-sizingとは、ボックスの大きさの算出方法を指定するためのプロパティです。
box-sizingには、「content-box」と「border-box」の二種類の値を指定することができます。
content-boxを指定すると、ボックスの幅と高さには、罫線とpaddingの値は含みません。
box-sizingを指定しない場合と同じ扱いになります。

border-boxを指定すると、ボックスの幅と高さに、罫線とpaddingの値を含みます。

わかりにくいので、例として、以下の要素で説明します。



div {
    width: 100px;
    height: 100px;
    border: 1px solid #000;
    padding: 10px;
}


box-sizingにcontent-boxを指定した場合、divの幅と高さは122pxになります。
box-sizingにborder-boxを指定した場合、divの幅と高さは100pxになります。

CSSでwidthやheightを指定する際に、paddingとborderの幅を考慮しなくてよくなるため、非常に快適です。



いかがでしたでしょうか。参考にしてもらえるとありがたいです。

【Monaca】Monaca新機能リリース!Windows8デバッガーリリース、IDE自動補完機能、エディターTheme機能搭載

1:Windows8Monacaデバッガーをリリースいたしました!



Windows8Monacaデバッガーをリリースいたしました。Monaca IDEのファイルメニュー上部の「Windows8」からダウンロード、お持ちのWindows8マシンにインストールすることが可能でございます。





ドキュメントはこちらをご覧ください。


2:Monaca IDE 配色テーマ機能をリリースいたしました!



Monaca IDEエディターの配色テーマ機能をリリースいたしました。Monaca IDE上部の「ファイル」のメニューより「エディター環境設定」を選ぶことで、お好きな配色テーマをMonaca IDEエディターに適用することが可能でございます。





3:Monaca IDE JavaScriptCSS自動補完機能をリリースいたしました!



Monaca IDEエディタ上でのJavaScriptCSSの自動補完機能をリリースいたしました。自動補完機能は「キーバインド」が「default」の場合のみ使用可能です。







4:AndroidiOSのデバッガーがMonaca IDEからダウンロードできるようになりました!



Monaca IDEからAndroid版、iOSMonacaデバッガーのダウンロードが行えます。Monacaデバッガーの新規リリースの際には是非こちらもご利用ください。

AndroidMonacaデバッガーのダウンロード






iOSMonacaデバッガーのダウンロード