Reputation: 191
I'm trying to add functionality to an existing iOS libGDX app (using RoboVM) so that when a scene2d.ui button is pressed, an MFMailComposeViewController popup is displayed with a predefined set of CSV files attached that are stored in the app's Library > local folder. Here's the code I have so far:
Imports & members:
import org.robovm.apple.foundation.*;
import org.robovm.apple.messageui.MFMailComposeResult;
import org.robovm.apple.messageui.MFMailComposeViewController;
import org.robovm.apple.messageui.MFMailComposeViewControllerDelegate;
import org.robovm.apple.uikit.*;
import org.robovm.objc.ObjCObject;
private UIWindow mailWindow;
private UIViewController mailViewController;
private MFMailComposeViewController mailPicker;
Methods:
private void createMailWindow()
{
mailWindow = new UIWindow(UIScreen.getMainScreen().getBounds());
mailViewController = new UIViewController();
mailWindow.setRootViewController(mailViewController);
}
private void sendEmail(String fileName, String subject, String body)
{
mailPicker = new MFMailComposeViewController();
mailPicker.addStrongRef(mailWindow);
String path = NSBundle.getMainBundle().getResourcePath();
if (fileName != null)
{
path = path.substring(0, path.lastIndexOf('/')) + "/Library/local/" + fileName;
}
MFMailComposeViewControllerDelegate delegate = new MFMailComposeViewControllerDelegate()
{
public void mailComposeControllerDidFinish(MFMailComposeViewController controller, MFMailComposeResult result, NSError error)
{
controller.dismissViewController(true, null);
mailPicker.removeFromParentViewController();
mailPicker.removeStrongRef(mailWindow);
mailWindow.setHidden(true);
mailPicker = null;
}
@Override
public void didFinish(MFMailComposeViewController controller, MFMailComposeResult result, NSError error)
{
}
};
mailPicker.setMailComposeDelegate(delegate);
mailPicker.addStrongRef((ObjCObject) delegate);
if (fileName != null)
{
// attach CSVs here...
}
mailPicker.setSubject((subject != null ? subject : "Test Results"));
mailPicker.setMessageBody((body != null ? body : "Please find attached the latest results data."), false);
if (MFMailComposeViewController.canSendMail())
{
mailWindow.getRootViewController().presentViewController(mailPicker, true, null);
mailWindow.makeKeyAndVisible();
}
}
}
I have this code in place and Eclipse doesn't flag any problems until I attempt a build, whereby I get the following error:
Exception in thread "main" java.lang.NoClassDefFoundError: org/robovm/rt/bro/NativeObject
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at com.mmu.cfa.DesktopMain.main(DesktopMain.java:26)
Caused by: java.lang.ClassNotFoundException: org.robovm.rt.bro.NativeObject
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
... 49 more
I've added the RoboVM Cocoa Touch Library and the RoboVM Runtime Library to my main project's build path. If I remove these two methods, my project builds without error. Is there something else I need to setup to get this running?
Upvotes: 1
Views: 267
Reputation: 7057
In a Libgdx application, the main project is shared by the projects of all supported platforms.
So main project must contain platform independent code.
RoboVM Cocoa Touch Library and RoboVM Runtime Library are platform dependent and would work only on iOS and not on desktop, android, html etc.
Create an interface representing the functionality that you require in the main project.
public interface EmailHandler {
public void createMailWindow();
public void sendEmail(String fileName, String subject, String body);
}
Create an implementation class in the robovm project with the code you have already written.
public class RobovmEmailHandler implements EmailHandler {
@Override
public void createMailWindow() {
// Your code goes here.
}
@Override
public void sendEmail(String fileName, String subject, String body) {
// Your code goes here.
}
}
Add the EmailHandler
parameter to the constructor of ApplicationListener
(your main game class in main project).
public class MyAwesomeGame extends Game {
private EmailHandler emailHandler; // Use it wherever you like.
public MyAwesomeGame(EmailHandler emailHandler) {
this.emailHandler = emailHandler;
// Rest of constructor.
}
}
Supply the implementation argument in RobovmLauncher
(main class of robovm project).
public class RobovmLauncher extends IOSApplication.Delegate {
@Override
protected IOSApplication createApplication() {
EmailHandler emailHandler = new RobovmEmailHandler();
IOSApplicationConfiguration config = new IOSApplicationConfiguration();
return new IOSApplication(new MyAwesomeGame(emailHandler), config);
}
}
Note:
Projects of other platforms would start shouting at you to provide an EmailHandler
to them. This is natural and expected. You should provide platform specific implementation of the interface for each platform you want to target.
Hope this helps.
Good luck.
Upvotes: 1