最速でandroid-sdk-pluginをAndroidStudioで使う
android-sdk-pluginプロジェクトを作る
1.コマンドからプロジェクトを作ります。
2.project/plugins.sbtとproject/build.propertiesとbuild.sbtにおまじないを書きます
android create project --target android-19 --path ./android-sdk-plugin-project --package com.example.project --activity MainActivity cd ./android-sdk-plugin-project mkdir ./project cat <<END > project/plugins.sbt addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.2.10") END cat << END > project/build.properties sbt.version=0.13.2-M2 END cat << END > build.sbt import android.Keys._ android.Plugin.androidBuild END
これで起動する準備が出来ました。
起動します(Java編)
APILevel19のエミュレーターを起動します
コマンド作れてません、スミマセン
sbtからrunします
sbt android:run
この時実行先端末をみつけられないと、android-sdk-pluginは以下のエラーを吐きます
[trace] Stack trace suppressed: run last android:install for the full output. [error] (android:install) no devices connected [error] Total time: 1 s, completed Mar 1, 2014 5:39:30 AM
起動します(Scala編)
rm src/com/example/project/MainActivity.java cat << END > src/com/example/project/MainActivity.scala package com.example.project import android.app.Activity import android.os.Bundle class MainActivity extends Activity { override def onCreate(bundle: Bundle) { super.onCreate(bundle) setContentView(R.layout.main) } } END sbt android:run
この時も起動先端末がないとエラーが出ます
IntellijIDEA(Android Studio)化します
project/plugin.sbtにsbt-ideaを追加します(IntellijIDEA Ultimate 13の人は不要)
cat <<END >> project/plugins.sbt resolvers += "Sonatype snapshots" at "http://oss.sonatype.org/content/repositories/snapshots/" addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.7.0-SNAPSHOT") END sbt gen-idea
IDEAで開きます
「File」>「Open」>「android-sdk-plugin-project」
IntellijIDEA(Android Studio)の赤線を消す
こんな赤線は2点を確認して修正します。
ProjectSDKを適切に設定する
Moduleのandroid-sdk-plugin-projectのDependenciesのModuleSDKをAndroid API 19に設定する
最後にOKを押す
android-sdk-plugin最高!!
Scala on Android で play-json を使う方法
AndroidでJSONを扱う場合、デフォルトのorg.jsonがありますがnullを直接扱ったりして微妙なライブラリです。
アプリ開発時のサーバーサイドとしてPlayFrameworkを使ってることもあり、使い慣れたplay-jsonを使いたいので使ってみました。
ちなみにObj->JSONはこんな感じにかけます
しかし普通に
resolvers += "Typesafe Repo" at "http://repo.typesafe.com/typesafe/releases/" libraryDependencies += "com.typesafe.play" %% "play-json" % "2.2.2-RC1"
こう書いて実行すると、Proguardが頑張り過ぎた場合に以下の例外が発生します
I/dalvikvm( 1681): Could not find method scala.collection.Set.hashCode, referenced from method play.api.libs.json.JsObject.hashCode W/dalvikvm( 1681): VFY: unable to resolve interface method 10596: Lscala/collection/Set;.hashCode ()I D/dalvikvm( 1681): VFY: replacing opcode 0x72 at 0x0004 W/dalvikvm( 1681): Exception Ljava/lang/NullPointerException; thrown while initializing Lcom/fasterxml/jackson/databind/cfg/MapperConfigBase; W/dalvikvm( 1681): Exception Ljava/lang/ExceptionInInitializerError; thrown while initializing Lplay/api/libs/json/JacksonJson$; W/System.err( 1681): java.lang.ExceptionInInitializerError W/System.err( 1681): at com.fasterxml.jackson.databind.ObjectMapper.<init>(ObjectMapper.java:433) W/System.err( 1681): at com.fasterxml.jackson.databind.ObjectMapper.<init>(ObjectMapper.java:364) W/System.err( 1681): at play.api.libs.json.JacksonJson$.<init>(JsValue.scala:462) W/System.err( 1681): at play.api.libs.json.JacksonJson$.<clinit>(JsValue.scala) W/System.err( 1681): at play.api.libs.json.Json$.stringify(Json.scala:48) W/System.err( 1681): at play.api.libs.json.JsValue$class.toString(JsValue.scala:77) W/System.err( 1681): at play.api.libs.json.JsObject.toString(JsValue.scala:164) W/System.err( 1681): at com.kohachori.example.MessageReceivingService.com$kohachori$example$MessageReceivingService$$update$1(MessageReceivingService.scala:80) W/System.err( 1681): at com.kohachori.example.MessageReceivingService$$anonfun$onCreate$1$$anonfun$apply$mcV$sp$2.apply(MessageReceivingService.scala:67) W/System.err( 1681): at com.kohachori.example.MessageReceivingService$$anonfun$onCreate$1$$anonfun$apply$mcV$sp$2.apply(MessageReceivingService.scala:63) W/System.err( 1681): at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32) W/System.err( 1681): at scala.concurrent.impl.ExecutionContextImpl$$anon$3.exec(ExecutionContextImpl.scala:107) W/System.err( 1681): at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) W/System.err( 1681): at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.pollAndExecAll(ForkJoinPool.java:1253) W/System.err( 1681): at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1346) W/System.err( 1681): at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) W/System.err( 1681): at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) W/System.err( 1681): Caused by: java.lang.NullPointerException W/System.err( 1681): at java.lang.Enum$1.create(Enum.java:43) W/System.err( 1681): at java.lang.Enum$1.create(Enum.java:35) W/System.err( 1681): at libcore.util.BasicLruCache.get(BasicLruCache.java:54) W/System.err( 1681): at java.lang.Enum.getSharedConstants(Enum.java:209) W/System.err( 1681): at java.lang.Class.getEnumConstants(Class.java:705) W/System.err( 1681): at com.fasterxml.jackson.databind.cfg.MapperConfig.collectFeatureDefaults(MapperConfig.java:73) W/System.err( 1681): at com.fasterxml.jackson.databind.cfg.MapperConfigBase.<clinit>(MapperConfigBase.java:28) W/System.err( 1681): ... 17 more
この場合はProguardが頑張りすぎないように以下の2行を追加すればplay-jsonが動くようになります
"-keep class com.fasterxml.jackson.databind.** { *; }", "-keep interface com.fasterxml.jackson.databind.** { *; }"
Scala on Android with Dipatch
Scala on AndroidでDipatchを使う方法
Androidで普通にDipatch使おうとすると、下記の例外を投げて通信してくれません。
W/dalvikvm(18092): VFY: unable to resolve exception class 431 (Ljavax/naming/AuthenticationException;) W/dalvikvm(18092): VFY: unable to find exception handler at addr 0x5f W/dalvikvm(18092): VFY: rejected Lcom/ning/http/client/providers/jdk/JDKAsyncHttpProvider;.createUrlConnection (Lcom/ning/http/client/Request;)Ljava/net/HttpURLConnection; W/dalvikvm(18092): VFY: rejecting opcode 0x0d at 0x005f W/dalvikvm(18092): VFY: rejected Lcom/ning/http/client/providers/jdk/JDKAsyncHttpProvider;.createUrlConnection (Lcom/ning/http/client/Request;)Ljava/net/HttpURLConnection; W/dalvikvm(18092): Verifier rejected class Lcom/ning/http/client/providers/jdk/JDKAsyncHttpProvider; W/dalvikvm(18092): Exception Ljava/lang/VerifyError; thrown while initializing Ldispatch/Http$; W/System.err(18092): java.lang.VerifyError: com/ning/http/client/providers/jdk/JDKAsyncHttpProvider W/System.err(18092): at com.ning.http.client.AsyncHttpClient.loadDefaultProvider(AsyncHttpClient.java:592) W/System.err(18092): at com.ning.http.client.AsyncHttpClient.<init>(AsyncHttpClient.java:184) W/System.err(18092): at dispatch.InternalDefaults$.client(defaults.scala:29) W/System.err(18092): at dispatch.Http$.<init>(execution.scala:30) W/System.err(18092): at dispatch.Http$.<clinit>(execution.scala) W/System.err(18092): at your.application.package.ClassName$$anonfun$onCreate$2$$anonfun$apply$2.apply(MessageReceivingService.scala:61) W/System.err(18092): at your.application.package.ClassName$$anonfun$onCreate$2$$anonfun$apply$2.apply(MessageReceivingService.scala:53) W/System.err(18092): at scala.util.Success$$anonfun$map$1.apply(Try.scala:206) W/System.err(18092): at scala.util.Try$.apply(Try.scala:161) W/System.err(18092): at scala.util.Success.map(Try.scala:206) W/System.err(18092): at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235) W/System.err(18092): at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235) W/System.err(18092): at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32) W/System.err(18092): at scala.concurrent.impl.ExecutionContextImpl$$anon$3.exec(ExecutionContextImpl.scala:107) W/System.err(18092): at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) W/System.err(18092): at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.pollAndExecAll(ForkJoinPool.java:1253) W/System.err(18092): at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1346) W/System.err(18092): at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) W/System.err(18092): at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
対処法は、下記の処理を通信前に実行することです。なぜ動くようになるのか謎ですが、AndroidでDispatchが使えるようになるのは幸せなことなのでこれで良いんです。理由がわかる方は教えて下さい。
import com.ning.http.client.AsyncHttpClientConfig import com.ning.http.client.providers.netty.NettyAsyncHttpProvider new NettyAsyncHttpProvider(new AsyncHttpClientConfig.Builder().build)