I'm trying to connect to my local App Engine project using the remote API.
Here is my source:
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RemoteApiOptions options = new RemoteApiOptions()
.server("192.168.1.5", 8888)
.credentials("username", "password");
RemoteApiInstaller installer = new RemoteApiInstaller();
try {
installer.install(options);
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
} catch(Exception e){
System.err.println(e.toString());
}finally {
installer.uninstall();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
I'm importing appengine-api.jar, appengine-remote-api.jar, and appengine-tools-api.jar from the App Engine Java SDK.
I get the following compilation error in both Eclipse and IntelliJ:
[2012-08-23 15:16:16 - Accident Map] Dx
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: already added: Lcom/google/appengine/repackaged/com/google/common/base/Absent;
at com.android.dx.dex.file.ClassDefsSection.add(ClassDefsSection.java:123)
at com.android.dx.dex.file.DexFile.add(DexFile.java:163)
at com.android.dx.command.dexer.Main.processClass(Main.java:486)
at com.android.dx.command.dexer.Main.processFileBytes(Main.java:455)
at com.android.dx.command.dexer.Main.access$400(Main.java:67)
at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:394)
at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:245)
at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:131)
at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:109)
at com.android.dx.command.dexer.Main.processOne(Main.java:418)
at com.android.dx.command.dexer.Main.processAllFiles(Main.java:329)
at com.android.dx.command.dexer.Main.run(Main.java:206)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.android.ide.eclipse.adt.internal.build.DexWrapper.run(DexWrapper.java:180)
at com.android.ide.eclipse.adt.internal.build.BuildHelper.executeDx(BuildHelper.java:703)
at com.android.ide.eclipse.adt.internal.build.builders.PostCompilerBuilder.build(PostCompilerBuilder.java:577)
at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:728)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:199)
at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:321)
at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:396)
at org.eclipse.core.internal.resources.Project$1.run(Project.java:618)
at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2344)
at org.eclipse.core.internal.resources.Project.internalBuild(Project.java:597)
at org.eclipse.core.internal.resources.Project.build(Project.java:124)
at com.android.ide.eclipse.adt.internal.project.ProjectHelper.doFullIncrementalDebugBuild(ProjectHelper.java:1000)
at com.android.ide.eclipse.adt.internal.launch.LaunchConfigDelegate.launch(LaunchConfigDelegate.java:147)
at org.eclipse.debug.internal.core.LaunchConfiguration.launch(LaunchConfiguration.java:855)
at org.eclipse.debug.internal.core.LaunchConfiguration.launch(LaunchConfiguration.java:704)
at org.eclipse.debug.internal.ui.DebugUIPlugin.buildAndLaunch(DebugUIPlugin.java:1047)
at org.eclipse.debug.internal.ui.DebugUIPlugin$8.run(DebugUIPlugin.java:1251)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
The same code works as a non-Android Java project with minimal changes.
It lookes like your AE setup is spot on. What I wouldn't expect is for the Remote Api to run on an Android handset. To connect via the Remote API, run it as a stand alone java process.
Android java is just a subset of Java and so the remote API may use things not available on Android (though that doesn't seem the case here) So really aren't you better of setting up your Android project to connect to AE in the way it was intended. I mean what are you going to do, ship your password to connect to your AE instance in your apk? There won't be any access control doing it that way and surely that isn't what you want, or do I misunderstand your purpose.
EDIT:
Why can't it run on Android? Maybe it can. The problems I see are:
1) the Android Whitelist may not contain all of the classes needed by the Remote API and even if it does now, there is no guarantee that future versions will work.
2) you are hardcoding your password into your android application. this gives every user the credentials to do everything ... insert junk that you will have to pay for if billing is enabled, delete all your cherished data, etc. etc. OK so your users would have to be malicious and figure it out, but unless you can really trust your users and don't distribute your apk via the play store, I think it is a fact of life that apks get pirated and really question why you would give a pirate access to your datastore credentials. I am not saying you can't do it that way, but just pointing out hey in fact maybe you don't.
If you use rpc calls (as linked above), you can limit what the client is able to do with the datastore.
Hum, I don't think you should add appengine-tools-api.jar into your project, as the documentation does not mention it. Did you try removing it ?