<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
		xmlns:xhtml="http://www.w3.org/1999/xhtml"
>

<channel>
	<title>KonifarPod</title>
	<atom:link href="http://konifar.com/feed" rel="self" type="application/rss+xml" />
	<link>http://konifar.com</link>
	<description></description>
	<lastBuildDate>Sat, 04 Oct 2014 11:16:45 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.2.26</generator>
<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://konifar.com/feed" />
	<item>
		<title>同じ声のアニメキャラを検索できるサービス『WhoVoice』作ってみた</title>
		<link>http://konifar.com/1540</link>
		<comments>http://konifar.com/1540#comments</comments>
		<pubDate>Sat, 04 Oct 2014 11:10:02 +0000</pubDate>
		<dc:creator><![CDATA[Konifar]]></dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://konifar.com/?p=1540</guid>
		<description><![CDATA[同じ声のアニメキャラを検索できるWhoVoiceというサービスを作りました。その ... <p><a href="http://konifar.com/1540">同じ声のアニメキャラを検索できるサービス『WhoVoice』作ってみた</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></description>
				<content:encoded><![CDATA[<p>同じ声のアニメキャラを検索できる<a href="http://www.who-voice.com/" class="broken_link" rel="nofollow">WhoVoice</a>というサービスを作りました。その過程で色々考えることもあったのでまとめておきます。</p>
<p> </p>
<h2>発端は・・・</h2>
<p>なんで作ったかというと理由は色々あるんですが、嫁とアニメ見てる時に頻繁に発生するやりとりが発端です。</p>
<p> </p>
<p>〜 深夜アニメを見ながら 〜</p>
<p style="font-size: 14px;"><span style="color: #ff2600;">俺</span>「<strong>なんかこの声聞いたことある</strong>」</p>
<p style="font-size: 14px;"><span style="color: #0433ff;">嫁</span>「え？誰？」</p>
<p style="font-size: 14px;"><span style="color: #ff2600;">俺</span>「ほら、あの人。<a href="http://psycho-pass.com/">サイコパス</a>に出てた、<strong>一番かっこいいキャラの人</strong>」</p>
<p style="font-size: 14px;"><span style="color: #0433ff;">嫁</span>「名前は？」</p>
<p style="font-size: 14px;"><span style="color: #ff2600;">俺</span>「出てこない・・・。<strong>黒髪で、常守監視官と一番仲いい人</strong>」</p>
<p style="font-size: 14px;"><span style="color: #0433ff;">嫁</span>「えー。。。」</p>
<p style="font-size: 14px;"><span style="color: #ff2600;">俺</span>「（Wikiで調べる）あ！<strong>狡噛さん</strong>です！」</p>
<p style="font-size: 14px;"><span style="color: #0433ff;">嫁</span>「あー！」</p>
<p style="font-size: 14px;"><span style="color: #ff2600;">俺</span>「（Wikiを見ながら）<strong>SAOのキバオウ</strong>も同じ声なのか！」</p>
<p style="font-size: 14px;"><span style="color: #0433ff;">嫁</span>「キバオウって誰だっけ？」</p>
<p style="font-size: 14px;"><span style="color: #ff2600;">俺</span>「（Googleで調べる）これこれ」</p>
<p style="font-size: 14px;"><span style="color: #0433ff;">嫁</span>「あー！へぇ！<strong>シュタゲのダルも同じだよねぇ</strong>」</p>
<p style="font-size: 14px;"><span style="color: #ff2600;">俺</span>「<strong>！！すごい！声優さんすごい！</strong>」</p>
<p> </p>
<p>こんな感じのやりとりがよく発生するんですが、これ結構めんどいんですよね。</p>
<p>Googleでアニメタイトル検索してWiki開いて、登場人物セクションを開いて該当のキャラを見つけて、声優のページに遷移して出演作品セクションを開いて、</p>
<p>それでようやく同じ声のキャラのリストを見れても、思い浮かばないキャラは別途Googleで検索して画像を見たりして。</p>
<p> </p>
<p><strong>このキャラもやってるの！？</strong>という発見があるのはすごく面白いんですが、もう毎回調べるのめんどくて。同じキャラ検索サービスとかないかなと色々探したんですけど見当たらず・・・。</p>
<p>じゃあ自分で作るか、ということで作りました。</p>
<p> </p>
<h2>絵に書いてみる</h2>
<p>まず、絵を書きながらどんなの作ろうかなぁと考えていきました。</p>
<p><img class="colorbox-1540"  title="whovoice1.jpg" src="http://konifar.com/wp-content/uploads/whovoice1.jpg" alt="Whovoice1" width="600" height="337" border="0" /></p>
<p><img class="colorbox-1540"  title="whovoice2.jpg" src="http://konifar.com/wp-content/uploads/whovoice2.jpg" alt="Whovoice2" width="600" height="337" border="0" /></p>
<p> </p>
<p>同じ声のキャラを検索したいなぁ、くらいのふわっとした感じでしたが、書きながら１人ブレストみたいにしているうちに色々やりたいことが浮かんできて、なんとなく仕様が決まってきました。</p>
<ul>
<li>必須なのは、作品、キャラ、声優。それぞれ画像は必須。</li>
<li>キャラの名セリフを表示したい。（本当は声再生できるようにしたいけど）</li>
<li>今期のアニメとかはすぐ見れるようにしたい。</li>
<li>シータとドラミちゃんが一緒、みたいな面白い組み合わせを作れるようにしたい。</li>
<li>ビックリ！ボタンみたいのをつけて、意外なキャラの組み合わせを順に表示したい。</li>
<li>検索は、ひらがなでも英語でも何でも検索できるようにしたい。</li>
</ul>
<p> </p>
<h2>実装はじめる</h2>
<p>このへんは書いてもあんまりおもしろくないので、やったことをさらっと。詳しくは別途書こうと思います。</p>
<ul>
<li>とりあえず勉強のためにRails4でやろうと決める</li>
<li>WikiにDB構造とか環境とか色々ちゃんと書いてやる気出す</li>
<li>Twitter Bootstrapは使わない。自分でデザインしてみると決める</li>
<li>自分でデザインするために赤塚さんの<a href="https://speakerdeck.com/ken_c_lo/zuruidezaintekunituku2013-plus-semihuratuto-version">ズルいデザイン</a>を熟読</li>
<li>ズルいデザインのとおりにsassを作成。テーマカラーや背景を決める</li>
<li>アイコンはfont awesomeで。assetsは背景画像のみにする</li>
<li>Google fontでテーマフォントを決定</li>
<li>jQueryは使わない。zepto.js+backbone.jsでやると決める</li>
<li>ざっと画面を作る</li>
<li>アニメデータは<a href="http://lain.gr.jp/">アニメデータベースlain</a>をクロールして取ってくる</li>
<li>クロールさせてくださいメールを管理者に送ってOKをもらう</li>
<li>Railsのクローラの勉強をして、<a href="https://github.com/chriskite/anemone">Anemone</a> + <a href="http://www.nokogiri.org/">Nokogiri</a> でやることに決定</li>
<li>AnemoneのstorageにmongoDBを使うことになったのでmongoDBをちょっと勉強</li>
<li>ひらがな、カタカナ、ローマ字でも検索できるように、<a href="http://developer.yahoo.co.jp/webapi/jlp/furigana/v1/furigana.html">YahooのルビふりAPI</a>を利用</li>
<li>アニメ作品、声優、キャラDBを作るバッチを作成</li>
<li>ルビふりバッチを作成</li>
</ul>
<p> </p>
<h2>やる気がなくなる</h2>
<p>で、深夜と土日使って1週間くらいでとりあえず動くところまで行ったんですが、<strong>やる気が一気になくなってしまいました。</strong></p>
<p>原因は明確で、つい楽しくなって色々構想を広げすぎた挙句めんどくなってしまったんですよね。つまり<strong>自爆</strong>です。</p>
<p>自爆の流れを思い出してみるとこんな感じ。</p>
<p>同じ声のキャラで、<a href="http://matome.naver.jp/odai/2133217240762760901">こんな感じ</a>のまとめ作れたら面白そう！ ⇒ でもそのためには登録画面が必要だなぁ。 ⇒ どういう画面がいいかな ⇒ あ、そしたらシェアボタンとかもほしいかも ⇒ 登録ボタンとか色々どこにつけよう・・・ ⇒ ユーザー登録もユーザーページも必要だな・・・ ⇒ <strong>めんどくさい</strong></p>
<p> </p>
<p>仕事が死ぬほど忙しくなったのもあり、<strong>ここで半年くらい休眠することになります。</strong></p>
<p><strong><br /></strong></p>
<h2>復活する</h2>
<p>という感じで半年以上眠っていたわけですが、その間もアニメを見ながら同じようにWikiを調べて声優見ては<strong>「え？！このキャラ同じなの？！」</strong>ということが何度もあり、そのたびに歯がゆい思いをしていました。</p>
<p>その思いが強まっていって復活に至ったというのもあるのですが、どちらかというと理由は別で、業務外で色々コード書いた方が仕事にもいい影響が出るなとひしひし感じたというのが大きいです。</p>
<p>実はちょっと前にコスプレイヤー向けの<a href="http://weekly.ascii.jp/elem/000/000/231/231760/">コスレーダー</a>というアプリを作ったんですが、業務外でコード書いてると本当に勉強になることが多かったんですよね。</p>
<p>今はRailsよりAndroid Javaを書くことが多いんですが、Androidで試したいライブラリや実装がたくさんあってもイキナリ業務で試すわけにもいかず。じゃあ途中まで作ってあるサービスをAPI化してAndroidの勉強しようかなと考えたわけです。</p>
<p> </p>
<p>で、そもそもめんどくさくなった原因は<strong>色々手を広げようとしすぎてめんどくなったこと</strong>だったので、原点に戻って自分が何がしたかったのか考えなおしてみました。そこで気づいたのは、<strong>なんか色々やろうとしたけど結局同じ声のキャラを検索できればそれだけでいい</strong>ってことなんですよね。むしろそれだけでシンプルにつくった方が楽だし使いやすいよなと考えなおしました。もしかしてこれがMostValuableProductってやつなんですかね？</p>
<p> </p>
<p>検索だけであればもうほとんどできていたので、<a href="http://activeadmin.info/">ActiveAdmin</a>使って管理画面を作ってHerokuにデプロイしてバッチを実行したら動くようになりました。Herokuに慣れていない自分には結構ハマることも多くて四苦八苦しましたが、2日くらいで終わりました。Herokuすごい。</p>
<p>AndroidのAPI作る目的だったはずなんですが、結局気づいたらWebで表示して管理画面も作っていて、結局Androidの勉強はこれからなんですけど。。 <a href="https://github.com/square/dagger">Dagger</a>とか<a href="http://robolectric.org/">Robolectric</a>とか使ってみようと思います。</p>
<p> </p>
<h2>使ってみる</h2>
<p>できたので使ってみたんですが、我ながら良い物作ったなぁとしみじみしました。</p>
<p> </p>
<p>『作品・声優・キャラで検索』から、アニメやキャラを検索します。YahooのルビふりAPIのおかげで、<strong>『化物語』『あららぎ』『hanazawakana』</strong>など、わりと曖昧な感じでも大丈夫です。まだ完璧じゃないので出ないこともありますが。</p>
<p><img class="colorbox-1540"  title="whovoice6.png" src="http://konifar.com/wp-content/uploads/whovoice6.png" alt="Whovoice6" width="337" height="600" border="0" /></p>
<p> </p>
<p><strong>『化物語』</strong>のページに行くとこんな感じ。セリフを入れられるのは本当にいい機能だなと思いました。</p>
<p><img class="colorbox-1540"  title="whovoice3.png" src="http://konifar.com/wp-content/uploads/whovoice3.png" alt="Whovoice3" width="337" height="600" border="0" /></p>
<p> </p>
<p>八九寺のページで見てみると・・・</p>
<p><img class="colorbox-1540"  title="whovoice5.png" src="http://konifar.com/wp-content/uploads/whovoice5.png" alt="Whovoice5" width="337" height="600" border="0" /></p>
<p> </p>
<p><strong>？！キュウべぇ？！</strong>まじか・・・！そう言われてみれば同じ気がするけど、そうかぁ・・・。まぁこんな感じで簡単にキャラ検索できてとてもいい感じになりました。</p>
<p>他にも、<strong>トトロのサツキ＝タッチの南＝サイコパスのドミネーター</strong>という事実には震えました。<strong>DEATH NOTEのニア</strong>も同じ声なんですね。</p>
<p><img class="colorbox-1540"  title="whovoice7.png" src="http://konifar.com/wp-content/uploads/whovoice7.png" alt="Whovoice7" width="337" height="600" border="0" /></p>
<p> </p>
<p>ちなみに管理画面はActiveAdminというgem使ってほぼ何もせずに作れたのですが、こんな感じでテーブルごとにIndex、Show、Update、Deleteのアクションができます。CarrierWaveとか使って画像のアップロードとかしている場合も、特に何もしなくても動くので楽ちんです。</p>
<p><img class="colorbox-1540"  title="whovoice4.png" src="http://konifar.com/wp-content/uploads/whovoice4.png" alt="Whovoice4" width="337" height="600" border="0" /></p>
<p> </p>
<h2>作ってみた感想</h2>
<p>つらつら書いてきましたが、色々考えたことをざーっと残します。</p>
<ul>
<li>デザイナーさんに感謝。デザイン考えながら開発するの大変。</li>
<li><a href="https://speakerdeck.com/ken_c_lo/zuruidezaintekunituku2013-plus-semihuratuto-version">ズルいデザイン</a>すごい。赤塚さんのスライドめっちゃ読みました。</li>
<li>sassとかjsとかめっちゃ忘れてる。業務外で書いとかないとダメ。</li>
<li>クロール初めてやったけど、意外と簡単にできた。一度やったことがあるってのがいつか本業にも活きてくると思う。</li>
<li>クロール許可くれたlainさんに感謝。</li>
<li>MongoDBも初めて触れてよかった。</li>
<li>CarrierWaveの画像アップロードも自分で初めてやれていい経験になった。</li>
<li>総じて、仕事でやれてないこといっぱいできてよかった。</li>
<li>けど色々やろうとしすぎるとやる気なくなっちゃうので注意が必要。</li>
<li>やる気なくなった時は、そもそも何がしたかったんだっけ？と思い出すの大事。</li>
<li>とりあえずショボくてもリリースまでやったらなんか気分いい。</li>
<li>次はAndroidアプリ作る目的だったけど、Webをちゃんと作りたくなってきた。</li>
</ul>
<p> </p>
<p>利用規約も連絡先も何もないのでサービスと言っていいかわからないレベルですが、<strong>たぶん僕はほぼ毎日使うと思うのでとりあえずそれでいいかな</strong>と思います。</p>
<p>この俺得サービス <a href="http://www.who-voice.com" class="broken_link" rel="nofollow">WhoVoice</a>、もし<strong>「私も得するよ！」</strong>と思ったら使ってみてください。</p>
<p>以上！</p>
<p><a href="http://konifar.com/1540">同じ声のアニメキャラを検索できるサービス『WhoVoice』作ってみた</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></content:encoded>
			<wfw:commentRss>http://konifar.com/1540/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://konifar.com/1540" />
	</item>
		<item>
		<title>AndroidでCustomDrawableStateが動かない時に確認すべきこと</title>
		<link>http://konifar.com/1528</link>
		<comments>http://konifar.com/1528#comments</comments>
		<pubDate>Mon, 29 Sep 2014 03:30:38 +0000</pubDate>
		<dc:creator><![CDATA[Konifar]]></dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://konifar.com/?p=1528</guid>
		<description><![CDATA[AndroidでCustomDrawableStateを作ったのにうまく機能しな ... <p><a href="http://konifar.com/1528">AndroidでCustomDrawableStateが動かない時に確認すべきこと</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></description>
				<content:encoded><![CDATA[<p>AndroidでCustomDrawableStateを作ったのにうまく機能しない問題にハマったのでメモ。</p>
<p>CustomDrawableStateの作り方自体はこちら ⇒ <a href="http://charlesharley.com/2012/programming/custom-drawable-states-in-android/" class="broken_link" rel="nofollow">Custom drawable states in Android</a></p>
<p> </p>
<h2>（１）onCreateDrawableStateが呼ばれているか</h2>
<p>上記の手順通りに実装しても、onCreateDrawableStateが呼ばれないことがあります。デバッグして呼ばれていなければ、android:duplicateParentState=“true”をレイアウトにつけると解決するかもしれません。</p>
<pre class="brush: xml; title: ; notranslate">
&lt;RelativeLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:duplicateParentState=&quot;true&quot;&gt;
    ...
&lt;/RelativeLayout&gt;
</pre>
<p>参考 : <a href="http://stackoverflow.com/questions/10223871/oncreatedrawablestate-never-call">onCreateDrawableState never call</a></p>
<p> </p>
<h2>（２）State更新時にrefreshDrawableStateを呼んでいるか</h2>
<p>これを呼ばないと表示が更新されません。statusをセットしたら、ちゃんと呼んであげましょう。</p>
<pre class="brush: java; title: ; notranslate">
public void setError(boolean isError) {
    this.isError = isError;
    refreshDrawableState();
}
</pre>
<p> </p>
<h2>（３）custom drawable の記述が間違っていないか</h2>
<p>例えばこのように記述していた場合、state_errorになっても色は変わりません。</p>
<pre class="brush: xml; title: ; notranslate">
&lt;xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;&gt;
&lt;selector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;&gt;
    &lt;item android:drawable=&quot;@drawable/bg_white&quot; android:state_pressed=&quot;false&quot; /&gt;
    &lt;item android:drawable=&quot;@drawable/bg_red&quot; app:state_error=&quot;true&quot; /&gt;
&lt;/selector&gt;
</pre>
<p>上から順に評価されていくため、state_pressedじゃないから当てはまると判断されて上のitemが適用されてしまいます。</p>
<p>ちゃんとstateを指定してあげれば動くはずです。</p>
<pre class="brush: xml; title: ; notranslate">
&lt;xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;&gt;
&lt;selector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;&gt;
    &lt;item android:drawable=&quot;@drawable/bg_white&quot; android:state_pressed=&quot;false&quot; app:state_error=“false&quot; /&gt;
    &lt;item android:drawable=&quot;@drawable/bg_red&quot; app:state_error=&quot;true&quot; /&gt;
&lt;/selector&gt;
</pre>
<p> </p>
<p> </p>
<p>こんなつまらないところでハマる人が1人でも減ることを祈ります。以上！</p>
<p><a href="http://konifar.com/1528">AndroidでCustomDrawableStateが動かない時に確認すべきこと</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></content:encoded>
			<wfw:commentRss>http://konifar.com/1528/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://konifar.com/1528" />
	</item>
		<item>
		<title>GenymotionでINSTALL_FAILED_MISSING_SHARED_LIBRARYが出た時の対処法</title>
		<link>http://konifar.com/1525</link>
		<comments>http://konifar.com/1525#comments</comments>
		<pubDate>Thu, 18 Sep 2014 22:29:29 +0000</pubDate>
		<dc:creator><![CDATA[Konifar]]></dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://konifar.com/?p=1525</guid>
		<description><![CDATA[超高速エミュレータのGenymotionにアプリインストールしようとして、Fai ... <p><a href="http://konifar.com/1525">GenymotionでINSTALL_FAILED_MISSING_SHARED_LIBRARYが出た時の対処法</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></description>
				<content:encoded><![CDATA[<p>超高速エミュレータの<a href="http://www.genymotion.com/">Genymotion</a>にアプリインストールしようとして、Failure [INSTALL_FAILED_MISSING_SHARED_LIBRARY] が出た時の対処方法です。</p>
<p>結論から言うとGoogle Appsがインストールされていないのが原因で、エミュレータに手動でインストールすれば解決します。</p>
<p>参考にしたstackoverflowはこちら ⇒ <a href="http://stackoverflow.com/questions/20635134/genymotion-emulator-installation-error-install-failed-missing-shared-library">Genymotion Emulator : Installation error: INSTALL_FAILED_MISSING_SHARED_LIBRARY</a></p>
<p> </p>
<h2>（１）ARM Translation_v1.1のインストール</h2>
<p>以下のサイトから『ARM Translation_v1.1』をダウンロードします。</p>
<p><a href="http://forum.xda-developers.com/showthread.php?t=2528952" class="broken_link" rel="nofollow">[GUIDE] Genymotion | Installing ARM Translation and GApps[Updated Nov.16] – xda-developers</a></p>
<p>Genymotionのエミュレータを起動して、ダウンロードしたzipファイルをDrag&amp;Dropします。何度かダイアログが表示されるので、OKを押した後で再起動してください。</p>
<p><img class="colorbox-1525"  title="genymotion1.png" src="http://konifar.com/wp-content/uploads/genymotion1.png" alt="Genymotion1" width="420" height="174" border="0" /></p>
<p><img class="colorbox-1525"  title="genymotion2.png" src="http://konifar.com/wp-content/uploads/genymotion2.png" alt="Genymotion2" width="420" height="157" border="0" /></p>
<p> </p>
<h2>（２）Google Apps for Android をインストール</h2>
<p>先ほどと同じサイトから、Google Apps for Androidをダウンロードします。</p>
<p><a href="http://forum.xda-developers.com/showthread.php?t=2528952" class="broken_link" rel="nofollow">[GUIDE] Genymotion | Installing ARM Translation and GApps[Updated Nov.16] – xda-developers</a></p>
<p>バージョンごとに用意されているので、起動したエミュレータのバージョンに合わせてインストールしてください。Android2.xはないっぽいですが。。。</p>
<p>ダウンロードしたら、先ほどと同じようにエミュレータにDrag&amp;Dropしてから再起動すると完了です。</p>
<p> </p>
<h2>（３）確認</h2>
<p>GooglePlayStoreがインストールされていれば成功です。</p>
<p><img class="colorbox-1525"  title="genymotion3.png" src="http://konifar.com/wp-content/uploads/genymotion3.png" alt="Genymotion3" width="468" height="243" border="0" /></p>
<p> </p>
<p>ここまでできていれば、おそらくエラーなくインストールできるようになっているはずなので試してみてください。</p>
<p> </p>
<p>以上！</p>
<p><a href="http://konifar.com/1525">GenymotionでINSTALL_FAILED_MISSING_SHARED_LIBRARYが出た時の対処法</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></content:encoded>
			<wfw:commentRss>http://konifar.com/1525/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://konifar.com/1525" />
	</item>
		<item>
		<title>AndroidQueryをやめてRetrofitを使ったら捗った話</title>
		<link>http://konifar.com/1511</link>
		<comments>http://konifar.com/1511#comments</comments>
		<pubDate>Thu, 11 Sep 2014 22:56:23 +0000</pubDate>
		<dc:creator><![CDATA[Konifar]]></dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[AndroidQuery]]></category>

		<guid isPermaLink="false">http://konifar.com/?p=1511</guid>
		<description><![CDATA[AndroidでAPIとやり取りする場合、HttpURLConnectionとか ... <p><a href="http://konifar.com/1511">AndroidQueryをやめてRetrofitを使ったら捗った話</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></description>
				<content:encoded><![CDATA[<p>AndroidでAPIとやり取りする場合、HttpURLConnectionとか使ってスクラッチで書いてもいいんですが、ライブラリを使ったほうが簡単に書けます。</p>
<p>そのような便利ライブラリの１つに<a href="https://code.google.com/p/android-query/wiki/AsyncAPI">AndroidQuery</a>というのがあります。名前からわかるとおりjQueryに影響を受けており、メソッドチェーンを使って簡単にGET・POSTを実装できます。</p>
<p>僕ももともとAndroidQueryを使っていたんですが、今回<a href="http://square.github.io/retrofit/">Retforit</a>というライブラリに置き換えたところコード量も減りとてもいい感じだったのでメモしておきます。</p>
<p> </p>
<h2>（１）Before After</h2>
<p>まずはBefore Afterから。</p>
<p><strong>[Before: AndroidQuery]</strong></p>
<pre class="brush: java; title: ; notranslate">
private void loadUsers() {
    final AjaxCallback cb = new AjaxCallback() {
        @Override
        public void callback(String url, JSONArray json, AjaxStatus status) {
            if (json != null) {
                final Gson gson = new GsonBuilder().setDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;).create();
                final Type type = new TypeToken&lt;List&gt;() {}.getType();
                List&lt;User&gt; users = gson.fromJson(json.toString(), type);
                Log.d(TAG, &quot;success&quot;);
            } else { 
                Log.e(TAG, status.getMessage() + &quot;&quot;);
            }
        }
    };
    new AQuery(this).ajax(url, JSONArray.class, cb);
}
</pre>
<p> </p>
<p><strong>[After: Retrofit]</strong></p>
<pre class="brush: java; title: ; notranslate">
private void loadUsers() {
    MainApplication.API.getUsers(new Callback&lt;List&gt;() {
        @Override
        public void failure(RetrofitError e) {
            Log.e(TAG, e.getMessage() + &quot;&quot;);
        }

        @Override
        public void success(List&lt;User&gt; users, Response response) {
            Log.d(TAG, &quot;success&quot;);
        }
    });
}
</pre>
<p> </p>
<p>わかりやすくするために最低限の部分だけ引用しましたが、かなりスッキリしました。メリットをまとめるとこんな感じです。</p>
<ul>
<li>Callbackクラスのインターフェースメソッドがわかりやすくていい感じ。</li>
<li>URLを各処理の中ではなく別のクラスにまとめて書いておくことができて見通しがいい。</li>
<li>Gsonでのparseも初期化処理で記述しておけば各処理の中で書かなくていい。</li>
<li>通信部分だけのライブラリなのでAndroidQueryよりもずっと軽量。</li>
<li>RestAdapterというクラスを使うことでDIしやすくなる。</li>
<li>モック用のライブラリも梱包されておりテストも書きやすい。</li>
</ul>
<p> </p>
<p>導入も簡単だったので、APIを１つずつAndroidQueryからのせかえていきました。</p>
<p> </p>
<h2>（２）Retrofit導入手順</h2>
<p>Retrofitを使う手順は簡単です。</p>
<h3>１．build.gradleにdependenciesを記述。</h3>
<p>Retrofitのライブラリをインポートするための設定を書きます。</p>
<pre class="brush: java; title: ; notranslate">
dependencies {
    compile 'com.squareup.retrofit:retrofit:1.6.0'
}
</pre>
<p> </p>
<h3>２．API用のインターフェースを作成</h3>
<p>インターフェースクラスを作成します。僕はserviceパッケージ内にApiServiceという名前で作成しました。</p>
<pre class="brush: java; title: ; notranslate">
public interface ApiService {

    public static final String API_URL = &quot;http://konifar.com&quot;;

    static final String PATH_USERS = &quot;/users&quot;;
    static final String EXT_JSON = &quot;.json&quot;;

    @GET(PATH_USERS + EXT_JSON)
    void getUsers(Callback&lt;List&lt;User&gt;&gt; cb);
}
</pre>
<p> </p>
<h3>３．Applicationクラスで初期化</h3>
<p>先ほどのインターフェースを使って、Applicationクラスの中で初期化処理を書きます。</p>
<pre class="brush: java; title: ; notranslate">
public class MainApplication extends Application {

    private static Gson GSON = new GsonBuilder().setDateFormat(Constants.JSON_DATE_FORMAT).create();

    private static RestAdapter REST_ADAPTER = new RestAdapter.Builder()
    .setEndpoint(ApiService.APP_URL).setConverter(new GsonConverter(GSON)).build();

    public static ApiService API = REST_ADAPTER.create(ApiService.class);

}
</pre>
<p>これで、通信したいところで、MainApplication.API.getUsers のように呼び出すことができるようになります。</p>
<p> </p>
<h3>４．APIを増やす時はApiServiceにAPIを追加</h3>
<p>APIを増やす時は、ApiServiceにメソッドを追加するだけです。ApiServiceクラスにまとまっているのでとても見通しがよいです。</p>
<p>またインターフェースにしているので、モッククラスを作ってDIすることも簡単にできます。<a href="http://square.github.io/dagger/">Dagger</a>との相性バツグンです。</p>
<p>multipart POSTにも対応しており、こんな感じでメソッドを定義すれば画像の送信もできます。</p>
<pre class="brush: java; title: ; notranslate">
@Multipart
@POST(PATH_USERS + EXT_JSON)
void postUser(@Part(PARAM_NAME) TypedString name, @Part(PARAM_IMAGE) TypedFile image, Callback&lt;User&gt; cb);
</pre>
<p> </p>
<p> </p>
<p>大きめのアプリになるとAPIの数も比例して多くなるので、呼び出し部分はなるべくシンプルに書けるようにした方が開発スピード上がります。Retrofitとてもいい感じなので、RESTfulなAPIで開発している方は試してみてはどうでしょうか。</p>
<p>以上！</p>
<p><a href="http://konifar.com/1511">AndroidQueryをやめてRetrofitを使ったら捗った話</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></content:encoded>
			<wfw:commentRss>http://konifar.com/1511/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://konifar.com/1511" />
	</item>
		<item>
		<title>CircleCIでAndroidテストを行う方法</title>
		<link>http://konifar.com/1504</link>
		<comments>http://konifar.com/1504#comments</comments>
		<pubDate>Thu, 11 Sep 2014 11:07:32 +0000</pubDate>
		<dc:creator><![CDATA[Konifar]]></dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[circleCI]]></category>

		<guid isPermaLink="false">http://konifar.com/?p=1504</guid>
		<description><![CDATA[お手軽なCIツールのCircleCIとGithubを連携して、ビルドする方法です ... <p><a href="http://konifar.com/1504">CircleCIでAndroidテストを行う方法</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></description>
				<content:encoded><![CDATA[<p>お手軽なCIツールの<a href="https://circleci.com/">CircleCI</a>とGithubを連携して、ビルドする方法です。基本的なGithubとの連携は<a href="https://circleci.com/docs/getting-started">公式ドキュメント</a>を参照していただくとして、今回はAndroidのコードをgithubにpushしたらCircleCIでビルドする、というところを書いておきます。</p>
<p> </p>
<p>CircleCIは、プロジェクトルートのcircle.ymlを参照して動作します。Androidでも同様で、ルートにcircle.ymlを作ります。このあたりは<a href="https://circleci.com/docs/android">公式ドキュメント</a>にも書いてあります。ただ、このcircle.ymlの中身を記述するのがちょっと面倒で、必要なAndroidSDKやビルドツールのインストールをちゃんと書いてあげないと動きません。supportライブラリを使っている場合も別途色々書かなければいけなくて、色々ハマった結果こんな感じになりました。</p>
<p> </p>
<pre class="brush: ruby; title: ; notranslate">
machine:
  environment:
    ANDROID_HOME: /usr/local/android-sdk-linux

dependencies:
  pre:
    - echo y | android update sdk --no-ui --all --filter &quot;platform-tools,tools&quot;
    - echo y | android update sdk --no-ui --all --filter &quot;android-19,build-tools-19.1.0&quot;
    - echo y | android update sdk --no-ui --all --filter &quot;extra-android-m2repository&quot;
    - echo y | android update sdk --no-ui --all --filter &quot;extra-android-support&quot;
    - echo y | android update sdk --no-ui --all --filter &quot;extra-google-m2repository&quot;
    - echo y | android update sdk --no-ui --all --filter &quot;extra-google-google_play_services&quot;
    - echo y | android update sdk --no-ui --all --filter &quot;addon-google_apis-google-19&quot;
    - echo y | android update lib-project --path ./appcompat --target android-19
    - echo y | android update project --path ./core --library ../appcompat --target android-19

  cache_directories:
    - ~/.android
  override:
    - ./gradlew dependencies
</pre>
<p> </p>
<p>dependencies > preの中でやっている下準備が重要です。ハマった時のエラーメッセージを全部はメモできていないのですが、ざっくり説明するとこんな感じです。</p>
<p> </p>
<pre class="brush: ruby; title: ; notranslate">
  pre:
    # toolsをアップデート
    - echo y | android update sdk --no-ui --all --filter &quot;platform-tools,tools&quot;

    # SDKとビルドツールのインストール。適宜バージョンを置き換えてください。
    - echo y | android update sdk --no-ui --all --filter &quot;android-19,build-tools-19.1.0&quot;

    # supportライブラリをインストールするために必要です。これがないと下記のエラーが出ました。
    # ① projectsCould not resolve com.android.support:support-v4:20.0.+.
    # ② projectsCould not GET 'http://maven.aviary.com/repo/release/com/android/support/support-v4/'. Received status code 403 from server: Forbidden
    - echo y | android update sdk --no-ui --all --filter &quot;extra-android-m2repository&quot;
    - echo y | android update sdk --no-ui --all --filter &quot;extra-android-support&quot;

    # GCM等、GooglePlayServicesを使っている場合に必要です。
    - echo y | android update sdk --no-ui --all --filter &quot;extra-google-m2repository&quot;
    - echo y | android update sdk --no-ui --all --filter &quot;extra-google-google_play_services&quot;

    # GoogleMap等を使っている場合に必要です。
    - echo y | android update sdk --no-ui --all --filter &quot;addon-google_apis-google-19&quot;

    # appcompat-v7以降を使っている場合に必要です。これがないと下記のエラーが出ました。
    # projectsCould not GET 'http://maven.aviary.com/repo/release/com/android/support/appcompat-v7/'. Received status code 403 from server: Forbidden
    - echo y | android update lib-project --path ./appcompat --target android-19
    - echo y | android update project --path ./core --library ../appcompat --target android-19
</pre>
<p> </p>
<p>testも一応走るのですが、<a href="http://robolectric.org/">Robolectric</a>がうまく動かないので調査中です。。。</p>
<p>以上！</p>
<p><a href="http://konifar.com/1504">CircleCIでAndroidテストを行う方法</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></content:encoded>
			<wfw:commentRss>http://konifar.com/1504/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://konifar.com/1504" />
	</item>
		<item>
		<title>Android Studioでプロジェクト全ファイルをフォーマット整形する</title>
		<link>http://konifar.com/1499</link>
		<comments>http://konifar.com/1499#comments</comments>
		<pubDate>Tue, 09 Sep 2014 18:33:45 +0000</pubDate>
		<dc:creator><![CDATA[Konifar]]></dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[AndroidStudio]]></category>

		<guid isPermaLink="false">http://konifar.com/?p=1499</guid>
		<description><![CDATA[コーディングルールに沿ってないファイルを一気にフォーマット整形する方法です。超簡 ... <p><a href="http://konifar.com/1499">Android Studioでプロジェクト全ファイルをフォーマット整形する</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></description>
				<content:encoded><![CDATA[<p>コーディングルールに沿ってないファイルを一気にフォーマット整形する方法です。超簡単です。</p>
<p>コードの入っているapp/srcディレクトリを選択して、<strong>右クリック &gt; Reformat Code</strong> を押します。</p>
<p>ダイアログが出てくるので、<strong>include sub directions </strong>にチェックを入れてRunをクリックします。</p>
<p><img class="colorbox-1499"  title="reformat_all3.png" src="http://konifar.com/wp-content/uploads/reformat_all3.png" alt="Reformat all3" width="572" height="195" border="0" /></p>
<p> </p>
<p>全ファイルを一気にフォーマットかけてくれます。</p>
<p><img class="colorbox-1499"  title="reformat_all2.png" src="http://konifar.com/wp-content/uploads/reformat_all2.png" alt="Reformat all2" width="468" height="100" border="0" /></p>
<p> </p>
<p>終わったら、diffを確認してみましょう。以上！</p>
<p> </p>
<p><a href="http://konifar.com/1499">Android Studioでプロジェクト全ファイルをフォーマット整形する</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></content:encoded>
			<wfw:commentRss>http://konifar.com/1499/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://konifar.com/1499" />
	</item>
		<item>
		<title>Android Studioで保存時に自動整形＋import整理するようにしてみた</title>
		<link>http://konifar.com/1493</link>
		<comments>http://konifar.com/1493#comments</comments>
		<pubDate>Tue, 09 Sep 2014 18:23:30 +0000</pubDate>
		<dc:creator><![CDATA[Konifar]]></dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[Develop]]></category>

		<guid isPermaLink="false">http://konifar.com/?p=1493</guid>
		<description><![CDATA[Commitする前にCommand+Option+Lでフォーマット整形してCo ... <p><a href="http://konifar.com/1493">Android Studioで保存時に自動整形＋import整理するようにしてみた</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></description>
				<content:encoded><![CDATA[<p>Commitする前にCommand+Option+Lでフォーマット整形してControl+Option+Oでimport整理するの面倒だったので、保存時に自動的にフォーマット整形＋import整理するようにしてみました。Android Studioのマクロ機能を使って2分でできたので手順をメモしておきます。</p>
<p> </p>
<h2>（１）マクロ記録開始</h2>
<p>Android Studioには、一連の操作を登録できるマクロ機能があります。</p>
<p><strong>Android Studio &gt; Edit &gt; Macros &gt; Start Macro Recording</strong> を押したあと操作して、終わったら <strong>Stop Macro Recording</strong> を押すだけです。</p>
<p>まずは、<strong>Start Macro Recording</strong> をクリックします。</p>
<p> </p>
<h2>（２）マクロの登録</h2>
<p>今回は、<strong>Reformat Code、</strong><strong>Optimize Import、Save All</strong> の操作を記録したいので</p>
<p><strong>Code &gt; Reformat Code</strong> をクリックしたあと、<strong>Code &gt; Optimize Import</strong> をクリックします。</p>
<p>Optimize Importをクリックしたあとでダイアログが表示された時は、ダイアログの中の Rearrange entries にチェックを入れてRunボタンを押してください。</p>
<p><img class="colorbox-1493"  title="android_studio_1.png" src="http://konifar.com/wp-content/uploads/android_studio_1.png" alt="Android studio 1" width="600" height="143" border="0" /></p>
<p>最後に、File &gt; Save Allをクリックすればマクロの操作は終了です。</p>
<p> </p>
<h2>（３）マクロの保存</h2>
<p><strong>Macros &gt; Stop Macro Recording </strong>をクリックしてマクロの登録を終了します。マクロに名前をつけるよう言われるので、適当な名前をつけてください。</p>
<p><img class="colorbox-1493"  title="android_studio_2.png" src="http://konifar.com/wp-content/uploads/android_studio_2.png" alt="Android studio 2" width="477" height="139" border="0" /><strong> </strong></p>
<p><strong><br /></strong></p>
<h2>（４）ショートカットキーのバインド</h2>
<p>保存は大体Command+Sでやりますから、ショートカットキーを変更しておきます。</p>
<p><strong>Android Studio &gt; Preferences &gt; Keymap &gt; Macros</strong> から、先ほど作ったマクロを選択して右クリック。Add Keyboard Shortcut でCommand+Sをバインドします。元のキーバインドを消していいかという警告が出ると思うので、OKを押してください。</p>
<p><img class="colorbox-1493"  title="android_studio3.png" src="http://konifar.com/wp-content/uploads/android_studio3.png" alt="Android studio3" width="600" height="408" border="0" /></p>
<p> </p>
<h2>（５）マクロのエクスポート</h2>
<p>以上で保存時に自動的にフォーマットがかかるはずです。もしチーム全体でこのマクロの設定を共有したい場合、設定をエクスポート・インポートすることができます。</p>
<p><strong>Android Studio &gt; File &gt; Export Settings</strong> をクリックします。ダイアログに、どの設定をエクスポートするかチェックボックスが並んでいるので、<strong>Macros</strong> だけ選択して他はクリアします。<strong>Key maps</strong>も選んでもいいのですが、独自にキーバインドしている人の設定とコンフリクトする可能性があるので外しておきました。</p>
<p>OKを押すとsettings.jarというファイルをエクスポートできるので、チームメンバーに渡して、<strong>Android Studio &gt; File &gt; Import Settings</strong> からマクロをインポートしてもらいましょう。</p>
<p> </p>
<p> </p>
<p>以上！コードが自動的に読みやすくなっていい感じです。マクロ機能はもっと使いこなせば色々捗りそうですね。</p>
<p><a href="http://konifar.com/1493">Android Studioで保存時に自動整形＋import整理するようにしてみた</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></content:encoded>
			<wfw:commentRss>http://konifar.com/1493/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://konifar.com/1493" />
	</item>
		<item>
		<title>FacebookSDKがMessage Dialogに対応したようなので使ってみた</title>
		<link>http://konifar.com/1485</link>
		<comments>http://konifar.com/1485#comments</comments>
		<pubDate>Tue, 09 Sep 2014 17:41:06 +0000</pubDate>
		<dc:creator><![CDATA[Konifar]]></dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://konifar.com/?p=1485</guid>
		<description><![CDATA[AndroidのFacebookSDKがMessageDialogに対応したらし ... <p><a href="http://konifar.com/1485">FacebookSDKがMessage Dialogに対応したようなので使ってみた</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></description>
				<content:encoded><![CDATA[<p><a href="https://developers.facebook.com/docs/android/share#message-dialog">AndroidのFacebookSDKがMessageDialogに対応した</a>らしいので使ってみました。</p>
<p>MessageDialogというのは、FacebookメッセンジャーアプリでアプリのOpenGraphシェア等を可能にするダイアログです。こんな感じに送れるようになります。</p>
<p><img class="colorbox-1485"  title="facebook_sdk1.png" src="http://konifar.com/wp-content/uploads/facebook_sdk1.png" alt="Facebook sdk1" width="330" height="513" border="0" /></p>
<p>Activityの中でやる場合のコードはこんな感じ。（SDKのインストールや細かい初期化は省略します）</p>
<pre class="brush: java; title: ; notranslate">
    void onClickBtnFacebook() {
        if (FacebookDialog.canPresentMessageDialog(this,
                FacebookDialog.MessageDialogFeature.MESSAGE_DIALOG)) {
            showFacebookMessageDialog();
        } else {
            /*
             * Facebookメッセンジャーがインストールされていない場合にシェアできないので、
             * Facebook本体のシェアダイアログを表示できればここでする。
             */
            showFacebookShareDialog();
        }
    }

    private void showFacebookShareDialog() {
        if (FacebookDialog.canPresentShareDialog(this,
                FacebookDialog.ShareDialogFeature.SHARE_DIALOG)) {
            try {
                FacebookDialog.ShareDialogBuilder builder =
                        new FacebookDialog.ShareDialogBuilder(this)
                                .setPicture(imageUrl)
                                .setName(name)
                                .setDescription(description)
                                .setLink(url);
                builder.build().present();
            } catch (FacebookException e) {
                // error handling
            }
        } else {
            showToast(&quot;Facebook App is not installed.&quot;);
        }
    }

    private void showFacebookMessageDialog() {
        try {
            FacebookDialog.MessageDialogBuilder builder =
                    new FacebookDialog.MessageDialogBuilder(this)
                    .setLink(url)
                    .setName(name)
                    .setCaption(caption)
                    .setPicture(imageUrl)
                    .setDescription(description);
            builder.build().present();
        } catch (FacebookException ex) {
            // error handling
        }
    }
</pre>
<p> </p>
<p>MessageDialogを作る時に指定できるname、url、caption、picture、descriptionが指定できるのですが、メソッドとの対応はこんな感じ。</p>
<p><img class="colorbox-1485"  title="facebook_sdk2.png" src="http://konifar.com/wp-content/uploads/facebook_sdk2.png" alt="Facebook sdk2" width="380" height="513" border="0" /></p>
<p>① setCaption(caption)</p>
<p>② setPicture(imageUrl)</p>
<p>③ setName(name)</p>
<p>④ setLink(url)</p>
<p>⑤ setDesription(description)</p>
<p>当然、タップした時の遷移先を指定するのは④のsetLink()です。</p>
<p> </p>
<p>また、Facebookメッセンジャーがインストールされていない場合には自動的にFacebookが開くなんて気の利いたことはしてくれないので、自分で分岐を書く必要があります。</p>
<p>if (FacebookDialog.canPresentMessageDialog(this, FacebookDialog.MessageDialogFeature.MESSAGE_DIALOG))</p>
<p>でFacebookメッセンジャーが使えるかどうかは確認できるので、falseだった時は通常のFacebookアプリのシェアダイアログが表示されるようにしてみました。</p>
<p> </p>
<p>タイムラインにシェアよりも、メッセンジャー経由でのシェアで入ってきたユーザーはコンバージョン率・継続率ともに高くなる傾向があるので、導入も簡単ですし使ってみてはいかがでしょうか？</p>
<p><a href="http://konifar.com/1485">FacebookSDKがMessage Dialogに対応したようなので使ってみた</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></content:encoded>
			<wfw:commentRss>http://konifar.com/1485/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://konifar.com/1485" />
	</item>
		<item>
		<title>EclipseからAndroid Studioへののせかえ手順まとめ</title>
		<link>http://konifar.com/1471</link>
		<comments>http://konifar.com/1471#comments</comments>
		<pubDate>Wed, 03 Sep 2014 16:00:11 +0000</pubDate>
		<dc:creator><![CDATA[Konifar]]></dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[AndroidStudio]]></category>
		<category><![CDATA[Eclipse]]></category>

		<guid isPermaLink="false">http://konifar.com/?p=1471</guid>
		<description><![CDATA[Android開発するならAndroid Studioという空気が広まってきたの ... <p><a href="http://konifar.com/1471">EclipseからAndroid Studioへののせかえ手順まとめ</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></description>
				<content:encoded><![CDATA[<p>Android開発するならAndroid Studioという空気が広まってきたので、Eclipse+ADTプラグインで作って開発していたプロジェクトをAndroid Studioにのせかえてみました。結構苦労したので、手順をメモしておこうと思います。</p>
<p> </p>
<h2>（１）現状の確認</h2>
<p>元は以下のような環境でした。</p>
<ul>
<li>コードはgitで管理。</li>
<li>クラス数は300個くらい。</li>
<li>mavenもgradleも不使用。ライブラリは/libraryディレクトリにまるごと入れて、Eclipseでプロジェクトを作ったあとインポート。</li>
<li>lib、library合わせて依存ライブラリの数は18個。</li>
</ul>
<p>git管理はしてるものの、クラスがそれなりに多いのに依存関係ぐちゃぐちゃで、EventBusとか便利ライブラリ入れていきたいのにちょっと戸惑うなぁという感じでした。俺だってgradleでライブラリ管理したりコンソールから環境ごとにビルドしたりしたいよ！という思いを胸に秘めながら開発していたわけです。</p>
<p> </p>
<h2>（２）Android Studioのインストール</h2>
<p>まずは<a href="https://developer.android.com/sdk/installing/studio.html">Android Studio</a>をインストールします。2014/09時点では0.8.6でした。インストールするとAndroid SDKも一緒に入っています。起動するとAndroid SDKのパスはAndroid Studio.app/sdk/ になっていますので、変えたければ『<a href="http://qiita.com/hidekuro/items/d2aadb907c617a4554db">Android StudioにおけるAndroidSDKやJDKのパス設定</a>』を参考に後で変えてください。まぁ変えなくてもいいと思いますが。</p>
<p> </p>
<h2>（３）プロジェクトの新規作成</h2>
<p>EclipseからAndroid Studioへのインポートは、Eclipseのエクスポート機能を使えば簡単に行えます。詳しくは<a href="http://techbooster.org/android/environment/16158/">この記事</a>を参考にしてください。試しに簡単なプロジェクトでやってみたらスルッとインポートできました。</p>
<p>しかし実際に本番のプロジェクトでやってみると、エラーが出まくって動きませんでした。ライブラリたくさん使った大きめのプロジェクトだとうまくいかないこともあるようです。しかもプロジェクト構成はそのままなので、gradleのプロジェクト構成になっていません。これだと結局プロダクトフレーバーといった<a href="http://blog.nkzn.info/entry/2014/03/21/015914">Android Studioの利点</a>が享受できません。</p>
<p>いっそのことgradleプロジェクトを新規作成してbuild.gradleを自分で頑張って書いてコードとリソースをコピってきた方が早そうだったので、新規作成することにしました。新規作成はAndroid Studioのダイアログにしたがっていけば迷わずできました。</p>
<p>なんかよくわからない変な感じになったらアンインストールしてやり直した方がいいかもしれません。アンインストールのやり方は<a href="http://konifar.com/1398">こちら</a>。</p>
<p> </p>
<h2>（４）build.gradleを記述</h2>
<p>ここが一番の鬼門でした。手順としてはこんな感じ。</p>
<ol>
<li>依存ライブラリをGoogleで調べてgradleの記述方法を見つけて記述</li>
<li>gradle syncしてみる</li>
<li>エラーが出たらエラー解消、出なければインポートしたライブラリが正しいかを確かめる</li>
</ol>
<p>例えば、Aviaryというライブラリのgradleの記述を<strong>『aviary sdk gradle』</strong>でGoogleで調べてみると、<a href="https://developers.aviary.com/docs/android/setup-guide" class="broken_link" rel="nofollow">公式ページ</a>にgradleサポートの情報が載っています。サンプルを落としてreadmeを見ると、gradleの記述方法が書いてありました。Aviaryの場合はこんな感じです。</p>
<pre class="brush: plain; title: ; notranslate">
dependencies {
    compile ('com.aviary.android.feather.sdk:aviary-sdk:3.4.3.351')
}
</pre>
<p>syncする時は、AndroidStudio上部のバーのボタンをクリックします。</p>
<p><img class="colorbox-1471"  title="android_studio_migration3.png" src="http://konifar.com/wp-content/uploads/android_studio_migration3.png" alt="Android studio migration3" width="137" height="133" border="0" /> </p>
<p>エラーが出たら、メッセージにエラーが表示されます。</p>
<p><img class="colorbox-1471"  title="android_studio_migration4.png" src="http://konifar.com/wp-content/uploads/android_studio_migration4.png" alt="Android studio migration4" width="513" height="213" border="0" /></p>
<p> </p>
<p>この作業を繰り返していくだけ、というとそれまでなんですが、それはもう色々とエラーが出まくりました。以下、ハマったエラーの対処方法まとめです。</p>
<p><a href="http://konifar.com/1414">AndroidStudioでローカルの別プロジェクトをインポートする</a></p>
<p><a href="http://konifar.com/1420">GooglePlayServicesがgradleでsyncできない時の対処法</a></p>
<p><a href="http://konifar.com/1444">gradle sync時にError:No such property: GROUP for class…エラー</a></p>
<p> </p>
<p>結局出来たbuild.gradleはこんな感じです。</p>
<pre class="brush: plain; title: ; notranslate">
apply plugin: 'com.android.application'

// load release properties
Properties props = new Properties()
if (rootProject.file(&quot;release.properties&quot;).exists()) {
    props.load(new FileInputStream(rootProject.file(&quot;release.properties&quot;)))
} else {
    println &quot;Please create release.properties in project root.&quot;
}

android {
    compileSdkVersion 19
    buildToolsVersion '19.1.0'

    defaultConfig {
        applicationId 'com.konifar'
        minSdkVersion 10
        targetSdkVersion 19
        versionCode 1
        versionName '1.0.0'
    }
    productFlavors {
        development {
        }
        staging {
        }
        production {
        }
    }

    signingConfigs {
        release {
            storeFile rootProject.file(&quot;konifar.keystore&quot;)
            storePassword props.storePassword
            keyAlias props.keyAlias
            keyPassword props.keyPassword
        }
    }
    buildTypes {
        debug {
            runProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            runProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
    }
    lintOptions {
        checkReleaseBuilds false
        abortOnError false
    }
    packagingOptions {
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
    }
    dexOptions {
        jumboMode true
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile project(':libraries:pulltorefresh')
    compile project(':libraries:facebook')
    compile project(':libraries:pagerslidingtabstrip') // customized for taptrip
    compile ('com.aviary.android.feather.sdk:aviary-sdk:3.4.3.351') {
        exclude module: 'support-v4'
    }
    compile ('com.android.support:appcompat-v7:19.+') {
        exclude module: 'support-v4'
    }
    compile ('com.nostra13.universalimageloader:universal-image-loader:1.9.1') {
        exclude module: 'support-v4'
    }
    compile ('com.mobeta.android.dslv:drag-sort-listview:0.6.1') {
        exclude module: 'support-v4'
    }
    compile ('com.jakewharton:butterknife:4.0.1')
    compile ('net.danlew:android.joda:2.3')
    compile ('com.google.code.gson:gson:2.2.4')
    compile ('com.google.android.gms:play-services:4.2.42')
    compile ('commons-validator:commons-validator:1.4.0')
    compile 'com.bugsense.trace:bugsense:3.6'
    compile 'de.greenrobot:eventbus:2.2.1'
}
</pre>
<p> </p>
<h2>（５）コードとリソースをコピー</h2>
<p>gradle syncして依存ライブラリをダウンロードできたら、Eclipseのプロジェクトのコードとリソースを新しいgradle プロジェクトにコピーします。gradleプロジェクトだと app/src/main/java以下にコードを配置します。リソースはapp/src/main/res以下です。</p>
<p>これはただコピーするだけで大丈夫でした。lintの設定が違う場合は少しエラーが表示されるかもしれません。（４）でインポートしたライブラリが間違っていた場合はここでエラーが大量発生するので、頑張ってエラーを解消しましょう。</p>
<p>ちなみに<a href="http://jakewharton.github.io/butterknife/">butterknife</a>は、Android StudioだとEclipseと違って面倒なビルドオプションの設定なく使えるので超楽です。</p>
<p> </p>
<h2>（６）ビルドして実行</h2>
<p>いよいよビルドして実行です。ここでも色々ハマりました。以下、対処方法まとめです。</p>
<p><a href="http://konifar.com/1405">Android Studioビルド時に Duplicate files copied エラー</a></p>
<p><a href="http://konifar.com/1428">Android Studioでgradleビルドエラー</a></p>
<p><a href="http://konifar.com/1439">Android Studioでビルド時にCannot merge new index xxxx into a non-jumbo instruction!</a></p>
<p><a href="http://konifar.com/1455">build.gradleからsigningConfigsの情報を別ファイルを切り出す</a></p>
<p> </p>
<p>その中でも、一番の難関はこのエラー。</p>
<p><a href="http://konifar.com/1447">gradleでビルド時にjava.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536</a></p>
<p><a href="http://konifar.com/1464">Android2でインストール時にINSTALL_FAILED_DEXOPTエラー</a></p>
<p>ライブラリを含めたメソッド数が65536個以上だとビルドやインストール時にエラーになるというもの。これを解決するためにはProguardを使って不必要なメソッドを入れないようにしたりしないとダメみたいだったので、Proguardを記述することにしました。</p>
<p> </p>
<h2>（７）Proguardを記述</h2>
<p>ビルド時にProguardを使うには、build.gradleのbuildTypesにrunProguard trueを記述します。</p>
<pre class="brush: plain; title: ; notranslate">
buildTypes {
    debug {
        runProguard true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
</pre>
<p>app/proguard-rules.pro には、proguardの設定を記述します。</p>
<p>何も指定しないと難読化してはいけないコードまで難読化されてしまって、まったく動かなくなります。keepオプションなどを使っていい感じに除外していく必要があります。例えば、gsonを使う場合は実行時にこんなエラーが出てしまいます。⇒ <a href="http://konifar.com/1451">Proguardを使っている時のgsonのエラー</a></p>
<p>最終的にこんなproguard-rules.pro を書きました。keepオプションなんかはまだまだ超適当です。 本当はもっとちゃんと書かないとダメです。他のプロジェクトのproguardファイルとか見せてもらいたいです。</p>
<pre class="brush: plain; title: ; notranslate">
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/konifar/AndroidSDK/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

-dontwarn com.konifar.**
-dontwarn org.apache.**
-dontwarn javax.**
-dontwarn butterknife.**
-dontwarn com.androidquery.**
-dontwarn com.squareup.okhttp.**


-keep class com.konifar.** { *; }
-keep interface com.konifar.** { *; }
-keep class com.facebook.** { *; }
-keep interface com.facebook.** { *; }
-keep class org.apache.** { *; }
-keep interface com.androidquery.** { *; }
-keep class com.androidquery.** { *; }
-keep interface com.google.** { *; }
-keep class com.google.** { *; }
-keep interface java.** { *; }
-keep class java.** { *; }
-keep interface org.json.** { *; }
-keep class org.json.** { *; }
-keep interface android.** { *; }
-keep class android.** { *; }
-keep interface com.aviary.** { *; }
-keep class com.aviary.** { *; }


##---------------Begin: proguard configuration common for all Android apps ----------
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-dump class_files.txt
-printseeds seeds.txt
-printusage unused.txt
-printmapping mapping.txt
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-allowaccessmodification
-keepattributes *Annotation*
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-repackageclasses ''

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService

# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
    native &lt;methods&gt;;
}

-keepclasseswithmembernames class * {
    public &lt;init&gt;(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembernames class * {
    public &lt;init&gt;(android.content.Context, android.util.AttributeSet, int);
}

# Preserve static fields of inner classes of R classes that might be accessed
# through introspection.
-keepclassmembers class **.R$* {
  public static &lt;fields&gt;;
}

# Preserve the special static methods that are required in all enumeration classes.
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
##---------------End: proguard configuration common for all Android apps ----------


##---------------Begin: proguard configuration for Gson  ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
##---------------End: proguard configuration for Gson  ----------
</pre>
<p> </p>
<p>（８）変更をgit push</p>
<p>うまくいけばプロジェクトを実行できるはずですが、コードのディレクトリなどがガラッと変わってしまうことでgitの履歴が消えてしまうのは嫌ですよね。</p>
<p>なので、今まで作った構成を参考に元のgit プロジェクトを同じ構成に作り直すことにしました。具体的には、git mvコマンドを使って（５）の作業をやり直します。git mvを使うと、変更履歴を保持したままファイル位置を変更することができます。</p>
<p>gitプロジェクトを同じ構成に変更できたら、Android Studioにインポートして動くかどうか見てみましょう。</p>
<p> </p>
<p> </p>
<p>ざっくりですが、こんな流れでのせかえ完了しました。</p>
<p>やってみた後に振り返るとこれだけだっけ？という感じですが、実際に手探りでやってみると結構大変でした。これからのせかえを検討している方々の参考になれば幸いです。</p>
<p> </p>
<p><a href="http://konifar.com/1471">EclipseからAndroid Studioへののせかえ手順まとめ</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></content:encoded>
			<wfw:commentRss>http://konifar.com/1471/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://konifar.com/1471" />
	</item>
		<item>
		<title>Android2でインストール時にINSTALL_FAILED_DEXOPTエラー</title>
		<link>http://konifar.com/1464</link>
		<comments>http://konifar.com/1464#comments</comments>
		<pubDate>Wed, 03 Sep 2014 13:39:00 +0000</pubDate>
		<dc:creator><![CDATA[Konifar]]></dc:creator>
				<category><![CDATA[Develop]]></category>
		<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://konifar.com/?p=1464</guid>
		<description><![CDATA[ビルドしたアプリをAndroid2の端末にインストールしようとしたら、INSTA ... <p><a href="http://konifar.com/1464">Android2でインストール時にINSTALL_FAILED_DEXOPTエラー</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></description>
				<content:encoded><![CDATA[<p>ビルドしたアプリをAndroid2の端末にインストールしようとしたら、<strong>INSTALL_FAILED_DEXOPT</strong> というエラーでインストールできませんでした。ビルドはできますし、Android4は全く問題ありません。Android2の端末だけダメでした。</p>
<pre class="brush: plain; title: ; notranslate">
pkg: /data/local/tmp/com.konifar
Failure [INSTALL_FAILED_DEXOPT]
</pre>
<p> </p>
<h2>1. 原因</h2>
<p>調べてみたところ、<a href="https://www.facebook.com/notes/facebook-engineering/under-the-hood-dalvik-patch-for-facebook-for-android/10151345597798920">Facebookエンジニア</a>のノートに詳しい原因が書いてありました。</p>
<p> </p>
<p><em>During standard installation, a program called &#8220;dexopt&#8221; runs to prepare your app for the specific phone it&#8217;s being installed on. Dexopt uses a fixed-size buffer (called the &#8220;LinearAlloc&#8221; buffer) to store information about all of the methods in your app. Recent versions of Android use an 8 or 16 MB buffer, but Froyo and Gingerbread (versions 2.2 and 2.3) only have 5 MB. Because older versions of Android have a relatively small buffer, our large number of methods was exceeding the buffer size and causing dexopt to crash. </em></p>
<p> </p>
<p>どうやら通常のインストール時には『dexopt』というプログラムが実行されるらしく、その処理はすべてのメソッドの情報を一定サイズの領域に貯めこむらしいです。Android4以上の最近のバージョンだと8MB、16MBの領域が確保されているのですが、Android2.3以下のOSでは5MBしかなく、それに収まりきらないほどたくさんのメソッド数だとdexoptがクラッシュしてインストールエラーになるとのことです。</p>
<p>アプリ内のメソッドだけでなく、インポートしたライブラリも含めたメソッド数なので、ちょっとライブラリを追加していくとすぐに限界に来てしまいます。。</p>
<p> </p>
<h2>2. 対処</h2>
<p>じゃあどうするかという話ですが、先ほどのリンクを見てみるとFacebookもいくつかやり方を試してみたらしいです。詳しくは見ていただきたいのですが、カスタムクラスローダーを作ったりとちょっと面倒そうで、すぐ解決できるという感じじゃありませんでした。また、Proguardを使って必要なメソッドだけapkに入れるというのもすでにやっていましたので、他の方法を考えなければなりませんでした。</p>
<p> </p>
<p>どうしようかなと悩みながら色々見てみると、build.gradleの依存関係の無駄がありそうということに気づきました。余計なライブラリをインポートしていたというわけです。</p>
<p>具体的に言うと、<strong>support-v4-13.0.0</strong> と <strong>support-v4-13.1.0</strong> が両方インポートされていました。これは片方だけでいいはず・・・と思い、build.gradleのコンパイル部分にexcludeオプションをつけてsupportライブラリをダウンロードしないようにしてみました。</p>
<p> </p>
<pre class="brush: plain; title: ; notranslate">
compile ('com.aviary.android.feather.sdk:aviary-sdk:3.4.3.351') {
    exclude module: 'support-v4'
}
</pre>
<p> </p>
<p>こんな感じのオプションを依存するライブラリすべてに追加してみたところ、メソッド数が制限内に収まったようで、Android2でもインストールできました。</p>
<p>さらっと書きましたが、この単純な結果に行き着くまでに1日かかりました。。。これちゃんと対応するならどうすべきなんでしょうか。ライブラリを追加するたびにヒヤヒヤするのは嫌なので、早めに恒久対応をしておきたいです。対応できたらまたメモに残しておこうと思います。</p>
<p> </p>
<p><a href="http://konifar.com/1464">Android2でインストール時にINSTALL_FAILED_DEXOPTエラー</a> is a post from: <a href="http://konifar.com">KonifarPod</a></p>
]]></content:encoded>
			<wfw:commentRss>http://konifar.com/1464/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
	<xhtml:link rel="alternate" media="handheld" type="text/html" href="http://konifar.com/1464" />
	</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

 Served from: konifar.com @ 2020-01-27 00:05:21 by W3 Total Cache -->