2014年6月30日月曜日

Google I/O 2014 - What's new in Android development tools

Google I/O 2014 - What's new in Android development tools



■ 全体の感想

前半は、Android Studio Beta の特に Variant についての解説、後半はデモと個別の機能について。
CIツールのことをかなり意識している感じが伝わってきた。
1.0 が出たら本格的にEclipse + ADTがオワコンになりそうな感じ。
現在はぜんぜんドキュメントがないが、1.0 になったら Android Studio のドキュメントをもっと増やす予定だそうだ。


■ 内容のpickup

Android Studio Beta がリリースされた。
(セッション時は 0.8.0 だが、その後 0.8.1 がリリースされている)

Android Studioの戦略は、統一されたビルドシステムを提供すること。つまり、Android Studio でビルドしようが、CIでビルドしようが、同じビルドができるようにすること。
柔軟性が大事。コードの再利用、ビルドのカスタマイズ化などをIDEとGradleのコンビネーションをうまくやりたい。
前回のI/Oからこの一年でさまざまなバグを修正し、パフォーマンスを改善し、IDEとの統合もたくさんしてきた。


Varitants
- Build Type
Develop vs Product 開発バージョン
- Product Flavor
Paid vs Free など目的に応じて変える
- multiple apk (coming soon) x86 vs ARM など
ゲームによい

- Variant Filter
- Improved Dependencies
Freeには広告があり場合など、Free版だけ広告ライブラリに依存しているなど
denpendencies scope: コンパイル時にチェックして、必要なものだけパッケージに入れる
- New Manifest Merger
ビルドダイプやFlavorに応じてpermissionを変えたいときなど
tools:replace


Insertion android:authorities="${applicationId}.provider"
ContentProviderで便利!

Variant Publishing
Variants in Libraries
まだ作業中


Customization
- BuildConfig Injection
Variantごとのフラグを入れたいときとかに便利
- Res value Injection
- Per-Variant SourceSet



APIs
- Variant Manipulation
- Plugin API
- API to augment IDE model


Android Wear
- Build-in Support for Micro App
メインアプリケーション内にパッケージされる
- Generate XML resoure
- Inject Node in Manifest

dependencies { wearApp project(':wearProject') } or dependencies { wearApp files('/path/to/apk') }


IDE Integration
- Updated Model
- Improved Sync / Build
- Project Structure / Editor Support / Lint


Performance
- Critical Issue
- Full vs Incremental Builds
- Investigation : Known Bottlenecks
- Project Evaluation / Model Building
- Incremental Support in Tasks
- Tasks Parallelization


Road to 1.0
- Finalize IDE Model / DSL
- Variant Aware Dependency Management
- Compatibility with Gradle Model / Plugins


■ Android Studio の新しい機能

Eclipse プロジェクトをインポートしたときにサマリーができるようになった。
例えば、どの jar を gradle の設定に変更したかや、src や res フォルドの階層がどう変わったかなど。


Android Specific View
新しい Android Specific View では、全てのビルドスクリプトが一カ所にまとまるなど、みやすくなる。
マニフェストや同じ名前のリソースファイルもまとまって表示される。
# Eclipseっぽい階層表示だ
# 次のいくつかのCanary buildで入るらしい。


New Project ウィザードで minSdkVersion を選ぶために、現在のAPI Levelの分布をみれるようになった。

WearとAndroid TV用のテンプレートが選べるようになった。

Wearのレイアウトプレビュー(四角と丸)がでるようになった。


プロジェクト全体を RTL 対応する機能が用意された。

エディタプレビュー上でOverflowメニューをクリックすると、メニューが表示されるなど、Activityをひもづけておくと、表示が実装に応じて変わるようになった。


異なるバージョンのプレビューが一度にでるようになった。


新しい属性
android:colorPrimary
android:colorAccent
ActionBarやチェックボックスの色が変わる


android:tint
android:tintMode


テーマに指定されている属性の詳細がF1で出るようになった


@IdRes int id
@DrawableRes int icon
など、アノテーションでどのリソースIDが指定されるべきかを宣言できるようになった。
あわないリソースIDを渡しているコードはLintでエラーになる。



2014年6月26日木曜日

polymer メモ



■ 外部の element を使うには、import し、

<link rel="import" href="../components/core-header-panel/core-header-panel.html">

element をタグとして使う

<core-header-panel>
...
</core-header-panel>



■ 自分で element を作ることもできる

element を作るには、<polymer-element> を使って定義する

Shadow DOM (<template>)で他の element をカプセル化できる
ここで指定したスタイルはこのマークアップにだけ提供され、他のところに影響しない
Shadow DOM polyfill docs

