我正在尝试使用sbt和jberkel/android-plugin在Scala和Akka中设置简单的Android项目。我成功地设法创建了基于getting started tutorial of android-plugin的简单应用程序。我还设法组装ProGuard配置,这使我能够将Akka混合到项目中。
现在我想添加Akka配置文件,我无法做到。我在src/main/resources
文件夹中创建了它并期望它能正常工作。不幸的是,在APK程序集中,sbt失败并出现以下错误:
[trace] Stack trace suppressed: run last Akkdroid/android:package-debug for the full output.
[error] (Akkdroid/android:package-debug)
[error] Using keystore: /home/ghik/.android/debug.keystore
[error] Packaging akkdroid-0.1.apk
[error] /data/Studia/S10/Mobilne/akkdroid/target/resources.apk:
[error] => res/layout/main.xml
[error] => AndroidManifest.xml
[error] => resources.arsc
[error] /data/Studia/S10/Mobilne/akkdroid/target/classes.dex => classes.dex
[error] /data/Studia/S10/Mobilne/akkdroid/target/classes.min.jar:
[error] => akkdroid.conf
[error] => library.properties
[error] => reference.conf
[error] => org/jboss/netty/container/spring/beans.xml
[error] /data/Studia/S10/Mobilne/akkdroid/src/main/resources/akkdroid.conf => akkdroid.conf
[error]
[error] Error packaging /data/Studia/S10/Mobilne/akkdroid/target/akkdroid-0.1.apk: Duplicate files at the same path inside the APK
[error] Total time: 20 s, completed 2013-04-24 20:32:47
从这些消息中,我推断我的akkdroid.conf
文件最初被(通过ProGuard?)复制到classes.min.jar
,之后sbt
尝试构建包含来自两者的资源的包classes.min.jar
和src/main/resources
,最终会看到我的文件两次。
不幸的是,我不知道为什么会发生这种情况以及如何解决它。
如果有帮助,这是我的sbt
构建文件(主要来自jberkel's template):
import sbt._
import Keys._
import AndroidKeys._
object General {
val settings = Defaults.defaultSettings ++ Seq(
name := "Akkdroid",
version := "0.1",
versionCode := 0,
scalaVersion := "2.10.1",
platformName in Android := "android-10",
javacOptions ++= Seq("-source", "1.6", "-target", "1.6")
)
val proguardSettings = Seq(
useProguard in Android := true,
proguardOption in Android :=
"""-keepclassmembers class * {
| ** MODULE$;
| }
|-keep public class akka.actor.LocalActorRefProvider {
|public <init>(...);
|}
|-keep public class akka.remote.RemoteActorRefProvider {
|public <init>(...);
|}
|-keep class akka.actor.SerializedActorRef {
|*;
|}
|-keep class akka.remote.netty.NettyRemoteTransport {
|*;
|}
|-keep class akka.serialization.JavaSerializer {
|*;
|}
|-keep class akka.serialization.ProtobufSerializer {
|*;
|}
|-keep class com.google.protobuf.GeneratedMessage {
|*;
|}
|-keep class akka.event.Logging*
|-keep class akka.event.Logging$LogExt{
|*;
|}
|-keep class scala.Option
|-keep class scala.Function1
|-keep class scala.PartialFunction
|-keep class scala.collection.SeqLike {
|public protected *;
|}
|-keep class akka.**
|-keepclassmembers class akka.**
|-keep class org.omg.**
|-keep class scala.Tuple2
|-dontskipnonpubliclibraryclassmembers
|-dontskipnonpubliclibraryclasses
""".stripMargin
)
lazy val fullAndroidSettings =
General.settings ++
AndroidProject.androidSettings ++
TypedResources.settings ++
proguardSettings ++
AndroidManifestGenerator.settings ++
AndroidMarketPublish.settings ++ Seq(
keyalias in Android := "change-me",
libraryDependencies += "org.scalatest" %% "scalatest" % "1.9.1" % "test"
)
}
object AndroidBuild extends Build {
javacOptions ++= Seq("-target", "1.6")
lazy val main = Project(
"Akkdroid",
file("."),
settings = General.fullAndroidSettings ++ Seq(
libraryDependencies += "com.typesafe.akka" % "akka-actor_2.10" % "2.1.2",
libraryDependencies += "com.typesafe.akka" % "akka-remote_2.10" % "2.1.2"
)
)
lazy val tests = Project(
"tests",
file("tests"),
settings = General.settings ++
AndroidTest.androidSettings ++
General.proguardSettings ++ Seq(
name := "AkkdroidTests"
)
) dependsOn main
}
我会非常感谢你的帮助。我几乎没有Android或SBT的经验。
答案 0 :(得分:1)
我遇到了同样的问题。我不知道这是否是处理它的最佳方法,但我将配置文件放在android项目的raw
目录中。然后我将其解析为Config
对象并将其传递给ActorSystem
构造函数。
object AkkaSystem {
private var systemOption: Option[ActorSystem] = None
def system(implicit context: Context): ActorSystem = synchronized {
systemOption match {
case None =>
val reader = new InputStreamReader(
context.getResources.openRawResource(R.raw.configuration)
)
systemOption = Option (
ActorSystem("MySystem", ConfigFactory.parseReader(reader))
)
reader.close()
systemOption.get
case Some(existingSystem) => existingSystem
}
}
}
然后在我的Activity
课程中,我可以使用AkkaSystem
个对象来获取已配置的ActorSystem
:
class MainActivity extends Activity {
implicit val context = this
private def mainActor = AkkaSystem.system.actorOf(Props[MainActor], "main")
}
我同意,如果我可以避免所有代码并且需要传递Context
以获取Android资源,那会更好。
答案 1 :(得分:1)
这是另一种似乎有用的方法,并且避免使用Android Context
将Akka配置加载为原始Android资源。我不确定它比将配置文件视为原始Android资源更“正确”。
我在config
项目的顶层创建了一个名为sbt
的目录,并将名为application.conf
的Akka配置文件放入该目录。
myapp/
config/
application.conf
project/
Build.scala
plugins.sbt
src/
main/
scala/
然后我将以下设置添加到Build.scala:
unmanagedClasspath in Runtime <+= (baseDirectory) map { bd => Attributed.blank(bd / "config") }
我正在使用Jan Berkel's Android application template,从而发起我的Build.scala
。上下文中的相关设置类似于
object General {
val settings = Defaults.defaultSettings ++ Seq (
name := "AkkaWeb",
version := "0.1",
<other settings elided>...
unmanagedClasspath in Runtime <+= (baseDirectory) map { bd => Attributed.blank(bd / "config") }
)
我必须做clean
以及reload
,但之后application.conf
文件会显示在.apk
文件中,同时显示Akka的默认{{1}当我构造reference.conf
时,Akka会读取它。
值得注意的一点是:如果我在主线程中构造ActorSystem
,那么在strict mode中运行时,读取配置文件会导致磁盘访问冲突。这是一个单独的问题,对于这个问题是偏离主题的,但需要注意的事项,特别是在构建ActorSystem
时我可以看到明显的延迟。
此解决方案直接从Akka文档here复制,您可以在其中阅读更多详细信息,以了解其正在做什么。
我刚注意到别的东西。我的ActorSystem
中的maven工件的顺序会影响Build.scala
文件中显示的reference.conf
。如果我希望.apk
jar中的akka-actor
成为那个reference.conf
,那么我必须将reference.conf
放在其他具有akka-actor
文件的工件之前与Typesafe配置库一起使用在我的reference.conf
文件中显示为.apk
。例如:
libraryDependencies ++= Seq(
"com.typesafe.akka" % "akka-actor_2.10" % "2.1.4",
"io.spray" % "spray-util" % "1.1-M7.1-openssl-M6"
)
如果这两个工件的顺序相反,那么生成的reference.conf
文件中的.apk
文件将是Spray工件中的文件,而不是Akka工件。