GenymotionにGooglePlayを入れようとするとAn error occured while deploying the fileが発生する
Genymotionについては以前触れたのでこちらで。
An error occured while deploying the file.
GooglePlayを入れるための準備をしていると次のエラーが発生しました。
Genymotionのバージョンは2.6.0
でした。
エミュレータを作り直したりカスタムしてSDカードを生成したりしてもうまくいかなかったのですが、次のようにすることで解決しました。
ADB tool connection settings
おそらく、Genymotionの設定画面を開いて、User custom Android SDK tools
にチェックが入っているので、 default
の方へ変更します。
これで解決しました。以上。
参考
Genymotion Android 6.0 に Play Store をインストールして Google Map を利用する / Qiita
Androidエンジニアが企画展に作品を出した話
2016/4/30~2016/5/15、2週間と1日、「CreativeAdventure」という、企画展がARTnSHELTERで開催されました。 そこで「Indoor Street」という作品を展示しました。企画展に作品を出すという経験での学びや感想をつらつらと書きます。
きっかけ
大学時代にU-moaという集団で活動をしていました。そのメンバーが社会人となり、徐々に東京に人が集まってきたので、当時のつながりや社会人になってからの新しいつながりを含めて、何か面白いことができないかとU-moaの代表が発起したのがきっかけです。
テーマ
企画展を行うにあたり、今回のテーマが「冒険」ということでした。 その他の参加メンバーの顔ぶれから、インタラクティブなものが求められると感じたのではじめは尻込みしていたのですが、せっかくのきっかけだしやってみようと思い参加をすることにしました。
作品
作品テーマ
冒険 ≒ 旅
と捉え、昨今の旅では必需品となるスマホを関連させる意味付けを行いました。
スマホアプリエンジニアで何ができるだろうか?と考えたときに、やはりスマホやアプリの要素を切り離せないと思いました。それらを軸に、インタラクションを与えられないかと考えました。
インタラクションと言えばわかりやすいのがVRだったのですが、企画展内で被りそうだったので、スマホの何かしらの情報を何かしらで飛ばして何かしらに変化を与えるという風にすることにしました。
作品概要
アプリで場所を検索すると、目の前に投影されてるスクリーンにその場所が表示され、スマホを持って歩くとその場所の中を歩けるという作品です。
アーキテクチャ
リモコンとなるスマホアプリと、場所を表示するWebがあります。
スマホアプリ
- Geocoder
- 目的地の緯度経度の取得に用います。
- Step Detector Sensor
- 歩行検知に用います。
- Accelerometer sensor
- 端末の傾きを検知するのに用います。
- Magnetic field sensor
- 端末の傾きを検知するのに用います。
- Open Sound Control
- Webへ情報を送るのに用います。
- 目的地の緯度経度、検知した歩行と傾き情報を送信します。
Android 4.4から歩行センサーが付いたのを知ったので、そのAPIを使うことにしました。
Web
- Node.js
- サーバやモジュールのimportに用います。
- Express
- Webページの作成に用います。
- Socket.io
- NodeサーバでOSCを経由して受け取った情報をWebへ送ります。
- Google Maps JavaScript API
- Street Viewの表示・制御に用います。
以前OSCを用いてWebと連携を行ったことがあったので、その方法で行うことにしました。
展示準備
会場にプロジェクターとスクリーン(壁)はあったので、必要なものは常設に必要なPCでした。
常設できるPCを持っていなかったので、メンバーに借りることにしました。 設置する作業よりも、借りたPCに環境構築をする方が大変でした。
作品を出す機会があれば、環境構築の手順を明確にしておくことと、実際に展示に使うであろうものを自分で用意しておかないとダメだなと思いました。
アプリをユーザに入れてもらう想定だったので、Google Playにアプリを公開しました。QRを読み込んでストアへ遷移し、入れてもらう想定だったのですが、もちろんiPhoneに対応していません。
楽しめないユーザがいるのでアプリを入れた状態のAndroidスマホを展示会場に置いておくことにしました。こちらも、配慮が足りなかったのと、端末を自分で用意していない点が至らなかったと思います。
展示中
展示して翌日に問題がありました。作品が展示されていませんでした。
起動方法がterminalに入ってディレクトリ移動してnpm start
とか、明らかにエンジニア以外に優しくない形だったので、.command
ファイルを作成してファイルをダブルクリックで起動できるようにしました。
初めての展示で、この辺りも配慮が足りていなかったです。
また.command
ファイルにリポジトリの更新も含めておいたので、展示中に変更があっても翌日には反映されるようにしました。
完成された作品なら不要かもしれませんが、変更が想定される作品の場合、更新する手段を入れておくと良いと思います。
はじめの想定では来場者の端末にアプリを入れてもらう想定だったので、トップページを作成し、そこに説明文とQRコードを用意していたのですが、これはうまくいかなかったです。 前述の通りiPhoneユーザは体験できないことと、QRコードを読み取ってアプリをインストールし、会場のIPを取得するためにもう一度QRコードを読み取ってアプリを起動するというフローが必要だったので、誰もそこまでしてくれないし理解してくれませんでした。
そこで、展示会場に合わせて置いたスマホを、あえて接続状態にし、スクリーンにはトップページではなくどこかにつないだ状態の画面を表示するようにしました。 こうすることで、見た目的にもキャッチーで、展示会場のスマホをいじることですぐに体験できるようになりました。 如何に自分の意図通りに来場者に触ってもらうのか?というところの敷居を下げる必要があると強く感じました。
振り返って
作品が展示されていなかったり、来場者に触ってもらえないなどもありましたが、来て頂いた方々には思ったより楽しんでもらえていたよう良かったです。 自分の行ってみたいところや、家の近く、思い出の場所などに行く人が多かったです。
連携部分の詰めが甘くて操作には癖があったのですが、それ込みでワイワイ楽しんでもらえていたのは嬉しくもあり助かった部分でもありました。
しかし、やはり理解するまでの敷居が高かったです。
Androidユーザで4.4以上の端末で会場のwifiにつないでQRコードを読み取りアプリをインストールして再びQRコードを読み取ってアプリを起動しないと遊べないので、スカイツリーより高いと揶揄されました。
実際その通りで、企画展に作品を出す場合は、アプリを入れてもらうということより、如何にして体験してもらうかが重要です。
敷居が高い作品の場合は、どうやってその敷居を下げることができるか?を考える必要があります。
技術的な制約により変更できないものがある場合は、事前準備を省くなどが良いと思います。
今回に関して言えば、作品を楽しめるアプリがインストールされているスマホを用意しておくことと、スクリーンに画面を投影させておくことが策に当たると思います。
スマホアプリエンジニア脳で、入れてもらった後のことばかり考えていました。
来場者とつながったり、終わった後の達成感、また、普段使わない技術に挑戦(場合によってはまずいかも)できるので、機会があればまた何かしたいと思いました。
ひとまずはPCとKitkat以降のスマホを購入してからにしたいです。
参考
AndroidでKuromojiを使う
Kuromoji
Androidでオフラインでも即座に形態素解析ができるように組み込んでみました。
LuceneのJapaneseTokenizerではなく、AtilikaのKuromojiを組み込みました。
はじめに言っておくと、組み込めたものはAtilikaのKuromoji-1.0-SNAPSHOTで、ipadicの辞書を利用したものです。
開発環境はKotlinです。
Atilika
0.7.7
公式で紹介されてる 0.7.7
を試してみました。
MavenCentralに上がっていないので、リポジトリを追加します。
- build.gradle
allprojects { repositories { jcenter() maven { url "http://www.atilika.org/nexus/content/repositories/atilika" } } }
必要なライブラリをGradleのDependenciesに追加します。
- app/build.gradle
compile "org.atilika.kuromoji:kuromoji:0.7.7"
必要なコードを記述してビルドします。
val tokenizer = Tokenizer.builder().build() val tokens = tokenizer.tokenize("我輩は猫である。名前はまだない。"); tokens.forEach { Log.d("Kuromoji", "${it.allFeatures}") }
実行はできたのですが、空白文字以外形態素解析が機能していませんでいた。 特定したわけではないですが、おそらく辞書の読み込みに失敗しているようです。
0.9.0
調べたら、MavenCentral
に0.9.0
が公開されてたので、そちらを使ってみました。
必要なライブラリをGradleのDependenciesに追加します。パッケージ名が異なるので注意してください。
- app/build.gradle
compile "com.atilika.kuromoji:kuromoji-ipadic:0.9.0"
必要なコードを記述してビルドします。
先ほどとは異なり、Builder
が大文字になっています。Tokenizer
のimport文ももちろん異なります。
val tokenizer = Tokenizer.Builder().mode(TokenizerBase.Mode.NORMAL).build() val tokens = tokenizer.tokenize("我輩は猫である。名前はまだない。"); tokens.forEach { Log.d("Kuromoji", "${it.allFeatures}") }
次のエラーがでました。
Caused by: java.lang.RuntimeException: Could not load dictionaries. at com.atilika.kuromoji.ipadic.Tokenizer$Builder.loadDictionaries(Tokenizer.java:231) at com.atilika.kuromoji.TokenizerBase.configure(TokenizerBase.java:77) at com.atilika.kuromoji.ipadic.Tokenizer.<init>(Tokenizer.java:74) at com.atilika.kuromoji.ipadic.Tokenizer.<init>(Tokenizer.java:59) at com.atilika.kuromoji.ipadic.Tokenizer$Builder.build(Tokenizer.java:203) Caused by: java.lang.IllegalArgumentException: capacity < 0: -4 at java.nio.ByteBuffer.allocate(ByteBuffer.java:54) at com.atilika.kuromoji.io.IntegerArrayIO.readArray(IntegerArrayIO.java:38) at com.atilika.kuromoji.buffer.WordIdMap.<init>(WordIdMap.java:35) at com.atilika.kuromoji.dict.TokenInfoDictionary.setup(TokenInfoDictionary.java:168) at com.atilika.kuromoji.dict.TokenInfoDictionary.newInstance(TokenInfoDictionary.java:160) at com.atilika.kuromoji.ipadic.Tokenizer$Builder.loadDictionaries(Tokenizer.java:219) at com.atilika.kuromoji.TokenizerBase.configure(TokenizerBase.java:77) at com.atilika.kuromoji.ipadic.Tokenizer.<init>(Tokenizer.java:74) at com.atilika.kuromoji.ipadic.Tokenizer.<init>(Tokenizer.java:65)
辞書の読み込みに失敗しているようです。 実際に問題となっているのは次のメソッドのようです。
- IntegerArrayIO#readArray
public static int[] readArray(InputStream input) throws IOException { DataInputStream dataInput = new DataInputStream(input); int length = dataInput.readInt(); ByteBuffer tmpBuffer = ByteBuffer.allocate(length * INT_BYTES); ReadableByteChannel channel = Channels.newChannel(dataInput); channel.read(tmpBuffer); tmpBuffer.rewind(); IntBuffer intBuffer = tmpBuffer.asIntBuffer(); int[] array = new int[length]; intBuffer.get(array); return array; }
このIssueで、フォークして解決したとあります。
しかし、別のIssueによると解決してMasterにマージされているようなので、Masterからビルドして必要なjarを生成してみます。
1.0-SNAPSHOT
試した時点でのコミットは9ce40b605990f38854a4b08c38dc08a85cc3bb8bです。
ソースを取り込んでjarを生成します。
$git clone git@github.com:atilika/kuromoji.git $cd kuromoji $mvn clean package
私の環境だと次のエラーがでました。
1.7 は無効な VM バージョンです。
JAVA_HOME
の設定が正しくないようだったので、設定します。
時間がかかりますが、無事生成できました。
kuromoji/kuromoji-core/target/kuromoji-core-1.0-SNAPSHOT.jar
kuromoji/kuromoji-ipadic/target/kuromoji-ipadic-1.0-SNAPSHOT.jar
を自分の形態素解析を行いたいプロジェクトのlibs
に配置します。
必要なライブラリをGradleのDependenciesに追加します。
- app/build.gradle
compile fileTree(dir: 'libs', include: ['*.jar']) compile files("libs/kuromoji-core-1.0-SNAPSHOT.jar") compile files("libs/kuromoji-ipadic-1.0-SNAPSHOT.jar")
必要なコードを記述します
val tokenizer = Tokenizer.Builder().mode(TokenizerBase.Mode.NORMAL).build() val tokens = tokenizer.tokenize("我輩は猫である。名前はまだない。"); tokens.forEach { Log.d("Kuromoji", "${it.allFeatures}") }
無事形態素解析した結果が得られました!
D/Kuromoji: 名詞,一般,*,*,*,*,我輩,ワガハイ,ワガハイ D/Kuromoji: 助詞,係助詞,*,*,*,*,は,ハ,ワ D/Kuromoji: 名詞,一般,*,*,*,*,猫,ネコ,ネコ D/Kuromoji: 助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ D/Kuromoji: 助動詞,*,*,*,五段・ラ行アル,基本形,ある,アル,アル D/Kuromoji: 記号,句点,*,*,*,*,。,。,。 D/Kuromoji: 名詞,一般,*,*,*,*,名前,ナマエ,ナマエ D/Kuromoji: 助詞,係助詞,*,*,*,*,は,ハ,ワ D/Kuromoji: 副詞,助詞類接続,*,*,*,*,まだ,マダ,マダ D/Kuromoji: 形容詞,自立,*,*,形容詞・アウオ段,基本形,ない,ナイ,ナイ D/Kuromoji: 記号,句点,*,*,*,*,。,。,。
まとめ
Android特有の問題もあってか、少し手間取りましたが、辞書が内包されているものは少し試すには便利です。
しかし、生成したjarが11MBもあったり、辞書展開時にOOBを引き起こしたりするので、特定の環境で専用に使う場合は良いと思いました。
それ以外の環境では、辞書のアップデートもされないし迅速なレスポンスを求めないのであればWEB APIで形態素解析を行うのがAndroidだと現実的だと思いました。
検証したサンプルです。
参考
LuceneのAnalyzer、KuromojiのModeごとの挙動を確認する / CLOVER
Kuromoji IPADIC / MVN REPOSITORY
Android runtime exception when creating new Tokenizer using kuromoji-ipadic / GitHub