公開されたプロパティ(この例だと "counter")はマークアップから初期化でき、値が変更されたときは変更のハンドラーが呼ばれる

{{ }} でプロパティを直接マークアップにバンドルできる

element の定義で on-[event](この例だと on-tap)属性を使ってイベントハンドラを function にバンドルできる

template の子は id 属性の値を使って、this.$.[id] で参照できる(この例だと this.$.counterVal)

<polymer-element name="my-counter" attributes="counter"> <template> <style> /*...*/ </style> <div id="label"><content></content></div> Value: <span id="counterVal">{{counter}}</span><br> <button on-tap="{{increment}}">Increment</button> </template> <script> Polymer({ counter: 0, // Default value counterChanged: function() { this.$.counterVal.classList.add('highlight'); }, increment: function() { this.counter++; } }); </script> </polymer-element>

作った element をタグとして使う

<my-counter counter="10">Points</my-counter>



■ body unresolved <body unresolved> ... </body> <body> の unresolved 属性は、カスタムエレメントのネイティブサポートが足りないブラウザでの flash of unstyled content (FOUC) を防ぐのに使われる

■ Tabの基本構成 <core-header-panel> <core-toolbar> <paper-tabs valueattr="name" selected="all" self-end> <paper-tab name="all">ALL</paper-tab> <paper-tab name="favorites">FAVORITES</paper-tab> </paper-tabs> </core-toolbar> <!-- main page content will go here --> </core-header-panel> <paper-tab ...><img src="ic_all.png"></paper-tab> のように画像もOK



■ 独自 element を1つの html ファイルにする

- 必要な element の import + <polymer-element>
- polymer-element の name 属性値をファイル名に使う(must じゃないが、そのほうがわかりやすい)
- 最後に Polymer({}); を呼んで element を登録する。これによりブラウザに認識される

post-card.html <link rel="import" href="../components/polymer/polymer.html"> <link rel="import" href="../components/core-icon-button/core-icon-button.html"> <polymer-element name="post-card"> <template> ... </template> <script> Polymer({}); </script> </polymer-element> Shadow DOM 内での :host pseudo-class は、独自 element 自身をさすことになる(上のコードだと <post-card> のスタイルを指定することになる) <template> <style> :host { ... } </style> ... </template>



■ 独自 element の子 element <post-card> <h2>hoge</h2> </post-card> のように、独自 element に子 element を入れる場合、insertion point を指定しないと描画されない

insertion point は <content> で作成する <polymer-element name="post-card"> <template> <style> ... </style> <div class="card-header" layout horizontal center> <content select="img"></content> <content select="h2"></content> </div> <content></content> </template> ... </polymer-element> この場合、<post-card> 内の <img> は最初の content に挿入され、 <h2> は2番目の content に挿入され、 それ以外の子 element は最後の content に挿入される

子 element のスタイルには ::content pseudo element を使う <polymer-element name="post-card"> <template> <style> ... polyfill-next-selector { content: ".card-header h2";} .card-header ::content h2 { margin: 0; font-size: 1.8rem; font-weight: 300; } polyfill-next-selector { content: ".card-header img";} .card-header ::content img { width: 70px; border-radius: 50%; margin: 10px; } </style> ... </template> ... </polymer-element> Shadow DOM をネイティブにサポートしていないブラウザのために、 polyfill-next-selector を使って、::content ルールを non-shadow DOM ルールにどのように変換するかを指定する



'},ClipboardSwf:null,Version:'1.5.1'}};dp.SyntaxHighlighter=dp.sh;dp.sh.Toolbar.Commands={ExpandSource:{label:'+ expand source',check:function(highlighter){return highlighter.collapse;},func:function(sender,highlighter) {sender.parentNode.removeChild(sender);highlighter.div.className=highlighter.div.className.replace('collapsed','');}},ViewSource:{label:'view plain',func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/'+code+'');wnd.document.close();}},CopyToClipboard:{label:'copy to clipboard',check:function(){return window.clipboardData!=null||dp.sh.ClipboardSwf!=null;},func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');if(window.clipboardData) {window.clipboardData.setData('text',code);} else if(dp.sh.ClipboardSwf!=null) {var flashcopier=highlighter.flashCopier;if(flashcopier==null) {flashcopier=document.createElement('div');highlighter.flashCopier=flashcopier;highlighter.div.appendChild(flashcopier);} flashcopier.innerHTML='';} alert('The code is in your clipboard now');}},PrintSource:{label:'print',func:function(sender,highlighter) {var iframe=document.createElement('IFRAME');var doc=null;iframe.style.cssText='position:absolute;width:0px;height:0px;left:-500px;top:-500px;';document.body.appendChild(iframe);doc=iframe.contentWindow.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write('

'+highlighter.div.innerHTML+'

');doc.close();iframe.contentWindow.focus();iframe.contentWindow.print();alert('Printing...');document.body.removeChild(iframe);}},About:{label:'?',func:function(highlighter) {var wnd=window.open('','_blank','dialog,width=300,height=150,scrollbars=0');var doc=wnd.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write(dp.sh.Strings.AboutDialog.replace('{V}',dp.sh.Version));doc.close();wnd.focus();}}};dp.sh.Toolbar.Create=function(highlighter) {var div=document.createElement('DIV');div.className='tools';for(var name in dp.sh.Toolbar.Commands) {var cmd=dp.sh.Toolbar.Commands[name];if(cmd.check!=null&&!cmd.check(highlighter)) continue;div.innerHTML+=''+cmd.label+'';} return div;} dp.sh.Toolbar.Command=function(name,sender) {var n=sender;while(n!=null&&n.className.indexOf('dp-highlighter')==-1) n=n.parentNode;if(n!=null) dp.sh.Toolbar.Commands[name].func(sender,n.highlighter);} dp.sh.Utils.CopyStyles=function(destDoc,sourceDoc) {var links=sourceDoc.getElementsByTagName('link');for(var i=0;i');} dp.sh.Utils.FixForBlogger=function(str) {return(dp.sh.isBloggerMode==true)?str.replace(/
|<br\s*\/?>/gi,''):str;} dp.sh.RegexLib={MultiLineCComments:new RegExp('/\\*[\\s\\S]*?\\*/','gm'),SingleLineCComments:new RegExp('//.*$','gm'),SingleLinePerlComments:new RegExp('#.*$','gm'),DoubleQuotedString:new RegExp('"(?:\\.|(\\\\\\")|[^\\""\\n])*"','g'),SingleQuotedString:new RegExp("'(?:\\.|(\\\\\\')|[^\\''\\n])*'",'g')};dp.sh.Match=function(value,index,css) {this.value=value;this.index=index;this.length=value.length;this.css=css;} dp.sh.Highlighter=function() {this.noGutter=false;this.addControls=true;this.collapse=false;this.tabsToSpaces=true;this.wrapColumn=80;this.showColumns=true;} dp.sh.Highlighter.SortCallback=function(m1,m2) {if(m1.indexm2.index) return 1;else {if(m1.lengthm2.length) return 1;} return 0;} dp.sh.Highlighter.prototype.CreateElement=function(name) {var result=document.createElement(name);result.highlighter=this;return result;} dp.sh.Highlighter.prototype.GetMatches=function(regex,css) {var index=0;var match=null;while((match=regex.exec(this.code))!=null) this.matches[this.matches.length]=new dp.sh.Match(match[0],match.index,css);} dp.sh.Highlighter.prototype.AddBit=function(str,css) {if(str==null||str.length==0) return;var span=this.CreateElement('SPAN');str=str.replace(/ /g,' ');str=str.replace(/');if(css!=null) {if((/br/gi).test(str)) {var lines=str.split(' 
');for(var i=0;ic.index)&&(match.index/gi,'\n');var lines=html.split('\n');if(this.addControls==true) this.bar.appendChild(dp.sh.Toolbar.Create(this));if(this.showColumns) {var div=this.CreateElement('div');var columns=this.CreateElement('div');var showEvery=10;var i=1;while(i<=150) {if(i%showEvery==0) {div.innerHTML+=i;i+=(i+'').length;} else {div.innerHTML+='·';i++;}} columns.className='columns';columns.appendChild(div);this.bar.appendChild(columns);} for(var i=0,lineIndex=this.firstLine;i0;i++) {if(Trim(lines[i]).length==0) continue;var matches=regex.exec(lines[i]);if(matches!=null&&matches.length>0) min=Math.min(matches[0].length,min);} if(min>0) for(var i=0;i

Blogger Syntax Highliter

Version: {V}

http://www.dreamprojections.com/syntaxhighlighter

©2004-2007 Alex Gorbatchev.

'},ClipboardSwf:null,Version:'1.5.1'}};dp.SyntaxHighlighter=dp.sh;dp.sh.Toolbar.Commands={ExpandSource:{label:'+ expand source',check:function(highlighter){return highlighter.collapse;},func:function(sender,highlighter) {sender.parentNode.removeChild(sender);highlighter.div.className=highlighter.div.className.replace('collapsed','');}},ViewSource:{label:'view plain',func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/'+code+'');wnd.document.close();}},CopyToClipboard:{label:'copy to clipboard',check:function(){return window.clipboardData!=null||dp.sh.ClipboardSwf!=null;},func:function(sender,highlighter) {var code=dp.sh.Utils.FixForBlogger(highlighter.originalCode).replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&');if(window.clipboardData) {window.clipboardData.setData('text',code);} else if(dp.sh.ClipboardSwf!=null) {var flashcopier=highlighter.flashCopier;if(flashcopier==null) {flashcopier=document.createElement('div');highlighter.flashCopier=flashcopier;highlighter.div.appendChild(flashcopier);} flashcopier.innerHTML='';} alert('The code is in your clipboard now');}},PrintSource:{label:'print',func:function(sender,highlighter) {var iframe=document.createElement('IFRAME');var doc=null;iframe.style.cssText='position:absolute;width:0px;height:0px;left:-500px;top:-500px;';document.body.appendChild(iframe);doc=iframe.contentWindow.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write('

'+highlighter.div.innerHTML+'

');doc.close();iframe.contentWindow.focus();iframe.contentWindow.print();alert('Printing...');document.body.removeChild(iframe);}},About:{label:'?',func:function(highlighter) {var wnd=window.open('','_blank','dialog,width=300,height=150,scrollbars=0');var doc=wnd.document;dp.sh.Utils.CopyStyles(doc,window.document);doc.write(dp.sh.Strings.AboutDialog.replace('{V}',dp.sh.Version));doc.close();wnd.focus();}}};dp.sh.Toolbar.Create=function(highlighter) {var div=document.createElement('DIV');div.className='tools';for(var name in dp.sh.Toolbar.Commands) {var cmd=dp.sh.Toolbar.Commands[name];if(cmd.check!=null&&!cmd.check(highlighter)) continue;div.innerHTML+=''+cmd.label+'';} return div;} dp.sh.Toolbar.Command=function(name,sender) {var n=sender;while(n!=null&&n.className.indexOf('dp-highlighter')==-1) n=n.parentNode;if(n!=null) dp.sh.Toolbar.Commands[name].func(sender,n.highlighter);} dp.sh.Utils.CopyStyles=function(destDoc,sourceDoc) {var links=sourceDoc.getElementsByTagName('link');for(var i=0;i');} dp.sh.Utils.FixForBlogger=function(str) {return(dp.sh.isBloggerMode==true)?str.replace(/
|<br\s*\/?>/gi,'\n'):str;} dp.sh.RegexLib={MultiLineCComments:new RegExp('/\\*[\\s\\S]*?\\*/','gm'),SingleLineCComments:new RegExp('//.*$','gm'),SingleLinePerlComments:new RegExp('#.*$','gm'),DoubleQuotedString:new RegExp('"(?:\\.|(\\\\\\")|[^\\""\\n])*"','g'),SingleQuotedString:new RegExp("'(?:\\.|(\\\\\\')|[^\\''\\n])*'",'g')};dp.sh.Match=function(value,index,css) {this.value=value;this.index=index;this.length=value.length;this.css=css;} dp.sh.Highlighter=function() {this.noGutter=false;this.addControls=true;this.collapse=false;this.tabsToSpaces=true;this.wrapColumn=80;this.showColumns=true;} dp.sh.Highlighter.SortCallback=function(m1,m2) {if(m1.indexm2.index) return 1;else {if(m1.lengthm2.length) return 1;} return 0;} dp.sh.Highlighter.prototype.CreateElement=function(name) {var result=document.createElement(name);result.highlighter=this;return result;} dp.sh.Highlighter.prototype.GetMatches=function(regex,css) {var index=0;var match=null;while((match=regex.exec(this.code))!=null) this.matches[this.matches.length]=new dp.sh.Match(match[0],match.index,css);} dp.sh.Highlighter.prototype.AddBit=function(str,css) {if(str==null||str.length==0) return;var span=this.CreateElement('SPAN');str=str.replace(/ /g,' ');str=str.replace(/');if(css!=null) {if((/br/gi).test(str)) {var lines=str.split(' 
');for(var i=0;ic.index)&&(match.index/gi,'\n');var lines=html.split('\n');if(this.addControls==true) this.bar.appendChild(dp.sh.Toolbar.Create(this));if(this.showColumns) {var div=this.CreateElement('div');var columns=this.CreateElement('div');var showEvery=10;var i=1;while(i<=150) {if(i%showEvery==0) {div.innerHTML+=i;i+=(i+'').length;} else {div.innerHTML+='·';i++;}} columns.className='columns';columns.appendChild(div);this.bar.appendChild(columns);} for(var i=0,lineIndex=this.firstLine;i0;i++) {if(Trim(lines[i]).length==0) continue;var matches=regex.exec(lines[i]);if(matches!=null&&matches.length>0) min=Math.min(matches[0].length,min);} if(min>0) for(var i=0;i

ページビューの合計